1 /*
2 Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3 All rights reserved.
4
5 This file is part of x11vnc.
6
7 x11vnc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11
12 x11vnc is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with x11vnc; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20 or see <http://www.gnu.org/licenses/>.
21
22 In addition, as a special exception, Karl J. Runge
23 gives permission to link the code of its release of x11vnc with the
24 OpenSSL project's "OpenSSL" library (or with modified versions of it
25 that use the same license as the "OpenSSL" library), and distribute
26 the linked executables. You must obey the GNU General Public License
27 in all respects for all of the code used other than "OpenSSL". If you
28 modify this file, you may extend this exception to your version of the
29 file, but you are not obligated to do so. If you do not wish to do
30 so, 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
53 char *console_guess(char *str, int *fd);
54 void console_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
55 void console_pointer_command(int mask, int x, int y, rfbClientPtr client);
56
57
58 void linux_dev_fb_msg(char *);
59
console_guess(char * str,int * fd)60 char *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
console_key_command(rfbBool down,rfbKeySym keysym,rfbClientPtr client)272 void 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
console_pointer_command(int mask,int x,int y,rfbClientPtr client)390 void 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