summaryrefslogtreecommitdiffstats
path: root/contrib/x11vnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/x11vnc.c')
-rw-r--r--contrib/x11vnc.c201
1 files changed, 163 insertions, 38 deletions
diff --git a/contrib/x11vnc.c b/contrib/x11vnc.c
index c937a22..e5367db 100644
--- a/contrib/x11vnc.c
+++ b/contrib/x11vnc.c
@@ -1,5 +1,5 @@
/*
- * x0vnc.c: a VNC server for X displays.
+ * x11vnc.c: a VNC server for X displays.
*
* Copyright (c) 2002 Karl J. Runge <runge@karlrunge.com> All rights reserved.
*
@@ -21,45 +21,30 @@
*
* This program is based heavily on the following programs:
*
- * original x11vnc.c of the libvncserver project (Johannes E. Schindelin)
+ * the originial x11vnc.c in libvncserver (Johannes E. Schindelin)
* krfb, the KDE desktopsharing project (Tim Jansen)
* x0rfbserver, the original native X vnc server (Jens Wagner)
*
* The primary goal of this program is to create a portable and simple
* command-line server utility that allows a VNC viewer to connect to an
- * actual X display (as x11vnc, krfb, and x0rfbserver do). The only
- * non-standard dependency of this program is the static library
- * libvncserver.a (although in some environments libjpeg.so may not be
- * readily available). To increase portability it is written in plain C.
+ * actual X display (as the above do). The only non-standard dependency
+ * of this program is the static library libvncserver.a (although in
+ * some environments libjpeg.so may not be readily available and needs
+ * to be installed, it may be found at ftp://ftp.uu.net/graphics/jpeg/).
+ * To increase portability it is written in plain C.
*
* The next goal is to improve performance and interactive response.
* The algorithm currently used here to achieve this is that of krfb
* (based on x0rfbserver algorithm). Additional heuristics are also
- * applied. Currently there are a bit too many of these...
+ * applied (currently there are a bit too many of these...)
*
* To build:
- * Obtain the libvncserver package (http://libvncserver.sourceforge.net)
- * and ensure that "make" and "make x11vnc" work correctly. Defining
- * HAVE_PTHREADS in the Makefile is recommended. One then could move the
- * x11vnc.c file aside, copy this file in its place into the source tree,
- * and issue:
- *
- * make x11vnc
- * mv x11vnc x0vnc
- *
- * to create the x0vnc binary. Otherwise, with x0vnc.c copied to
- * libvncserver source directory, something like this should work:
- *
- * gcc -Wall -DALLOW24BPP -I. -DBACKCHANNEL -c x0vnc.c
- * gcc -o x0vnc x0vnc.o -L. -lvncserver -L/usr/local/lib -lz -ljpeg \
- * -L/usr/X11R6/lib -lX11 -lXext -lXtst
- *
- * include -DHAVE_PTHREADS ... -lpthread to use threads.
- *
- * On Solaris the 2nd command might look something like:
- *
- * gcc -o x0vnc x0vnc.o -L. -lvncserver -L/usr/local/lib -lz -ljpeg \
- * -lsocket -lnsl -L/usr/X/lib -R/usr/X/lib -lX11 -lXext -lXtst
+ * Obtain the libvncserver package (http://libvncserver.sourceforge.net).
+ * As of 12/2002 this version of x11vnc.c is contained in the libvncserver
+ * CVS tree. Parameters in the Makefile should be adjusted to the build
+ * system and then "make x11vnc" should create it. For earlier releases
+ * (say libvncserver-0.4) this file may be inserted in place of the
+ * original x11vnc.c file.
*/
#include <unistd.h>
@@ -71,11 +56,24 @@
#include <X11/extensions/XTest.h>
#include <X11/keysym.h>
+/*
+ * Work around Bool and KeySym same names in X and rfb.
+ * Bool is #define int in <X11/Xlib.h>
+ * KeySym is typedef XID in <X11/X.h>
+ * (note that X and rfb KeySym types are the same so a bit silly to worry...
+ * the Bool types are different though)
+ */
+typedef Bool X_Bool;
+typedef KeySym X_KeySym;
+
+/* the #define Bool can be removed: */
#ifdef Bool
#undef Bool
#endif
-#define Bool RFBBool
+
+/* the KeySym typedef cannot be removed, so use an alias for rest of file: */
#define KeySym RFBKeySym
+
#include "rfb.h"
Display *dpy = 0;
@@ -129,6 +127,8 @@ int shared = 0; /* share vnc display. */
int view_only = 0; /* client can only watch. */
int connect_once = 1; /* allow only one client connection. */
+int use_altgr = 0; /* use the altgr_keyboard modifier tweak */
+
/*
* waitms is the msec to wait between screen polls. Not too old h/w shows
* poll times of 15-35ms, so maybe this value cuts the rest load by 2 or so.
@@ -143,7 +143,7 @@ int tile_fuzz = 2; /* tolerance for suspecting changed tiles touching */
/* a known changed tile. */
int grow_fill = 3; /* do the grow islands heuristic with this width. */
int gaps_fill = 4; /* do a final pass to try to fill gaps between tiles. */
-double fs_frac = 0.5; /* threshold tile fraction to do fullscreen updates. */
+double fs_frac = 0.6; /* threshold tile fraction to do fullscreen updates. */
#define NSCAN 32
int scanlines[NSCAN] = { /* scan pattern jitter from x0rfbserver */
@@ -217,6 +217,115 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
return(RFB_CLIENT_ACCEPT);
}
+/* For tweaking modifiers wrt the Alt-Graph key */
+
+#define LEFTSHIFT 1
+#define RIGHTSHIFT 2
+#define ALTGR 4
+char mod_state = 0;
+
+char modifiers[0x100];
+KeyCode keycodes[0x100], left_shift_code, right_shift_code, altgr_code;
+
+void initialize_keycodes() {
+ X_KeySym key, *keymap;
+ int i, j, minkey, maxkey, syms_per_keycode;
+
+ memset(modifiers, -1, sizeof(modifiers));
+
+ XDisplayKeycodes(dpy, &minkey, &maxkey);
+
+ keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
+ &syms_per_keycode);
+
+ for (i = minkey; i <= maxkey; i++) {
+ for (j = 0; j < syms_per_keycode; j++) {
+ key = keymap[ (i - minkey) * syms_per_keycode + j ];
+ if ( key >= ' ' && key < 0x100
+ && i == XKeysymToKeycode(dpy, key) ) {
+ keycodes[key] = i;
+ modifiers[key] = j;
+ }
+ }
+ }
+
+ left_shift_code = XKeysymToKeycode(dpy, XK_Shift_L);
+ right_shift_code = XKeysymToKeycode(dpy, XK_Shift_R);
+ altgr_code = XKeysymToKeycode(dpy, XK_Mode_switch);
+
+ XFree ((void *) keymap);
+}
+
+void tweak_mod(char mod, Bool down) {
+ Bool is_shift = mod_state & (LEFTSHIFT|RIGHTSHIFT);
+ X_Bool dn = (X_Bool) down;
+
+ if (mod < 0) {
+ return;
+ }
+
+ X_LOCK
+ if (is_shift && mod != 1) {
+ if (mod_state & LEFTSHIFT) {
+ XTestFakeKeyEvent(dpy, left_shift_code, !dn, CurrentTime);
+ }
+ if (mod_state & RIGHTSHIFT) {
+ XTestFakeKeyEvent(dpy, right_shift_code, !dn, CurrentTime);
+ }
+ }
+ if ( ! is_shift && mod == 1 ) {
+ XTestFakeKeyEvent(dpy, left_shift_code, dn, CurrentTime);
+ }
+ if ( (mod_state & ALTGR) && mod != 2 ) {
+ XTestFakeKeyEvent(dpy, altgr_code, !dn, CurrentTime);
+ }
+ if ( ! (mod_state & ALTGR) && mod == 2 ) {
+ XTestFakeKeyEvent(dpy, altgr_code, dn, CurrentTime);
+ }
+ X_UNLOCK
+}
+
+static void altgr_keyboard(Bool down, KeySym keysym, rfbClientPtr client) {
+ KeyCode k;
+ int tweak = 0;
+
+ if (view_only) {
+ return;
+ }
+
+#define ADJUSTMOD(sym, state) \
+ if (keysym == sym) { \
+ if (down) { \
+ mod_state |= state; \
+ } else { \
+ mod_state &= ~state; \
+ } \
+ }
+
+ ADJUSTMOD(XK_Shift_L, LEFTSHIFT)
+ ADJUSTMOD(XK_Shift_R, RIGHTSHIFT)
+ ADJUSTMOD(XK_Mode_switch, ALTGR)
+
+ if ( down && keysym >= ' ' && keysym < 0x100 ) {
+ tweak = 1;
+ tweak_mod(modifiers[keysym], True);
+ k = keycodes[keysym];
+ } else {
+ X_LOCK
+ k = XKeysymToKeycode(dpy, (X_KeySym) keysym);
+ X_UNLOCK
+ }
+ if ( k != NoSymbol ) {
+ X_LOCK
+ XTestFakeKeyEvent(dpy, k, (X_Bool) down, CurrentTime);
+ X_UNLOCK
+ }
+
+ if ( tweak ) {
+ tweak_mod(modifiers[keysym], False);
+ }
+}
+
/* key event handler */
static void keyboard(Bool down, KeySym keysym, rfbClientPtr client) {
KeyCode k;
@@ -224,19 +333,23 @@ static void keyboard(Bool down, KeySym keysym, rfbClientPtr client) {
if (view_only) {
return;
}
+
+ if (use_altgr) {
+ altgr_keyboard(down, keysym, client);
+ return;
+ }
X_LOCK
- /* KeySym is XID in <X11/X.h> */
- k = XKeysymToKeycode(dpy, (XID) keysym);
+ k = XKeysymToKeycode(dpy, (X_KeySym) keysym);
if ( k != NoSymbol ) {
- /* Bool is int in <X11/Xlib.h> */
- XTestFakeKeyEvent(dpy, k, (int) down, CurrentTime);
+ XTestFakeKeyEvent(dpy, k, (X_Bool) down, CurrentTime);
XFlush(dpy);
got_user_input++;
}
+
X_UNLOCK
}
@@ -1212,7 +1325,7 @@ void watch_loop(void) {
void print_help() {
char help[] =
-"x0vnc options:\n"
+"x11vnc options:\n"
"\n"
"-defer time time in ms to wait for updates before sending to\n"
" client [rfbDeferUpdateTime] (default %d)\n"
@@ -1231,6 +1344,9 @@ void print_help() {
" horizontal tiles into one big rectangle) (default %s).\n"
"-nohints do not use hints; send each tile separately.\n"
"\n"
+"-altgr use a mechanism to properly handle the AltGr modifier\n"
+" on certain keyboards (default %d).\n"
+"-noaltgr send the keysym directly to the X server.\n"
"-threads use threaded algorithm [rfbRunEventLoop] if compiled\n"
" with threads (default %s).\n"
"-nothreads do not use [rfbRunEventLoop].\n"
@@ -1242,8 +1358,9 @@ void print_help() {
;
fprintf(stderr, help, defer_update, waitms, gaps_fill, grow_fill,
fs_frac, tile_fuzz,
- use_hints ? "on":"off", use_threads ? "on":"off",
- view_only ? "on":"off", shared ? "on":"off");
+ use_hints ? "on":"off", use_altgr ? "on":"off",
+ use_threads ? "on":"off", view_only ? "on":"off",
+ shared ? "on":"off");
rfbUsage();
exit(1);
}
@@ -1282,6 +1399,10 @@ int main(int argc, char** argv) {
use_threads = 1;
} else if (!strcmp(argv[i], "-nothreads")) {
use_threads = 0;
+ } else if (!strcmp(argv[i], "-altgr")) {
+ use_altgr = 1;
+ } else if (!strcmp(argv[i], "-noaltgr")) {
+ use_altgr = 0;
} else if (!strcmp(argv[i], "-viewonly")) {
view_only = 1;
} else if (!strcmp(argv[i], "-shared")) {
@@ -1370,6 +1491,10 @@ int main(int argc, char** argv) {
initialize_shm();
+ if (use_altgr) {
+ initialize_keycodes();
+ }
+
printf("screen setup finished.\n");
watch_loop();