1/* 2 Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> 3 All rights reserved. 4 5This file is part of x11vnc. 6 7x11vnc is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2 of the License, or (at 10your option) any later version. 11 12x11vnc is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with x11vnc; if not, write to the Free Software 19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA 20or see <http://www.gnu.org/licenses/>. 21 22In addition, as a special exception, Karl J. Runge 23gives permission to link the code of its release of x11vnc with the 24OpenSSL project's "OpenSSL" library (or with modified versions of it 25that use the same license as the "OpenSSL" library), and distribute 26the linked executables. You must obey the GNU General Public License 27in all respects for all of the code used other than "OpenSSL". If you 28modify this file, you may extend this exception to your version of the 29file, but you are not obligated to do so. If you do not wish to do 30so, delete this exception statement from your version. 31*/ 32 33/* -- linuxfb.c -- */ 34 35#include "x11vnc.h" 36#include "cleanup.h" 37#include "scan.h" 38#include "xinerama.h" 39#include "screen.h" 40#include "pointer.h" 41#include "allowed_input_t.h" 42#include "uinput.h" 43#include "keyboard.h" 44#include "macosx.h" 45 46#if LIBVNCSERVER_HAVE_SYS_IOCTL_H 47#include <sys/ioctl.h> 48#endif 49#if LIBVNCSERVER_HAVE_LINUX_FB_H 50#include <linux/fb.h> 51#endif 52 53char *console_guess(char *str, int *fd); 54void console_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client); 55void console_pointer_command(int mask, int x, int y, rfbClientPtr client); 56 57 58void linux_dev_fb_msg(char *); 59 60char *console_guess(char *str, int *fd) { 61 char *q, *in = strdup(str); 62 char *atparms = NULL, *file = NULL; 63 int do_input, have_uinput, tty = -1; 64 65#ifdef MACOSX 66 return macosx_console_guess(str, fd); 67#endif 68 69 70 if (strstr(in, "/dev/fb") == in) { 71 free(in); 72 in = (char *) malloc(strlen("console:") + strlen(str) + 1); 73 sprintf(in, "console:%s", str); 74 } else if (strstr(in, "fb") == in) { 75 free(in); 76 in = (char *) malloc(strlen("console:/dev/") + strlen(str) + 1); 77 sprintf(in, "console:/dev/%s", str); 78 } else if (strstr(in, "vt") == in) { 79 free(in); 80 in = (char *) malloc(strlen("console_") + strlen(str) + 1); 81 sprintf(in, "console_%s", str); 82 } 83 84 if (strstr(in, "console") != in) { 85 rfbLog("console_guess: unrecognized console/fb format: %s\n", str); 86 free(in); 87 return NULL; 88 } 89 90 q = strrchr(in, '@'); 91 if (q) { 92 atparms = strdup(q+1); 93 *q = '\0'; 94 } 95 q = strrchr(in, ':'); 96 if (q) { 97 file = strdup(q+1); 98 *q = '\0'; 99 } 100 if (! file || file[0] == '\0') { 101 file = strdup("/dev/fb"); 102 } 103 if (strstr(file, "fb") == file) { 104 q = (char *) malloc(strlen("/dev/") + strlen(file) + 1); 105 sprintf(q, "/dev/%s", file); 106 free(file); 107 file = q; 108 } 109 if (!strcmp(file, "/dev/fb")) { 110 /* sometimes no sylink fb -> fb0 */ 111 struct stat sbuf; 112 if (stat(file, &sbuf) != 0) { 113 free(file); 114 file = strdup("/dev/fb0"); 115 } 116 } 117 118 do_input = 1; 119 if (pipeinput_str) { 120 have_uinput = 0; 121 do_input = 0; 122 } else { 123 have_uinput = check_uinput(); 124 } 125 if (strstr(in, "console_vt")) { 126 have_uinput = 0; 127 } 128 129 if (!strcmp(in, "consolex")) { 130 do_input = 0; 131 } else if (strstr(in, "console_vtx")) { 132 have_uinput = 0; 133 do_input = 0; 134 } else if (!strcmp(in, "console")) { 135 /* current active VT: */ 136 if (! have_uinput) { 137 tty = 0; 138 } 139 } else { 140 int n; 141 if (sscanf(in, "console%d", &n) == 1) { 142 tty = n; 143 have_uinput = 0; 144 } else if (sscanf(in, "console_vt%d", &n) == 1) { 145 tty = n; 146 have_uinput = 0; 147 } 148 } 149 if (strstr(in, "console_vt") == in) { 150 char tmp[100]; 151 int fd, rows = 30, cols = 80, w, h; 152 sprintf(tmp, "/dev/vcsa%d", tty); 153 file = strdup(tmp); 154 fd = open(file, O_RDWR); 155 if (fd >= 0) { 156 read(fd, tmp, 4); 157 rows = (unsigned char) tmp[0]; 158 cols = (unsigned char) tmp[1]; 159 close(fd); 160 } 161 w = cols * 8; 162 h = rows * 16; 163 rfbLog("%s %dx%d\n", file, cols, rows); 164 if (getenv("RAWFB_VCSA_BPP")) { 165 /* 8bpp, etc */ 166 int bt = atoi(getenv("RAWFB_VCSA_BPP")); 167 if (bt > 0 && bt <=32) { 168 sprintf(tmp, "%dx%dx%d", w, h, bt); 169 } else { 170 sprintf(tmp, "%dx%dx16", w, h); 171 } 172 } else { 173 /* default 16bpp */ 174 sprintf(tmp, "%dx%dx16", w, h); 175 } 176 atparms = strdup(tmp); 177 } 178 rfbLog("console_guess: file is %s\n", file); 179 180 if (! atparms) { 181#if LIBVNCSERVER_HAVE_LINUX_FB_H 182#if LIBVNCSERVER_HAVE_SYS_IOCTL_H 183 struct fb_var_screeninfo var_info; 184 int d = open(file, O_RDWR); 185 if (d >= 0) { 186 int w, h, b; 187 unsigned long rm = 0, gm = 0, bm = 0; 188 if (ioctl(d, FBIOGET_VSCREENINFO, &var_info) != -1) { 189 w = (int) var_info.xres; 190 h = (int) var_info.yres; 191 b = (int) var_info.bits_per_pixel; 192 193 rm = (1 << var_info.red.length) - 1; 194 gm = (1 << var_info.green.length) - 1; 195 bm = (1 << var_info.blue.length) - 1; 196 rm = rm << var_info.red.offset; 197 gm = gm << var_info.green.offset; 198 bm = bm << var_info.blue.offset; 199 200 if (b == 8 && rm == 0xff && gm == 0xff && bm == 0xff) { 201 /* I don't believe it... */ 202 rm = 0x07; 203 gm = 0x38; 204 bm = 0xc0; 205 } 206 if (b <= 8 && (rm == gm && gm == bm)) { 207 if (b == 4) { 208 rm = 0x07; 209 gm = 0x38; 210 bm = 0xc0; 211 } 212 } 213 214 /* @66666x66666x32:0xffffffff:... */ 215 atparms = (char *) malloc(200); 216 sprintf(atparms, "%dx%dx%d:%lx/%lx/%lx", 217 w, h, b, rm, gm, bm); 218 *fd = d; 219 } else { 220 perror("ioctl"); 221 close(d); 222 } 223 } else { 224 rfbLog("could not open: %s\n", file); 225 rfbLogPerror("open"); 226 linux_dev_fb_msg(file); 227 close(d); 228 } 229#endif 230#endif 231 } 232 233 if (atparms) { 234 int gw, gh, gb; 235 if (sscanf(atparms, "%dx%dx%d", &gw, &gh, &gb) == 3) { 236 fb_x = gw; 237 fb_y = gh; 238 fb_b = gb; 239 } 240 } 241 242 if (do_input) { 243 if (tty >=0 && tty < 64) { 244 pipeinput_str = (char *) malloc(10); 245 sprintf(pipeinput_str, "CONSOLE%d", tty); 246 rfbLog("console_guess: file pipeinput %s\n", 247 pipeinput_str); 248 initialize_pipeinput(); 249 } else if (have_uinput) { 250 pipeinput_str = strdup("UINPUT"); 251 rfbLog("console_guess: file pipeinput %s\n", 252 pipeinput_str); 253 initialize_pipeinput(); 254 } 255 } 256 257 if (! atparms) { 258 rfbLog("console_guess: could not get @ parameters.\n"); 259 return NULL; 260 } 261 262 q = (char *) malloc(strlen("mmap:") + strlen(file) + 1 + strlen(atparms) + 1); 263 if (strstr(in, "console_vt")) { 264 sprintf(q, "snap:%s@%s", file, atparms); 265 } else { 266 sprintf(q, "map:%s@%s", file, atparms); 267 } 268 free(atparms); 269 return q; 270} 271 272void console_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { 273 static int control = 0, alt = 0; 274 allowed_input_t input; 275 276 if (debug_keyboard) fprintf(stderr, "console_key_command: %d %s\n", (int) keysym, down ? "down" : "up"); 277 278 if (pipeinput_cons_fd < 0) { 279 return; 280 } 281 if (view_only) { 282 return; 283 } 284 get_allowed_input(client, &input); 285 if (! input.keystroke) { 286 return; 287 } 288 289 /* From LinuxVNC.c: */ 290 if (keysym == XK_Control_L || keysym == XK_Control_R) { 291 if (! down) { 292 if (control > 0) { 293 control--; 294 } 295 } else { 296 control++; 297 } 298 return; 299 } 300 if (keysym == XK_Alt_L || keysym == XK_Alt_R) { 301 if (! down) { 302 if (alt > 0) { 303 alt--; 304 } 305 } else { 306 alt++; 307 } 308 return; 309 } 310 if (!down) { 311 return; 312 } 313 if (keysym == XK_Escape) { 314 keysym = 27; 315 } 316 if (control) { 317 /* shift down to the "control" zone */ 318 if (keysym >= 'a' && keysym <= 'z') { 319 keysym -= ('a' - 1); 320 } else if (keysym >= 'A' && keysym <= 'Z') { 321 keysym -= ('A' - 1); 322 } else { 323 keysym = 0xffff; 324 } 325 } else if (alt) { 326 /* shift up to the upper half Latin zone */ 327 if (keysym >= '!' && keysym <= '~') { 328 keysym += 128; 329 } 330 } 331 if (debug_keyboard) fprintf(stderr, "keysym now: %d\n", (int) keysym); 332 if (keysym == XK_Tab) { 333 keysym = '\t'; 334 } else if (keysym == XK_Return || keysym == XK_KP_Enter) { 335 keysym = '\r'; 336 } else if (keysym == XK_BackSpace) { 337 keysym = 8; 338 } else if (keysym == XK_Home || keysym == XK_KP_Home) { 339 keysym = 1; 340 } else if (keysym == XK_End || keysym == XK_KP_End) { 341 keysym = 5; 342 } else if (keysym == XK_Up || keysym == XK_KP_Up) { 343 keysym = 16; 344 } else if (keysym == XK_Down || keysym == XK_KP_Down) { 345 keysym = 14; 346 } else if (keysym == XK_Right || keysym == XK_KP_Right) { 347 keysym = 6; 348 } else if (keysym == XK_Next || keysym == XK_KP_Next) { 349 keysym = 6; 350 } else if (keysym == XK_Left || keysym == XK_KP_Left) { 351 keysym = 2; 352 } else if (keysym == XK_Prior || keysym == XK_KP_Prior) { 353 keysym = 2; 354 } else { 355 if (keysym >= XK_KP_Multiply && keysym <= XK_KP_Equal) { 356 keysym -= 0xFF80; 357 } 358 } 359#if LIBVNCSERVER_HAVE_SYS_IOCTL_H && defined(TIOCSTI) 360 if (keysym < 0x100) { 361 if (ioctl(pipeinput_cons_fd, TIOCSTI, &keysym) != -1) { 362 return; 363 } 364 perror("ioctl"); 365 close(pipeinput_cons_fd); 366 pipeinput_cons_fd = -1; 367 if (! pipeinput_cons_dev) { 368 return; 369 } 370 pipeinput_cons_fd = open(pipeinput_cons_dev, O_WRONLY); 371 if (pipeinput_cons_fd < 0) { 372 rfbLog("pipeinput: could not reopen %s\n", 373 pipeinput_cons_dev); 374 perror("open"); 375 return; 376 } 377 if (ioctl(pipeinput_cons_fd, TIOCSTI, &keysym) == -1) { 378 perror("ioctl"); 379 close(pipeinput_cons_fd); 380 pipeinput_cons_fd = -1; 381 rfbLog("pipeinput: could not reopen %s\n", 382 pipeinput_cons_dev); 383 } 384 } 385#endif 386 387 if (client) {} 388} 389 390void console_pointer_command(int mask, int x, int y, rfbClientPtr client) { 391 /* do not forget viewonly perms */ 392 if (mask || x || y || client) {} 393} 394 395