diff options
author | runge <runge> | 2004-05-06 02:46:07 +0000 |
---|---|---|
committer | runge <runge> | 2004-05-06 02:46:07 +0000 |
commit | d43fc7efbe881b67be16ee54cd859f5759bf04a0 (patch) | |
tree | 2ea67c3ade351ead6607e6997f6c5c2d3a7c0efc /contrib | |
parent | f5cfa4bc8d73f16e963f4a2aa99f63614f7da758 (diff) | |
download | libtdevnc-d43fc7efbe881b67be16ee54cd859f5759bf04a0.tar.gz libtdevnc-d43fc7efbe881b67be16ee54cd859f5759bf04a0.zip |
x11vnc: mouse -> keystroke and keystroke -> mouse remappings.
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/ChangeLog | 10 | ||||
-rw-r--r-- | contrib/x11vnc.c | 562 |
2 files changed, 445 insertions, 127 deletions
diff --git a/contrib/ChangeLog b/contrib/ChangeLog index 06e29e5..758308e 100644 --- a/contrib/ChangeLog +++ b/contrib/ChangeLog @@ -1,3 +1,13 @@ +2004-05-05 Karl Runge <runge@karlrunge.com> + * enable mouse button -> keystrokes mapping in -buttonmap (mousewheel) + * enable keystroke -> mouse button mapping in -remap (touchpad paste) + (-remap incompat ':' -> '-', sorry...) + * shm OS blacklist (i.e. <= SunOS 5.8) -> -onetile + * revert to check_user_input() under -nofb + * cleanup: lastmod, remove tile_shm and update_client_pointer, + debug output, rfbPort failure. + * user friendly last line: 'The VNC desktop is hostname:0' + 2004-04-28 Karl Runge <runge@karlrunge.com> * -auth cmdline option for xauthority. * decrease default deferupdate under -nofb. diff --git a/contrib/x11vnc.c b/contrib/x11vnc.c index a0b6e95..450ce1c 100644 --- a/contrib/x11vnc.c +++ b/contrib/x11vnc.c @@ -59,7 +59,7 @@ * can be very painful; one has to modify one's behavior a bit. * * General audio at the remote display is lost unless one separately - * sets up some audio side-channel. + * sets up some audio side-channel such as esd. * * It does not appear possible to query the X server for the current * cursor shape. We can use XTest to compare cursor to current window's @@ -95,8 +95,11 @@ #include <unistd.h> #include <signal.h> +#include <sys/utsname.h> + #include <sys/ipc.h> #include <sys/shm.h> + #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/extensions/XShm.h> @@ -126,6 +129,9 @@ #include <X11/extensions/Xinerama.h> #endif +/* date +'"lastmod: %Y-%m-%d";' */ +char lastmod[] = "lastmod: 2004-05-05"; + /* X and rfb framebuffer */ Display *dpy = 0; @@ -145,9 +151,6 @@ XImage *scanline; XImage *fullscreen; int fs_factor = 0; -#ifdef SINGLE_TILE_SHM -XShmSegmentInfo tile_shm; -#endif XShmSegmentInfo *tile_row_shm; /* for all possible row runs */ XShmSegmentInfo scanline_shm; XShmSegmentInfo fullscreen_shm; @@ -333,9 +336,6 @@ void clean_up_exit (int ret) { exit_flag = 1; /* remove the shm areas: */ -#ifdef SINGLE_TILE_SHM - shm_clean(&tile_shm, tile); -#endif shm_clean(&scanline_shm, scanline); shm_clean(&fullscreen_shm, fullscreen); @@ -377,9 +377,6 @@ void interrupted (int sig) { * to avoid deadlock, etc, just delete the shm areas and * leave the X stuff hanging. */ -#ifdef SINGLE_TILE_SHM - shm_delete(&tile_shm); -#endif shm_delete(&scanline_shm); shm_delete(&fullscreen_shm); @@ -424,7 +421,6 @@ void set_signals(void) { if (sigpipe == 1) { #ifdef SIG_IGN - rfbLog("set_signals: ignoring SIGPIPE\n"); signal(SIGPIPE, SIG_IGN); #endif } else if (sigpipe == 2) { @@ -771,6 +767,7 @@ void initialize_modtweak() { typedef struct keyremap { KeySym before; KeySym after; + int isbutton; struct keyremap *next; } keyremap_t; @@ -778,22 +775,22 @@ keyremap_t *keyremaps = NULL; void initialize_remap(char *infile) { FILE *in; - char *p, line[256], str1[256], str2[256]; + char *p, *q, line[256], str1[256], str2[256]; int i; KeySym ksym1, ksym2; keyremap_t *remap, *current; in = fopen(infile, "r"); if (in == NULL) { - /* assume cmd line key1:key2,key3:key4 */ - if (! strchr(infile, ':') || (in = tmpfile()) == NULL) { + /* assume cmd line key1-key2,key3-key4 */ + if (! strchr(infile, '-') || (in = tmpfile()) == NULL) { rfbLog("remap: cannot open: %s\n", infile); perror("fopen"); clean_up_exit(1); } p = infile; while (*p) { - if (*p == ':') { + if (*p == '-') { fprintf(in, " "); } else if (*p == ',') { fprintf(in, "\n"); @@ -807,7 +804,7 @@ void initialize_remap(char *infile) { rewind(in); } while (fgets(line, 256, in) != NULL) { - int blank = 1; + int blank = 1, isbtn = 0; p = line; while (*p) { if (! isspace(*p)) { @@ -822,6 +819,10 @@ void initialize_remap(char *infile) { if (strchr(line, '#')) { continue; } + if ( (q = strchr(line, '-')) != NULL) { + /* allow Keysym1-Keysym2 notation */ + *q = ' '; + } if (sscanf(line, "%s %s", str1, str2) != 2) { rfbLog("remap: bad line: %s\n", line); @@ -838,6 +839,13 @@ void initialize_remap(char *infile) { } else { ksym2 = XStringToKeysym(str2); } + if (ksym2 == NoSymbol) { + int i; + if (sscanf(str2, "Button%d", &i) == 1) { + ksym2 = (KeySym) i; + isbtn = 1; + } + } if (ksym1 == NoSymbol || ksym2 == NoSymbol) { rfbLog("warning: skipping bad remap line: %s", line); continue; @@ -845,9 +853,10 @@ void initialize_remap(char *infile) { remap = (keyremap_t *) malloc((size_t) sizeof(keyremap_t)); remap->before = ksym1; remap->after = ksym2; + remap->isbutton = isbtn; remap->next = NULL; - rfbLog("remapping: (%s, 0x%x) -> (%s, 0x%x)\n", str1, ksym1, - str2, ksym2); + rfbLog("remapping: (%s, 0x%x) -> (%s, 0x%x) isbtn=%d\n", str1, + ksym1, str2, ksym2, isbtn); if (keyremaps == NULL) { keyremaps = remap; } else { @@ -972,9 +981,11 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr * running under -modtweak. */ rfbClientPtr last_keyboard_client = NULL; +int num_buttons = -1; static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { KeyCode k; + int isbutton = 0; if (debug_keyboard) { X_LOCK; @@ -993,13 +1004,17 @@ static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { while (remap != NULL) { if (remap->before == keysym) { keysym = remap->after; + isbutton = remap->isbutton; if (debug_keyboard) { + X_LOCK; rfbLog("keyboard(): remapping keysym: " "0x%x \"%s\" -> 0x%x \"%s\"\n", (int) remap->before, XKeysymToString(remap->before), (int) remap->after, + remap->isbutton ? "button" : XKeysymToString(remap->after)); + X_UNLOCK; } break; } @@ -1007,6 +1022,28 @@ static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { } } + if (isbutton) { + int button = (int) keysym; + if (! down) { + return; /* nothing to send */ + } + if (debug_keyboard) { + rfbLog("keyboard(): remapping keystroke to button %d" + " click\n", button); + } + if (button < 1 || button > num_buttons) { + rfbLog("keyboard(): ignoring mouse button out of " + "bounds: %d\n", button); + return; + } + X_LOCK; + XTestFakeButtonEvent(dpy, button, True, CurrentTime); + XTestFakeButtonEvent(dpy, button, False, CurrentTime); + XFlush(dpy); + X_UNLOCK; + return; + } + if (use_modifier_tweak) { modifier_tweak_keyboard(down, keysym, client); X_LOCK; @@ -1040,16 +1077,178 @@ static void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) { /* * pointer event handling routines. */ +typedef struct ptrremap { + KeySym keysym; + KeyCode keycode; + int end; + int button; + int down; + int up; +} prtremap_t; + MUTEX(pointerMutex); #define MAX_BUTTONS 5 -int pointer_map[MAX_BUTTONS+1]; -int num_buttons = -1; +#define MAX_BUTTON_EVENTS 50 +prtremap_t pointer_map[MAX_BUTTONS+1][MAX_BUTTON_EVENTS]; char *pointer_remap = NULL; void update_pointer(int, int, int); -void init_pointer(void) { + +/* based on IsModifierKey in Xutil.h */ +#define ismodkey(keysym) \ + ((((KeySym)(keysym) >= XK_Shift_L) && ((KeySym)(keysym) <= XK_Hyper_R))) + + +/* + * For parsing the -buttonmap sections, e.g. "4" or ":Up+Up+Up:" + */ +void buttonparse(int from, char **s) { + char *q; + int to, i; + int modisdown[256]; + + q = *s; + + for (i=0; i<256; i++) { + modisdown[i] = 0; + } + + if (*q == ':') { + /* :sym1+sym2+...+symN: format */ + int l = 0, n = 0; + char list[1000]; + char *t, *kp = q + 1; + KeyCode kcode; + + while (*(kp+l) != ':' && *(kp+l) != '\0') { + /* loop to the matching ':' */ + l++; + if (l >= 1000) { + rfbLog("buttonparse: keysym list too long: " + "%s\n", q); + break; + } + } + *(kp+l) = '\0'; + strncpy(list, kp, l); + list[l] = '\0'; + rfbLog("remap button %d using \"%s\"\n", from, list); + + /* loop over tokens separated by '+' */ + t = strtok(list, "+"); + while (t) { + KeySym ksym; + int i; + if (n >= MAX_BUTTON_EVENTS - 20) { + rfbLog("buttonparse: too many button map " + "events: %s\n", list); + break; + } + if (sscanf(t, "0x%x", &i) == 1) { + ksym = (KeySym) i; /* hex value */ + } else { + ksym = XStringToKeysym(t); /* string value */ + } + if (ksym == NoSymbol) { + /* see if Button<N> "keysym" was used: */ + if (sscanf(t, "Button%d", &i) == 1) { + rfbLog(" event %d: button %d\n", + from, n+1, i); + if (i == 0) i = -1; /* bah */ + pointer_map[from][n].keysym = NoSymbol; + pointer_map[from][n].keycode = NoSymbol; + pointer_map[from][n].button = i; + pointer_map[from][n].end = 0; + pointer_map[from][n].down = 0; + pointer_map[from][n].up = 0; + } else { + rfbLog("buttonparse: ignoring unknown " + "keysym: %s\n", t); + n--; + } + } else { + kcode = XKeysymToKeycode(dpy, ksym); + + pointer_map[from][n].keysym = ksym; + pointer_map[from][n].keycode = kcode; + pointer_map[from][n].button = 0; + pointer_map[from][n].end = 0; + if (! ismodkey(ksym) ) { + /* do both down then up */ + pointer_map[from][n].down = 1; + pointer_map[from][n].up = 1; + } else { + if (modisdown[kcode]) { + pointer_map[from][n].down = 0; + pointer_map[from][n].up = 1; + modisdown[kcode] = 0; + } else { + pointer_map[from][n].down = 1; + pointer_map[from][n].up = 0; + modisdown[kcode] = 1; + } + } + rfbLog(" event %d: keysym %s (0x%x) -> " + "keycode 0x%x down=%d up=%d\n", n+1, + XKeysymToString(ksym), ksym, kcode, + pointer_map[from][n].down, + pointer_map[from][n].up); + } + t = strtok(NULL, "+"); + n++; + } + + /* we must release any modifiers that are still down: */ + for (i=0; i<256; i++) { + kcode = (KeyCode) i; + if (n >= MAX_BUTTON_EVENTS) { + rfbLog("buttonparse: too many button map " + "events: %s\n", list); + break; + } + if (modisdown[kcode]) { + pointer_map[from][n].keysym = NoSymbol; + pointer_map[from][n].keycode = kcode; + pointer_map[from][n].button = 0; + pointer_map[from][n].end = 0; + pointer_map[from][n].down = 0; + pointer_map[from][n].up = 1; + modisdown[kcode] = 0; + n++; + } + } + + /* advance the source pointer position */ + (*s) += l+2; + } else { + /* single digit format */ + char str[2]; + str[0] = *q; + str[1] = '\0'; + + to = atoi(str); + if (to < 1) { + rfbLog("skipping invalid remap button \"%d\" for button" + " %d from string \"%s\"\n", + to, from, str); + } else { + rfbLog("remap button %d using \"%s\"\n", from, str); + rfbLog(" button: %d -> %d\n", from, to); + pointer_map[from][0].keysym = NoSymbol; + pointer_map[from][0].keycode = NoSymbol; + pointer_map[from][0].button = to; + pointer_map[from][0].end = 0; + pointer_map[from][0].down = 0; + pointer_map[from][0].up = 0; + } + /* advance the source pointer position */ + (*s)++; + } +} + +void initialize_pointer_map(void) { unsigned char map[MAX_BUTTONS]; - int i; + int i, k; /* * This routine counts the number of pointer buttons on the X * server (to avoid problems, even crashes, if a client has more @@ -1059,23 +1258,33 @@ void init_pointer(void) { X_LOCK; num_buttons = XGetPointerMapping(dpy, map, MAX_BUTTONS); - X_UNLOCK; + if (num_buttons < 0) { num_buttons = 0; } /* FIXME: should use info in map[] */ for (i=1; i<= MAX_BUTTONS; i++) { - pointer_map[i] = i; + for (k=0; k < MAX_BUTTON_EVENTS; k++) { + pointer_map[i][k].end = 1; + } + pointer_map[i][0].keysym = NoSymbol; + pointer_map[i][0].keycode = NoSymbol; + pointer_map[i][0].button = i; + pointer_map[i][0].end = 0; + pointer_map[i][0].down = 0; + pointer_map[i][0].up = 0; } if (pointer_remap) { - /* -buttonmap, format is like: 12-21:2 */ - char *p, *q; + /* -buttonmap, format is like: 12-21=2 */ + char *p, *q, *remap = pointer_remap; int n; - if ((p = strchr(pointer_remap, ':')) != NULL) { + + if ((p = strchr(remap, '=')) != NULL) { /* undocumented max button number */ n = atoi(p+1); + *p = '\0'; if (n < num_buttons || num_buttons == 0) { num_buttons = n; } else { @@ -1084,30 +1293,31 @@ void init_pointer(void) { num_buttons = n; } } - if ((q = strchr(pointer_remap, '-')) != NULL) { + if ((q = strchr(remap, '-')) != NULL) { /* * The '-' separates the 'from' and 'to' lists, * then it is kind of like tr(1). */ char str[2]; int from, to; - p = pointer_remap; + + rfbLog("remapping pointer buttons using string:\n"); + rfbLog(" \"%s\"\n", remap); + + p = remap; q++; i = 0; str[1] = '\0'; while (*p != '-') { + int n; str[0] = *p; from = atoi(str); - str[0] = *(q+i); - to = atoi(str); - rfbLog("button remap: %d -> %d using: " - "%s\n", from, to, pointer_remap); - pointer_map[from] = to; + buttonparse(from, &q); p++; - i++; } } } + X_UNLOCK; } /* @@ -1125,9 +1335,6 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) { return; } - if (num_buttons < 0) { - init_pointer(); - } if (mask >= 0) { /* @@ -1248,22 +1455,67 @@ void update_pointer(int mask, int x, int y) { last_event = last_input = time(0); for (i=0; i < MAX_BUTTONS; i++) { - /* look for buttons that have be clicked or released: */ - if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) { - if (debug_pointer) { - rfbLog("pointer(): mask change: mask: 0x%x -> " - "0x%x button: %d\n", button_mask, mask,i+1); + /* look for buttons that have be clicked or released: */ + if ( (button_mask & (1<<i)) != (mask & (1<<i)) ) { + int k; + if (debug_pointer) { + rfbLog("pointer(): mask change: mask: 0x%x -> " + "0x%x button: %d\n", button_mask, mask,i+1); + } + for (k=0; k < MAX_BUTTON_EVENTS; k++) { + int bmask = (mask & (1<<i)); + + if (pointer_map[i+1][k].end) { + break; } - mb = pointer_map[i+1]; - if (num_buttons && mb > num_buttons) { - rfbLog("ignoring mouse button out of bounds: %d" - ">%d mask: 0x%x -> 0x%x\n", mb, num_buttons, - button_mask, mask); - continue; + + if (pointer_map[i+1][k].button) { + /* sent button up or down */ + mb = pointer_map[i+1][k].button; + if ((num_buttons && mb > num_buttons) + || mb < 1) { + rfbLog("ignoring mouse button out of " + "bounds: %d>%d mask: 0x%x -> 0x%x\n", + mb, num_buttons, button_mask, mask); + continue; + } + if (debug_pointer) { + rfbLog("pointer(): sending button %d" + " %s (event %d)\n", mb, bmask + ? "down" : "up", k+1); + } + XTestFakeButtonEvent(dpy, mb, (mask & (1<<i)) + ? True : False, CurrentTime); + } else { + /* sent keysym up or down */ + KeyCode key = pointer_map[i+1][k].keycode; + int up = pointer_map[i+1][k].up; + int down = pointer_map[i+1][k].down; + + if (! bmask) { + /* do not send keysym on button up */ + continue; + } + if (debug_pointer) { + rfbLog("pointer(): sending button %d " + "down as keycode 0x%x (event %d)\n", + i+1, key, k+1); + rfbLog(" down=%d up=%d " + "keysym: %s\n", down, up, + XKeysymToString(XKeycodeToKeysym( + dpy, key, 0))); + } + if (down) { + XTestFakeKeyEvent(dpy, key, True, + CurrentTime); + } + if (up) { + XTestFakeKeyEvent(dpy, key, False, + CurrentTime); + } } - XTestFakeButtonEvent(dpy, mb, - (mask & (1<<i)) ? True : False, CurrentTime); } + } } if (nofb) { @@ -1294,13 +1546,17 @@ void initialize_watch_bell() { int ir, reason; if (! XkbSelectEvents(dpy, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask) ) { - fprintf(stderr, "warning: disabling bell.\n"); + if (! quiet) { + fprintf(stderr, "warning: disabling bell.\n"); + } watch_bell = 0; return; } if (! XkbOpenDisplay(DisplayString(dpy), &xkb_base_event_type, &ir, NULL, NULL, &reason) ) { - fprintf(stderr, "warning: disabling bell.\n"); + if (! quiet) { + fprintf(stderr, "warning: disabling bell.\n"); + } watch_bell = 0; } } @@ -2057,46 +2313,6 @@ void blackout_nearby_tiles(x, y, dt) { } /* - * This is a special workaround to quickly send rfbCursorPosUpdates - * to client(s) when in -nofb mode, e.g. Win2VNC. It sends the updates - * immediately (by-passing libvncserver). Requires a customized Win2VNC - * to interpret the rfbCursorPosUpdates. Currently no big reason to - * do this for non-nofb mode (i.e. normal viewing) and so the normal - * libvncserver mechanism is used. Thanks to Edoardo Tirtarahardja. - */ -void update_client_pointer(rfbClientPtr cl, rfbBool send) { - rfbFramebufferUpdateMsg *fu; - - if (! nofb) { - /* normal libvncserver mechanism: */ - cl->cursorWasMoved = send; - return; - } - if (! send) { - return; - } - if (cl->state != RFB_NORMAL) { - /* bad idea to force this data to initializing clients */ - return; - } - - fu = (rfbFramebufferUpdateMsg*) cl->updateBuf; - cl->rfbFramebufferUpdateMessagesSent++; - fu->type = rfbFramebufferUpdate; - fu->nRects = Swap16IfLE(1); - memcpy(&cl->updateBuf[cl->ublen], (char*) fu, - sz_rfbFramebufferUpdateMsg); - cl->ublen = sz_rfbFramebufferUpdateMsg; - - rfbSendCursorPos(cl); - - if (debug_pointer) { - rfbLog("Sending rfbEncodingPointerPos message to host %s with " - "x=%d,y=%d\n", cl->host, screen->cursorX, screen->cursorY); - } -} - -/* * Send rfbCursorPosUpdates back to clients that understand them. This * seems to be TightVNC specific. */ @@ -2134,7 +2350,7 @@ void cursor_pos_updates(int x, int y) { * send a pointer position. */ if (x == cursor_x && y == cursor_y) { - update_client_pointer(cl, FALSE); + cl->cursorWasMoved = FALSE; } else { /* an X11 app evidently warped the pointer */ if (debug_pointer) { @@ -2142,11 +2358,11 @@ void cursor_pos_updates(int x, int y) { "detected dx=%3d dy=%3d\n", cursor_x - x, cursor_y - y); } - update_client_pointer(cl, TRUE); + cl->cursorWasMoved = TRUE; cnt++; } } else { - update_client_pointer(cl, TRUE); + cl->cursorWasMoved = TRUE; cnt++; } } @@ -3224,11 +3440,6 @@ void initialize_shm() { int i; /* set all shm areas to "none" before trying to create any */ -#ifdef SINGLE_TILE_SHM - tile_shm.shmid = -1; - tile_shm.shmaddr = (char *) -1; - tile = NULL; -#endif scanline_shm.shmid = -1; scanline_shm.shmaddr = (char *) -1; scanline = NULL; @@ -3241,14 +3452,6 @@ void initialize_shm() { tile_row[i] = NULL; } -#ifdef SINGLE_TILE_SHM - /* the tile (e.g. 32x32) shared memory area image: */ - - if (! shm_create(&tile_shm, &tile, tile_x, tile_y, "tile")) { - clean_up_exit(1); - } -#endif - /* the scanline (e.g. 1280x1) shared memory area image: */ if (! shm_create(&scanline_shm, &scanline, dpy_x, 1, "scanline")) { @@ -4659,7 +4862,7 @@ void watch_loop(void) { if (! use_threads) { rfbProcessEvents(screen, -1); - if (! nofb && check_user_input(dt, &cnt)) { + if (check_user_input(dt, &cnt)) { /* true means loop back for more input */ continue; } @@ -4726,12 +4929,14 @@ void watch_loop(void) { * to eat as much user input here as we can using some hints from the * duration of the previous scan_for_updates() call (in dt). * + * note: we do this even under -nofb + * * return of 1 means watch_loop should short-circuit and reloop, * return of 0 means watch_loop should proceed to scan_for_updates(). */ int check_user_input(double dt, int *cnt) { - + if (old_pointer) { /* every n-th drops thru to scan */ if ((got_user_input || ui_skip < 0) && *cnt % ui_skip != 0) { @@ -4881,10 +5086,14 @@ void print_help() { "exit as soon as a client disconnects. See -shared and -forever below\n" "to override these protections.\n" "\n" +"For additional info see: http://www.karlrunge.com/x11vnc/\n" +" and http://www.karlrunge.com/x11vnc/#faq\n" +"\n" "Options:\n" "\n" "-display disp X11 server display to connect to, the X server process\n" " must be running on same machine and support MIT-SHM.\n" +" Equivalent to setting the DISPLAY env. variable.\n" "-id windowid Show the window corresponding to <windowid> not the\n" " entire display. Warning: bugs! new toplevels missed!...\n" "-flashcmap In 8bpp indexed color, let the installed colormap flash\n" @@ -4920,7 +5129,8 @@ void print_help() { "\n" "-noshm Do not use the MIT-SHM extension for the polling.\n" " remote displays can be polled this way: be careful\n" -" this can use large amounts of network bandwidth.\n" +" this can use large amounts of network bandwidth. Also\n" +" of use if machine has a limited number of shm segments.\n" "-flipbyteorder Sometimes needed if remotely polled host has different\n" " endianness. Ignored unless -noshm is set.\n" "-blackout string Black out rectangles on the screen. string is a comma\n" @@ -4942,7 +5152,9 @@ void print_help() { "-nomodtweak Send the keysym directly to the X server.\n" "-remap string Read keysym remappings from file \"string\". Format is\n" " one pair of keysyms per line (can be name or hex value).\n" -" \"string\" can also be of form: key1:key2,key3:key4...\n" +" \"string\" can also be of form: key1-key2,key3-key4...\n" +" To map a key to a button click, use the fake keysyms\n" +" \"Button1\", ..., etc. E.g. -remap Super_R-Button2\n" "-nobell Do not watch for XBell events.\n" "-nofb Ignore framebuffer: only process keyboard and pointer.\n" "-nosel Do not manage exchange of X selection/cutbuffer.\n" @@ -4958,8 +5170,24 @@ void print_help() { " on touchscreens or other non-standard setups).\n" "-cursorpos Send the X cursor position back to all vnc clients that\n" " support the TightVNC CursorPosUpdates extension.\n" -"-buttonmap str String to remap mouse buttons. Format: IJK-LMN, this\n" +"-buttonmap string String to remap mouse buttons. Format: IJK-LMN, this\n" " maps buttons I -> L, etc., e.g. -buttonmap 13-31\n" +"\n" +" Button presses can also be mapped to keysyms: replace\n" +" a button digit on the right of the dash with :<sym>:\n" +" or :<sym1>+<sym2>: etc. for multiple keys. For example,\n" +" if the viewing machine has a mouse-wheel (buttons 4 5)\n" +" but the x11vnc side does not, these will do scrolls:\n" +" -buttonmap 12345-123:Prior::Next:\n" +" -buttonmap 12345-123:Up+Up+Up::Down+Down+Down:\n" +"\n" +" If you include a modifier like \"Shift_L\" the modifier's\n" +" up/down state is toggled, e.g. to send \"The\" use\n" +" :Shift_L+t+Shift_L+h+e: (the 1st one is shift down and\n" +" the 2nd one is shift up. (note: the initial state of\n" +" the modifier is ignored and not reset)\n" +" To include button events use \"Button1\", ... etc.\n" +"\n" "-nodragging Do not update the display during mouse dragging events\n" " (mouse motion with a button held down). Greatly\n" " improves response on slow setups, but you lose all\n" @@ -4994,6 +5222,7 @@ void print_help() { " than f, the whole screen is updated (default %.2f).\n" "-onetile Do not use the new copy_tiles() framebuffer mechanism,\n" " just use 1 shm tile for polling. Same as -old_copytile.\n" +" Limits shm segments used to 3.\n" "-gaps n Heuristic to fill in gaps in rows or cols of n or less\n" " tiles. Used to improve text paging (default %d).\n" "-grow n Heuristic to grow islands of changed tiles n or wider\n" @@ -5038,6 +5267,17 @@ void print_help() { * choose a desktop name */ #define MAXN 256 + +char *this_host() { + char host[MAXN]; +#ifdef LIBVNCSERVER_HAVE_GETHOSTNAME + if (gethostname(host, MAXN) == 0) { + return strdup(host); + } +#endif + return NULL; +} + char *choose_title(char *display) { static char title[(MAXN+10)]; strcpy(title, "x11vnc"); @@ -5051,11 +5291,9 @@ char *choose_title(char *display) { title[0] = '\0'; if (display[0] == ':') { char host[MAXN]; -#ifdef LIBVNCSERVER_HAVE_GETHOSTNAME - if (gethostname(host, MAXN) == 0) { - strncpy(title, host, MAXN - strlen(title)); + if (this_host() != NULL) { + strncpy(title, this_host(), MAXN - strlen(title)); } -#endif } strncat(title, display, MAXN - strlen(title)); if (subwin) { @@ -5068,6 +5306,31 @@ char *choose_title(char *display) { return title; } +/* + * check blacklist for OSs with tight shm limits. + */ +int limit_shm(void) { + struct utsname ut; + int limit = 0; + + if (uname(&ut) == -1) { + return 0; + } + if (!strcmp(ut.sysname, "SunOS")) { + char *r = ut.release; + if (*r == '5' && *(r+1) == '.') { + if (strchr("2345678", *(r+2)) != NULL) { + limit = 1; + } + } + } + if (limit) { + fprintf(stderr, "reducing shm usage on %s %s (adding " + "-onetile)\n", ut.sysname, ut.release); + } + return limit; +} + int main(int argc, char** argv) { XImage *fb; @@ -5078,7 +5341,7 @@ int main(int argc, char** argv) { int pw_loc = -1; int dt = 0; int bg = 0; - int got_waitms = 0, got_rfbwait = 0; + int got_rfbwait = 0; int got_deferupdate = 0, got_defer = 0; /* used to pass args we do not know about to rfbGetScreen(): */ @@ -5191,7 +5454,6 @@ int main(int argc, char** argv) { got_defer = 1; } else if (!strcmp(arg, "-wait")) { waitms = atoi(argv[++i]); - got_waitms = 1; } else if (!strcmp(arg, "-nap")) { take_naps = 1; #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD @@ -5295,10 +5557,6 @@ int main(int argc, char** argv) { if (waitms < 0) { waitms = 0; } - if (! using_shm && ! got_waitms) { - /* try to cut down on polling over network... */ - waitms *= 2; - } if (inetd) { shared = 0; connect_once = 1; @@ -5311,6 +5569,13 @@ int main(int argc, char** argv) { argv2[argc2++] = "604800000"; /* one week... */ } + /* check for OS with small shm limits */ + if (using_shm && ! single_copytile) { + if (limit_shm()) { + single_copytile = 1; + } + } + if (nofb && ! got_deferupdate && ! got_defer) { /* reduce defer time under -nofb */ defer_update = defer_update_nofb; @@ -5322,6 +5587,14 @@ int main(int argc, char** argv) { argv2[argc2++] = "-deferupdate"; argv2[argc2++] = strdup(tmp); } + if (debug_pointer || debug_keyboard) { + if (bg || quiet) { + fprintf(stderr, "disabling -bg/-q under -debug_pointer" + "/-debug_keyboard\n"); + bg = 0; + quiet = 0; + } + } if (! quiet) { fprintf(stderr, "\n"); @@ -5381,6 +5654,7 @@ int main(int argc, char** argv) { fprintf(stderr, "tile_fuzz: %d\n", tile_fuzz); fprintf(stderr, "use_hints: %d\n", use_hints); fprintf(stderr, "bg: %d\n", bg); + fprintf(stderr, "%s\n", lastmod); } else { rfbLogEnable(0); } @@ -5589,14 +5863,48 @@ int main(int argc, char** argv) { if (remap_file != NULL) { initialize_remap(remap_file); } + initialize_pointer_map(); - if (screen->rfbPort) { - fprintf(stdout, "PORT=%d\n", screen->rfbPort); - fflush(stdout); + if (! inetd) { + if (! screen->rfbPort || screen->rfbListenSock < 0) { + rfbLog("Error: could not obtain listening port.\n"); + clean_up_exit(1); + } } if (! quiet) { rfbLog("screen setup finished.\n"); } + if (screen->rfbPort) { + char *host = this_host(); + int port = screen->rfbPort; + if (host != NULL) { + /* note that vncviewer special cases 5900-5999 */ + if (quiet) { + if (port >= 5900) { + fprintf(stderr, "The VNC desktop is " + "%s:%d\n", host, port - 5900); + } else { + fprintf(stderr, "The VNC desktop is " + "%s:%d\n", host, port); + } + } else if (port >= 5900) { + rfbLog("The VNC desktop is %s:%d\n", host, + port - 5900); + if (port >= 6000) { + rfbLog("possible aliases: %s:%d, " + "%s::%d\n", host, port, host, port); + } + } else { + rfbLog("The VNC desktop is %s:%d\n", host, + port); + rfbLog("possible alias: %s::%d\n", + host, port); + } + } + fflush(stderr); + fprintf(stdout, "PORT=%d\n", screen->rfbPort); + fflush(stdout); + } #if defined(LIBVNCSERVER_HAVE_FORK) && defined(LIBVNCSERVER_HAVE_SETSID) if (bg) { |