You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libtdevnc/x11vnc/linuxfb.c

362 lines
8.1 KiB

/* -- linuxfb.c -- */
#include "x11vnc.h"
#include "cleanup.h"
#include "scan.h"
#include "xinerama.h"
#include "screen.h"
#include "pointer.h"
#include "allowed_input_t.h"
#include "uinput.h"
#include "keyboard.h"
#include "macosx.h"
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#if LIBVNCSERVER_HAVE_LINUX_FB_H
#include <linux/fb.h>
#endif
char *console_guess(char *str, int *fd);
void console_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
void console_pointer_command(int mask, int x, int y, rfbClientPtr client);
void linux_dev_fb_msg(char *);
char *console_guess(char *str, int *fd) {
char *q, *in = strdup(str);
char *atparms = NULL, *file = NULL;
int do_input, have_uinput, tty = -1;
#ifdef MACOSX
return macosx_console_guess(str, fd);
#endif
if (strstr(in, "/dev/fb") == in) {
free(in);
in = (char *) malloc(strlen("console:") + strlen(str) + 1);
sprintf(in, "console:%s", str);
} else if (strstr(in, "fb") == in) {
free(in);
in = (char *) malloc(strlen("console:/dev/") + strlen(str) + 1);
sprintf(in, "console:/dev/%s", str);
} else if (strstr(in, "vt") == in) {
free(in);
in = (char *) malloc(strlen("console_") + strlen(str) + 1);
sprintf(in, "console_%s", str);
}
if (strstr(in, "console") != in) {
rfbLog("console_guess: unrecognized console/fb format: %s\n", str);
free(in);
return NULL;
}
q = strrchr(in, '@');
if (q) {
atparms = strdup(q+1);
*q = '\0';
}
q = strrchr(in, ':');
if (q) {
file = strdup(q+1);
*q = '\0';
}
if (! file || file[0] == '\0') {
file = strdup("/dev/fb");
}
if (strstr(file, "fb") == file) {
q = (char *) malloc(strlen("/dev/") + strlen(file) + 1);
sprintf(q, "/dev/%s", file);
free(file);
file = q;
}
if (!strcmp(file, "/dev/fb")) {
/* sometimes no sylink fb -> fb0 */
struct stat sbuf;
if (stat(file, &sbuf) != 0) {
free(file);
file = strdup("/dev/fb0");
}
}
do_input = 1;
if (pipeinput_str) {
have_uinput = 0;
do_input = 0;
} else {
have_uinput = check_uinput();
}
if (strstr(in, "console_vt")) {
have_uinput = 0;
}
if (!strcmp(in, "consolex")) {
do_input = 0;
} else if (strstr(in, "console_vtx")) {
have_uinput = 0;
do_input = 0;
} else if (!strcmp(in, "console")) {
/* current active VT: */
if (! have_uinput) {
tty = 0;
}
} else {
int n;
if (sscanf(in, "console%d", &n) == 1) {
tty = n;
have_uinput = 0;
} else if (sscanf(in, "console_vt%d", &n) == 1) {
tty = n;
have_uinput = 0;
}
}
if (strstr(in, "console_vt") == in) {
char tmp[100];
int fd, rows = 30, cols = 80, w, h;
sprintf(tmp, "/dev/vcsa%d", tty);
file = strdup(tmp);
fd = open(file, O_RDWR);
if (fd >= 0) {
read(fd, tmp, 4);
rows = (unsigned char) tmp[0];
cols = (unsigned char) tmp[1];
close(fd);
}
w = cols * 8;
h = rows * 16;
rfbLog("%s %dx%d\n", file, cols, rows);
if (getenv("RAWFB_VCSA_BPP")) {
/* 8bpp, etc */
int bt = atoi(getenv("RAWFB_VCSA_BPP"));
if (bt > 0 && bt <=32) {
sprintf(tmp, "%dx%dx%d", w, h, bt);
} else {
sprintf(tmp, "%dx%dx16", w, h);
}
} else {
/* default 16bpp */
sprintf(tmp, "%dx%dx16", w, h);
}
atparms = strdup(tmp);
}
rfbLog("console_guess: file is %s\n", file);
if (! atparms) {
#if LIBVNCSERVER_HAVE_LINUX_FB_H
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H
struct fb_var_screeninfo var_info;
int d = open(file, O_RDWR);
if (d >= 0) {
int w, h, b;
unsigned long rm = 0, gm = 0, bm = 0;
if (ioctl(d, FBIOGET_VSCREENINFO, &var_info) != -1) {
w = (int) var_info.xres;
h = (int) var_info.yres;
b = (int) var_info.bits_per_pixel;
rm = (1 << var_info.red.length) - 1;
gm = (1 << var_info.green.length) - 1;
bm = (1 << var_info.blue.length) - 1;
rm = rm << var_info.red.offset;
gm = gm << var_info.green.offset;
bm = bm << var_info.blue.offset;
if (b == 8 && rm == 0xff && gm == 0xff && bm == 0xff) {
/* I don't believe it... */
rm = 0x07;
gm = 0x38;
bm = 0xc0;
}
if (b <= 8 && (rm == gm && gm == bm)) {
if (b == 4) {
rm = 0x07;
gm = 0x38;
bm = 0xc0;
}
}
/* @66666x66666x32:0xffffffff:... */
atparms = (char *) malloc(200);
sprintf(atparms, "%dx%dx%d:%lx/%lx/%lx",
w, h, b, rm, gm, bm);
*fd = d;
} else {
perror("ioctl");
close(d);
}
} else {
rfbLog("could not open: %s\n", file);
rfbLogPerror("open");
linux_dev_fb_msg(file);
close(d);
}
#endif
#endif
}
if (atparms) {
int gw, gh, gb;
if (sscanf(atparms, "%dx%dx%d", &gw, &gh, &gb) == 3) {
fb_x = gw;
fb_y = gh;
fb_b = gb;
}
}
if (do_input) {
if (tty >=0 && tty < 64) {
pipeinput_str = (char *) malloc(10);
sprintf(pipeinput_str, "CONSOLE%d", tty);
rfbLog("console_guess: file pipeinput %s\n",
pipeinput_str);
initialize_pipeinput();
} else if (have_uinput) {
pipeinput_str = strdup("UINPUT");
rfbLog("console_guess: file pipeinput %s\n",
pipeinput_str);
initialize_pipeinput();
}
}
if (! atparms) {
rfbLog("console_guess: could not get @ parameters.\n");
return NULL;
}
q = (char *) malloc(strlen("mmap:") + strlen(file) + 1 + strlen(atparms) + 1);
if (strstr(in, "console_vt")) {
sprintf(q, "snap:%s@%s", file, atparms);
} else {
sprintf(q, "map:%s@%s", file, atparms);
}
return q;
}
void console_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
static int control = 0, alt = 0;
allowed_input_t input;
if (debug_keyboard) fprintf(stderr, "console_key_command: %d %s\n", (int) keysym, down ? "down" : "up");
if (pipeinput_cons_fd < 0) {
return;
}
if (view_only) {
return;
}
get_allowed_input(client, &input);
if (! input.keystroke) {
return;
}
/* From LinuxVNC.c: */
if (keysym == XK_Control_L || keysym == XK_Control_R) {
if (! down) {
if (control > 0) {
control--;
}
} else {
control++;
}
return;
}
if (keysym == XK_Alt_L || keysym == XK_Alt_R) {
if (! down) {
if (alt > 0) {
alt--;
}
} else {
alt++;
}
return;
}
if (!down) {
return;
}
if (keysym == XK_Escape) {
keysym = 27;
}
if (control) {
/* shift down to the "control" zone */
if (keysym >= 'a' && keysym <= 'z') {
keysym -= ('a' - 1);
} else if (keysym >= 'A' && keysym <= 'Z') {
keysym -= ('A' - 1);
} else {
keysym = 0xffff;
}
} else if (alt) {
/* shift up to the upper half Latin zone */
if (keysym >= '!' && keysym <= '~') {
keysym += 128;
}
}
if (debug_keyboard) fprintf(stderr, "keysym now: %d\n", (int) keysym);
if (keysym == XK_Tab) {
keysym = '\t';
} else if (keysym == XK_Return || keysym == XK_KP_Enter) {
keysym = '\r';
} else if (keysym == XK_BackSpace) {
keysym = 8;
} else if (keysym == XK_Home || keysym == XK_KP_Home) {
keysym = 1;
} else if (keysym == XK_End || keysym == XK_KP_End) {
keysym = 5;
} else if (keysym == XK_Up || keysym == XK_KP_Up) {
keysym = 16;
} else if (keysym == XK_Down || keysym == XK_KP_Down) {
keysym = 14;
} else if (keysym == XK_Right || keysym == XK_KP_Right) {
keysym = 6;
} else if (keysym == XK_Next || keysym == XK_KP_Next) {
keysym = 6;
} else if (keysym == XK_Left || keysym == XK_KP_Left) {
keysym = 2;
} else if (keysym == XK_Prior || keysym == XK_KP_Prior) {
keysym = 2;
} else {
if (keysym >= XK_KP_Multiply && keysym <= XK_KP_Equal) {
keysym -= 0xFF80;
}
}
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCSTI)
if (keysym < 0x100) {
if (ioctl(pipeinput_cons_fd, TIOCSTI, &keysym) != -1) {
return;
}
perror("ioctl");
close(pipeinput_cons_fd);
pipeinput_cons_fd = -1;
if (! pipeinput_cons_dev) {
return;
}
pipeinput_cons_fd = open(pipeinput_cons_dev, O_WRONLY);
if (pipeinput_cons_fd < 0) {
rfbLog("pipeinput: could not reopen %s\n",
pipeinput_cons_dev);
perror("open");
return;
}
if (ioctl(pipeinput_cons_fd, TIOCSTI, &keysym) == -1) {
perror("ioctl");
close(pipeinput_cons_fd);
pipeinput_cons_fd = -1;
rfbLog("pipeinput: could not reopen %s\n",
pipeinput_cons_dev);
}
}
#endif
if (client) {}
}
void console_pointer_command(int mask, int x, int y, rfbClientPtr client) {
/* do not forget viewonly perms */
if (mask || x || y || client) {}
}