summaryrefslogtreecommitdiffstats
path: root/x11vnc/keyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/keyboard.c')
-rw-r--r--x11vnc/keyboard.c3418
1 files changed, 0 insertions, 3418 deletions
diff --git a/x11vnc/keyboard.c b/x11vnc/keyboard.c
deleted file mode 100644
index 54ff70e..0000000
--- a/x11vnc/keyboard.c
+++ /dev/null
@@ -1,3418 +0,0 @@
-/*
- Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
- All rights reserved.
-
-This file is part of x11vnc.
-
-x11vnc is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or (at
-your option) any later version.
-
-x11vnc is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with x11vnc; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
-or see <http://www.gnu.org/licenses/>.
-
-In addition, as a special exception, Karl J. Runge
-gives permission to link the code of its release of x11vnc with the
-OpenSSL project's "OpenSSL" library (or with modified versions of it
-that use the same license as the "OpenSSL" library), and distribute
-the linked executables. You must obey the GNU General Public License
-in all respects for all of the code used other than "OpenSSL". If you
-modify this file, you may extend this exception to your version of the
-file, but you are not obligated to do so. If you do not wish to do
-so, delete this exception statement from your version.
-*/
-
-/* -- keyboard.c -- */
-
-#include "x11vnc.h"
-#include "xwrappers.h"
-#include "xrecord.h"
-#include "xinerama.h"
-#include "pointer.h"
-#include "userinput.h"
-#include "win_utils.h"
-#include "rates.h"
-#include "cleanup.h"
-#include "allowed_input_t.h"
-#include "unixpw.h"
-#include "v4l.h"
-#include "linuxfb.h"
-#include "uinput.h"
-#include "macosx.h"
-#include "screen.h"
-
-void get_keystate(int *keystate);
-void clear_modifiers(int init);
-int track_mod_state(rfbKeySym keysym, rfbBool down, rfbBool set);
-void clear_keys(void);
-void clear_locks(void);
-int get_autorepeat_state(void);
-int get_initial_autorepeat_state(void);
-void autorepeat(int restore, int bequiet);
-void check_add_keysyms(void);
-int add_keysym(KeySym keysym);
-void delete_added_keycodes(int bequiet);
-void initialize_remap(char *infile);
-int sloppy_key_check(int key, rfbBool down, rfbKeySym keysym, int *new_kc);
-void switch_to_xkb_if_better(void);
-char *short_kmbcf(char *str);
-void initialize_allowed_input(void);
-void initialize_modtweak(void);
-void initialize_keyboard_and_pointer(void);
-void get_allowed_input(rfbClientPtr client, allowed_input_t *input);
-double typing_rate(double time_window, int *repeating);
-int skip_cr_when_scaling(char *mode);
-void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
-
-
-static void delete_keycode(KeyCode kc, int bequiet);
-static int count_added_keycodes(void);
-static void add_remap(char *line);
-static void add_dead_keysyms(char *str);
-static void initialize_xkb_modtweak(void);
-static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
- rfbClientPtr client);
-static void tweak_mod(signed char mod, rfbBool down);
-static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
- rfbClientPtr client);
-static void pipe_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
-
-
-/*
- * Routine to retreive current state keyboard. 1 means down, 0 up.
- */
-void get_keystate(int *keystate) {
-#if NO_X11
- RAWFB_RET_VOID
- if (!keystate) {}
- return;
-#else
- int i, k;
- char keys[32];
-
- RAWFB_RET_VOID
-
- /* n.b. caller decides to X_LOCK or not. */
- XQueryKeymap(dpy, keys);
- for (i=0; i<32; i++) {
- char c = keys[i];
-
- for (k=0; k < 8; k++) {
- if (c & 0x1) {
- keystate[8*i + k] = 1;
- } else {
- keystate[8*i + k] = 0;
- }
- c = c >> 1;
- }
- }
-#endif /* NO_X11 */
-}
-
-/*
- * Try to KeyRelease any non-Lock modifiers that are down.
- */
-void clear_modifiers(int init) {
-#if NO_X11
- RAWFB_RET_VOID
- if (!init) {}
- return;
-#else
- static KeyCode keycodes[256];
- static KeySym keysyms[256];
- static char *keystrs[256];
- static int kcount = 0, first = 1;
- int keystate[256];
- int i, j, minkey, maxkey, syms_per_keycode;
- KeySym *keymap;
- KeySym keysym;
- KeyCode keycode;
-
- RAWFB_RET_VOID
-
- /* n.b. caller decides to X_LOCK or not. */
- if (first) {
- /*
- * we store results in static arrays, to aid interrupted
- * case, but modifiers could have changed during session...
- */
- 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++) {
- char *str;
- keysym = keymap[ (i - minkey) * syms_per_keycode + j ];
- if (keysym == NoSymbol || ! ismodkey(keysym)) {
- continue;
- }
- keycode = XKeysymToKeycode(dpy, keysym);
- if (keycode == NoSymbol) {
- continue;
- }
- keycodes[kcount] = keycode;
- keysyms[kcount] = keysym;
- str = XKeysymToString(keysym);
- if (! str) str = "null";
- keystrs[kcount] = strdup(str);
- kcount++;
- }
- }
- XFree_wr((void *) keymap);
- first = 0;
- }
- if (init) {
- return;
- }
-
- get_keystate(keystate);
- for (i=0; i < kcount; i++) {
- keysym = keysyms[i];
- keycode = keycodes[i];
-
- if (! keystate[(int) keycode]) {
- continue;
- }
-
- if (clear_mods) {
- rfbLog("clear_modifiers: up: %-10s (0x%x) "
- "keycode=0x%x\n", keystrs[i], keysym, keycode);
- }
- XTestFakeKeyEvent_wr(dpy, keycode, False, CurrentTime);
- }
- XFlush_wr(dpy);
-#endif /* NO_X11 */
-}
-
-static KeySym simple_mods[] = {
- XK_Shift_L, XK_Shift_R,
- XK_Control_L, XK_Control_R,
- XK_Meta_L, XK_Meta_R,
- XK_Alt_L, XK_Alt_R,
- XK_Super_L, XK_Super_R,
- XK_Hyper_L, XK_Hyper_R,
- XK_Mode_switch,
- NoSymbol
-};
-#define NSIMPLE_MODS 13
-
-int track_mod_state(rfbKeySym keysym, rfbBool down, rfbBool set) {
- KeySym sym = (KeySym) keysym;
- static rfbBool isdown[NSIMPLE_MODS];
- static int first = 1;
- int i, cnt = 0;
-
- /*
- * simple tracking method for the modifier state without
- * contacting the Xserver. Ignores, of course what keys are
- * pressed on the physical display.
- *
- * This is unrelated to our mod_tweak and xkb stuff.
- * Just a simple thing for wireframe/scroll heuristics,
- * sloppy keys etc.
- */
-
- if (first) {
- for (i=0; i<NSIMPLE_MODS; i++) {
- isdown[i] = FALSE;
- }
- first = 0;
- }
-
- if (sym != NoSymbol) {
- for (i=0; i<NSIMPLE_MODS; i++) {
- if (sym == simple_mods[i]) {
- if (set) {
- isdown[i] = down;
- return 1;
- } else {
- if (isdown[i]) {
- return 1;
- } else {
- return 0;
- }
- }
- break;
- }
- }
- /* not a modifier */
- if (set) {
- return 0;
- } else {
- return -1;
- }
- }
-
- /* called with NoSymbol: return number currently pressed: */
- for (i=0; i<NSIMPLE_MODS; i++) {
- if (isdown[i]) {
- cnt++;
- }
- }
- return cnt;
-}
-
-/*
- * Attempt to set all keys to Up position. Can mess up typing at the
- * physical keyboard so use with caution.
- */
-void clear_keys(void) {
- int k, keystate[256];
-
- RAWFB_RET_VOID
-
- /* n.b. caller decides to X_LOCK or not. */
- get_keystate(keystate);
- for (k=0; k<256; k++) {
- if (keystate[k]) {
- KeyCode keycode = (KeyCode) k;
- rfbLog("clear_keys: keycode=%d\n", keycode);
- XTestFakeKeyEvent_wr(dpy, keycode, False, CurrentTime);
- }
- }
- XFlush_wr(dpy);
-}
-
-
-void clear_locks(void) {
-#if NO_X11
- RAWFB_RET_VOID
- return;
-#else
- XModifierKeymap *map;
- int i, j, k = 0;
- unsigned int state = 0;
-
- RAWFB_RET_VOID
-
- /* n.b. caller decides to X_LOCK or not. */
-#if LIBVNCSERVER_HAVE_XKEYBOARD
- if (xkb_present) {
- XkbStateRec kbstate;
- XkbGetState(dpy, XkbUseCoreKbd, &kbstate);
- rfbLog("locked: 0x%x\n", kbstate.locked_mods);
- rfbLog("latched: 0x%x\n", kbstate.latched_mods);
- rfbLog("compat: 0x%x\n", kbstate.compat_state);
- state = kbstate.locked_mods;
- if (! state) {
- state = kbstate.compat_state;
- }
- } else
-#endif
- {
- state = mask_state();
- /* this may contain non-locks too... */
- rfbLog("state: 0x%x\n", state);
- }
- if (! state) {
- return;
- }
- map = XGetModifierMapping(dpy);
- if (! map) {
- return;
- }
- for (i = 0; i < 8; i++) {
- int did = 0;
- for (j = 0; j < map->max_keypermod; j++) {
- if (! did && state & (0x1 << i)) {
- if (map->modifiermap[k]) {
- KeyCode key = map->modifiermap[k];
- KeySym ks = XKeycodeToKeysym(dpy, key, 0);
- char *nm = XKeysymToString(ks);
- rfbLog("toggling: %03d / %03d -- %s\n", key, ks, nm ? nm : "BadKey");
- did = 1;
- XTestFakeKeyEvent_wr(dpy, key, True, CurrentTime);
- usleep(10*1000);
- XTestFakeKeyEvent_wr(dpy, key, False, CurrentTime);
- XFlush_wr(dpy);
- }
- }
- k++;
- }
- }
- XFreeModifiermap(map);
- XFlush_wr(dpy);
- rfbLog("state: 0x%x\n", mask_state());
-#endif
-}
-
-/*
- * Kludge for -norepeat option: we turn off keystroke autorepeat in
- * the X server when clients are connected. This may annoy people at
- * the physical display. We do this because 'key down' and 'key up'
- * user input events may be separated by 100s of ms due to screen fb
- * processing or link latency, thereby inducing the X server to apply
- * autorepeat when it should not. Since the *client* is likely doing
- * keystroke autorepeating as well, it kind of makes sense to shut it
- * off if no one is at the physical display...
- */
-static int save_auto_repeat = -1;
-
-int get_autorepeat_state(void) {
-#if NO_X11
- RAWFB_RET(0)
- return 0;
-#else
- XKeyboardState kstate;
-
- RAWFB_RET(0)
-
- X_LOCK;
- XGetKeyboardControl(dpy, &kstate);
- X_UNLOCK;
- return kstate.global_auto_repeat;
-#endif /* NO_X11 */
-}
-
-int get_initial_autorepeat_state(void) {
- if (save_auto_repeat < 0) {
- save_auto_repeat = get_autorepeat_state();
- }
- return save_auto_repeat;
-}
-
-void autorepeat(int restore, int bequiet) {
-#if NO_X11
- RAWFB_RET_VOID
- if (!restore || !bequiet) {}
- return;
-#else
- int global_auto_repeat;
- XKeyboardControl kctrl;
-
- RAWFB_RET_VOID
-
- if (restore) {
- if (save_auto_repeat < 0) {
- return; /* nothing to restore */
- }
- global_auto_repeat = get_autorepeat_state();
- /* read state and skip restore if equal (e.g. no clients) */
- if (global_auto_repeat == save_auto_repeat) {
- return;
- }
-
- X_LOCK;
- kctrl.auto_repeat_mode = save_auto_repeat;
- XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl);
- XFlush_wr(dpy);
- X_UNLOCK;
-
- if (! bequiet && ! quiet) {
- rfbLog("Restored X server key autorepeat to: %d\n",
- save_auto_repeat);
- }
- } else {
- global_auto_repeat = get_autorepeat_state();
- if (save_auto_repeat < 0) {
- /*
- * we only remember the state at startup
- * to avoid confusing ourselves later on.
- */
- save_auto_repeat = global_auto_repeat;
- }
-
- X_LOCK;
- kctrl.auto_repeat_mode = AutoRepeatModeOff;
- XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kctrl);
- XFlush_wr(dpy);
- X_UNLOCK;
-
- if (! bequiet && ! quiet) {
- rfbLog("Disabled X server key autorepeat.\n");
- if (no_repeat_countdown >= 0) {
- rfbLog(" to force back on run: 'xset r on' (%d "
- "times)\n", no_repeat_countdown+1);
- }
- }
- }
-#endif /* NO_X11 */
-}
-
-/*
- * We periodically delete any keysyms we have added, this is to
- * lessen our effect on the X server state if we are terminated abruptly
- * and cannot clear them and also to clear out any strange little used
- * ones that would just fill up the keymapping.
- */
-void check_add_keysyms(void) {
- static time_t last_check = 0;
- int clear_freq = 300, quiet = 1, count;
- time_t now = time(NULL);
-
- if (unixpw_in_progress) return;
-
- if (now > last_check + clear_freq) {
- count = count_added_keycodes();
- /*
- * only really delete if they have not typed recently
- * and we have added 8 or more.
- */
- if (now > last_keyboard_input + 5 && count >= 8) {
- X_LOCK;
- delete_added_keycodes(quiet);
- X_UNLOCK;
- }
- last_check = now;
- }
-}
-
-static KeySym added_keysyms[0x100];
-
-/* these are just for rfbLog messages: */
-static KeySym alltime_added_keysyms[1024];
-static int alltime_len = 1024;
-static int alltime_num = 0;
-
-int add_keysym(KeySym keysym) {
- static int first = 1;
- int n;
-#if NO_X11
- if (first) {
- for (n=0; n < 0x100; n++) {
- added_keysyms[n] = NoSymbol;
- }
- first = 0;
- }
- RAWFB_RET(0)
- if (!keysym) {}
- return 0;
-#else
- int minkey, maxkey, syms_per_keycode;
- int kc, ret = 0;
- KeySym *keymap;
-
- if (first) {
- for (n=0; n < 0x100; n++) {
- added_keysyms[n] = NoSymbol;
- }
- first = 0;
- }
-
- RAWFB_RET(0)
-
- if (keysym == NoSymbol) {
- return 0;
- }
- /* there can be a race before MappingNotify */
- for (n=0; n < 0x100; n++) {
- if (added_keysyms[n] == keysym) {
- return n;
- }
- }
-
- XDisplayKeycodes(dpy, &minkey, &maxkey);
- keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
- &syms_per_keycode);
-
- for (kc = minkey+1; kc <= maxkey; kc++) {
- int i, j, didmsg = 0, is_empty = 1;
- char *str;
- KeySym newks[8];
-
- for (n=0; n < syms_per_keycode; n++) {
- if (keymap[ (kc-minkey) * syms_per_keycode + n]
- != NoSymbol) {
- is_empty = 0;
- break;
- }
- }
- if (! is_empty) {
- continue;
- }
-
- for (i=0; i<8; i++) {
- newks[i] = NoSymbol;
- }
- if (add_keysyms == 2) {
- newks[0] = keysym; /* XXX remove me */
- } else {
- for(i=0; i < syms_per_keycode; i++) {
- newks[i] = keysym;
- if (i >= 7) break;
- }
- }
-
- XChangeKeyboardMapping(dpy, kc, syms_per_keycode,
- newks, 1);
-
- if (alltime_num >= alltime_len) {
- didmsg = 1; /* something weird */
- } else {
- for (j=0; j<alltime_num; j++) {
- if (alltime_added_keysyms[j] == keysym) {
- didmsg = 1;
- break;
- }
- }
- }
- if (! didmsg) {
- str = XKeysymToString(keysym);
- rfbLog("added missing keysym to X display: %03d "
- "0x%x \"%s\"\n", kc, keysym, str ? str : "null");
-
- if (alltime_num < alltime_len) {
- alltime_added_keysyms[alltime_num++] = keysym;
- }
- }
-
- XFlush_wr(dpy);
- added_keysyms[kc] = keysym;
- ret = kc;
- break;
- }
- XFree_wr(keymap);
- return ret;
-#endif /* NO_X11 */
-}
-
-static void delete_keycode(KeyCode kc, int bequiet) {
-#if NO_X11
- RAWFB_RET_VOID
- if (!kc || !bequiet) {}
- return;
-#else
- int minkey, maxkey, syms_per_keycode, i;
- KeySym *keymap;
- KeySym ksym, newks[8];
- char *str;
-
- RAWFB_RET_VOID
-
- XDisplayKeycodes(dpy, &minkey, &maxkey);
- keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
- &syms_per_keycode);
-
- for (i=0; i<8; i++) {
- newks[i] = NoSymbol;
- }
-
- XChangeKeyboardMapping(dpy, kc, syms_per_keycode, newks, 1);
-
- if (! bequiet && ! quiet) {
- ksym = XKeycodeToKeysym(dpy, kc, 0);
- str = XKeysymToString(ksym);
- rfbLog("deleted keycode from X display: %03d 0x%x \"%s\"\n",
- kc, ksym, str ? str : "null");
- }
-
- XFree_wr(keymap);
- XFlush_wr(dpy);
-#endif /* NO_X11 */
-}
-
-static int count_added_keycodes(void) {
- int kc, count = 0;
- for (kc = 0; kc < 0x100; kc++) {
- if (added_keysyms[kc] != NoSymbol) {
- count++;
- }
- }
- return count;
-}
-
-void delete_added_keycodes(int bequiet) {
- int kc;
- for (kc = 0; kc < 0x100; kc++) {
- if (added_keysyms[kc] != NoSymbol) {
- delete_keycode(kc, bequiet);
- added_keysyms[kc] = NoSymbol;
- }
- }
-}
-
-/*
- * The following is for an experimental -remap option to allow the user
- * to remap keystrokes. It is currently confusing wrt modifiers...
- */
-typedef struct keyremap {
- KeySym before;
- KeySym after;
- int isbutton;
- struct keyremap *next;
-} keyremap_t;
-
-static keyremap_t *keyremaps = NULL;
-
-static void add_remap(char *line) {
- char str1[256], str2[256];
- KeySym ksym1, ksym2;
- int isbtn = 0;
- unsigned int i;
- static keyremap_t *current = NULL;
- keyremap_t *remap;
-
- if (sscanf(line, "%s %s", str1, str2) != 2) {
- rfbLogEnable(1);
- rfbLog("remap: invalid line: %s\n", line);
- clean_up_exit(1);
- }
- if (sscanf(str1, "0x%x", &i) == 1) {
- ksym1 = (KeySym) i;
- } else {
- ksym1 = XStringToKeysym(str1);
- }
- if (sscanf(str2, "0x%x", &i) == 1) {
- ksym2 = (KeySym) i;
- } else {
- ksym2 = XStringToKeysym(str2);
- }
- if (ksym2 == NoSymbol) {
- if (sscanf(str2, "Button%u", &i) == 1) {
- ksym2 = (KeySym) i;
- isbtn = 1;
- }
- }
- if (ksym1 == NoSymbol || ksym2 == NoSymbol) {
- if (strcasecmp(str2, "NoSymbol") && strcasecmp(str2, "None")) {
- rfbLog("warning: skipping invalid remap line: %s", line);
- return;
- }
- }
- 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) isbtn=%d\n", str1,
- ksym1, str2, ksym2, isbtn);
-
- if (keyremaps == NULL) {
- keyremaps = remap;
- } else {
- current->next = remap;
- }
- current = remap;
-}
-
-static void add_dead_keysyms(char *str) {
- char *p, *q;
- int i;
- char *list[] = {
- "g grave dead_grave",
- "a acute dead_acute",
- "c asciicircum dead_circumflex",
- "t asciitilde dead_tilde",
- "m macron dead_macron",
- "b breve dead_breve",
- "D abovedot dead_abovedot",
- "d diaeresis dead_diaeresis",
- "o degree dead_abovering",
- "A doubleacute dead_doubleacute",
- "r caron dead_caron",
- "e cedilla dead_cedilla",
-/* "x XXX-ogonek dead_ogonek", */
-/* "x XXX-belowdot dead_belowdot", */
-/* "x XXX-hook dead_hook", */
-/* "x XXX-horn dead_horn", */
- NULL
- };
-
- p = str;
-
- while (*p != '\0') {
- if (isspace((unsigned char) (*p))) {
- *p = '\0';
- }
- p++;
- }
-
- if (!strcmp(str, "DEAD")) {
- for (i = 0; list[i] != NULL; i++) {
- p = list[i] + 2;
- add_remap(p);
- }
- } else if (!strcmp(str, "DEAD=missing")) {
- for (i = 0; list[i] != NULL; i++) {
- KeySym ksym, ksym2;
- int inmap = 0;
-
- p = strdup(list[i] + 2);
- q = strchr(p, ' ');
- if (q == NULL) {
- free(p);
- continue;
- }
- *q = '\0';
- ksym = XStringToKeysym(p);
- *q = ' ';
- if (ksym == NoSymbol) {
- free(p);
- continue;
- }
- if (XKeysymToKeycode(dpy, ksym)) {
- inmap = 1;
- }
-#if LIBVNCSERVER_HAVE_XKEYBOARD
- if (! inmap && xkb_present && dpy) {
- int kc, grp, lvl;
- for (kc = 0; kc < 0x100; kc++) {
- for (grp = 0; grp < 4; grp++) {
- for (lvl = 0; lvl < 8; lvl++) {
- ksym2 = XkbKeycodeToKeysym(dpy,
- kc, grp, lvl);
- if (ksym2 == NoSymbol) {
- continue;
- }
- if (ksym2 == ksym) {
- inmap = 1;
- break;
- }
- }
- }
- }
- }
-#else
- if ((ksym2 = 0)) {}
-#endif
- if (! inmap) {
- add_remap(p);
- }
- free(p);
- }
- } else if ((p = strchr(str, '=')) != NULL) {
- while (*p != '\0') {
- for (i = 0; list[i] != NULL; i++) {
- q = list[i];
- if (*p == *q) {
- q += 2;
- add_remap(q);
- break;
- }
- }
- p++;
- }
- }
-}
-
-/*
- * process the -remap string (file or mapping string)
- */
-void initialize_remap(char *infile) {
- FILE *in;
- char *p, *q, line[256];
-
- if (keyremaps != NULL) {
- /* free last remapping */
- keyremap_t *next_remap, *curr_remap = keyremaps;
- while (curr_remap != NULL) {
- next_remap = curr_remap->next;
- free(curr_remap);
- curr_remap = next_remap;
- }
- keyremaps = NULL;
- }
- if (infile == NULL || *infile == '\0') {
- /* just unset remapping */
- return;
- }
-
- in = fopen(infile, "r");
- if (in == NULL) {
- /* assume cmd line key1-key2,key3-key4 */
- if (strstr(infile, "DEAD") == infile) {
- ;
- } else if (!strchr(infile, '-')) {
- rfbLogEnable(1);
- rfbLog("remap: cannot open: %s\n", infile);
- rfbLogPerror("fopen");
- clean_up_exit(1);
- }
- if ((in = tmpfile()) == NULL) {
- rfbLogEnable(1);
- rfbLog("remap: cannot open tmpfile for %s\n", infile);
- rfbLogPerror("tmpfile");
- clean_up_exit(1);
- }
-
- /* copy in the string to file format */
- p = infile;
- while (*p) {
- if (*p == '-') {
- fprintf(in, " ");
- } else if (*p == ',' || *p == ' ' || *p == '\t') {
- fprintf(in, "\n");
- } else {
- fprintf(in, "%c", *p);
- }
- p++;
- }
- fprintf(in, "\n");
- fflush(in);
- rewind(in);
- }
-
- while (fgets(line, 256, in) != NULL) {
- p = lblanks(line);
- if (*p == '\0') {
- continue;
- }
- if (strchr(line, '#')) {
- continue;
- }
-
- if (strstr(p, "DEAD") == p) {
- add_dead_keysyms(p);
- continue;
- }
- if ((q = strchr(line, '-')) != NULL) {
- /* allow Keysym1-Keysym2 notation */
- *q = ' ';
- }
- add_remap(p);
- }
- fclose(in);
-}
-
-/*
- * preliminary support for using the Xkb (XKEYBOARD) extension for handling
- * user input. inelegant, slow, and incomplete currently... but initial
- * tests show it is useful for some setups.
- */
-typedef struct keychar {
- KeyCode code;
- int group;
- int level;
-} keychar_t;
-
-/* max number of key groups and shift levels we consider */
-#define GRP 4
-#define LVL 8
-static int lvl_max, grp_max, kc_min, kc_max;
-static KeySym xkbkeysyms[0x100][GRP][LVL];
-static unsigned int xkbstate[0x100][GRP][LVL];
-static unsigned int xkbignore[0x100][GRP][LVL];
-static unsigned int xkbmodifiers[0x100][GRP][LVL];
-static int multi_key[0x100], mode_switch[0x100], skipkeycode[0x100];
-static int shift_keys[0x100];
-
-/*
- * for trying to order the keycodes to avoid problems, note the
- * *first* keycode bound to it. kc_vec will be a permutation
- * of 1...256 to get them in the preferred order.
- */
-static int kc_vec[0x100];
-static int kc1_shift, kc1_control, kc1_caplock, kc1_alt;
-static int kc1_meta, kc1_numlock, kc1_super, kc1_hyper;
-static int kc1_mode_switch, kc1_iso_level3_shift, kc1_multi_key;
-
-int sloppy_key_check(int key, rfbBool down, rfbKeySym keysym, int *new_kc) {
- if (!sloppy_keys) {
- return 0;
- }
-
- RAWFB_RET(0)
-#if NO_X11
- if (!key || !down || !keysym || !new_kc) {}
- return 0;
-#else
-
- if (!down && !keycode_state[key] && !IsModifierKey(keysym)) {
- int i, cnt = 0, downkey = -1;
- int nmods_down = track_mod_state(NoSymbol, FALSE, FALSE);
- int mods_down[256];
-
- if (nmods_down) {
- /* tracking to skip down modifier keycodes. */
- for(i=0; i<256; i++) {
- mods_down[i] = 0;
- }
- i = 0;
- while (simple_mods[i] != NoSymbol) {
- KeySym ksym = simple_mods[i];
- KeyCode k = XKeysymToKeycode(dpy, ksym);
- if (k != NoSymbol && keycode_state[(int) k]) {
- mods_down[(int) k] = 1;
- }
-
- i++;
- }
- }
- /*
- * the keycode is already up... look for a single one
- * (non modifier) that is down
- */
- for (i=0; i<256; i++) {
- if (keycode_state[i]) {
- if (nmods_down && mods_down[i]) {
- continue;
- }
- cnt++;
- downkey = i;
- }
- }
- if (cnt == 1) {
- if (debug_keyboard) {
- fprintf(stderr, " sloppy_keys: %d/0x%x "
- "-> %d/0x%x (nmods: %d)\n", (int) key,
- (int) key, downkey, downkey, nmods_down);
- }
- *new_kc = downkey;
- return 1;
- }
- }
- return 0;
-#endif /* NO_X11 */
-}
-
-#if !LIBVNCSERVER_HAVE_XKEYBOARD || SKIP_XKB
-
-/* empty functions for no xkb */
-static void initialize_xkb_modtweak(void) {}
-static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
- rfbClientPtr client) {
- if (!client || !down || !keysym) {} /* unused vars warning: */
-}
-void switch_to_xkb_if_better(void) {}
-
-#else
-
-void switch_to_xkb_if_better(void) {
- KeySym keysym, *keymap;
- int miss_noxkb[256], miss_xkb[256], missing_noxkb = 0, missing_xkb = 0;
- int i, j, k, n, minkey, maxkey, syms_per_keycode;
- int syms_gt_4 = 0;
- int kc, grp, lvl;
-
- /* non-alphanumeric on us keyboard */
- KeySym must_have[] = {
- XK_exclam,
- XK_at,
- XK_numbersign,
- XK_dollar,
- XK_percent,
-/* XK_asciicircum, */
- XK_ampersand,
- XK_asterisk,
- XK_parenleft,
- XK_parenright,
- XK_underscore,
- XK_plus,
- XK_minus,
- XK_equal,
- XK_bracketleft,
- XK_bracketright,
- XK_braceleft,
- XK_braceright,
- XK_bar,
- XK_backslash,
- XK_semicolon,
-/* XK_apostrophe, */
- XK_colon,
- XK_quotedbl,
- XK_comma,
- XK_period,
- XK_less,
- XK_greater,
- XK_slash,
- XK_question,
-/* XK_asciitilde, */
-/* XK_grave, */
- NoSymbol
- };
-
- if (! use_modifier_tweak || got_noxkb) {
- return;
- }
- if (use_xkb_modtweak) {
- /* already using it */
- return;
- }
- RAWFB_RET_VOID
-
- XDisplayKeycodes(dpy, &minkey, &maxkey);
-
- keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
- &syms_per_keycode);
-
- /* handle alphabetic char with only one keysym (no upper + lower) */
- for (i = minkey; i <= maxkey; i++) {
- KeySym lower, upper;
- /* 2nd one */
- keysym = keymap[(i - minkey) * syms_per_keycode + 1];
- if (keysym != NoSymbol) {
- continue;
- }
- /* 1st one */
- keysym = keymap[(i - minkey) * syms_per_keycode + 0];
- if (keysym == NoSymbol) {
- continue;
- }
- XConvertCase(keysym, &lower, &upper);
- if (lower != upper) {
- keymap[(i - minkey) * syms_per_keycode + 0] = lower;
- keymap[(i - minkey) * syms_per_keycode + 1] = upper;
- }
- }
-
- k = 0;
- while (must_have[k] != NoSymbol) {
- int gotit = 0;
- KeySym must = must_have[k];
- for (i = minkey; i <= maxkey; i++) {
- for (j = 0; j < syms_per_keycode; j++) {
- keysym = keymap[(i-minkey) * syms_per_keycode + j];
- if (j >= 4) {
- if (k == 0 && keysym != NoSymbol) {
- /* for k=0 count the high keysyms */
- syms_gt_4++;
- if (debug_keyboard > 1) {
- char *str = XKeysymToString(keysym);
- fprintf(stderr, "- high keysym mapping"
- ": at %3d j=%d "
- "'%s'\n", i, j, str ? str : "null");
- }
- }
- continue;
- }
- if (keysym == must) {
- if (debug_keyboard > 1) {
- char *str = XKeysymToString(must);
- fprintf(stderr, "- at %3d j=%d found "
- "'%s'\n", i, j, str ? str : "null");
- }
- /* n.b. do not break, see syms_gt_4 above. */
- gotit = 1;
- }
- }
- }
- if (! gotit) {
- if (debug_keyboard > 1) {
- char *str = XKeysymToString(must);
- KeyCode kc = XKeysymToKeycode(dpy, must);
- fprintf(stderr, "- did not find 0x%lx '%s'\t"
- "Ks2Kc: %d\n", must, str ? str:"null", kc);
- if (kc != None) {
- int j2;
- for(j2=0; j2<syms_per_keycode; j2++) {
- keysym = keymap[(kc-minkey) *
- syms_per_keycode + j2];
- fprintf(stderr, " %d=0x%lx",
- j2, keysym);
- }
- fprintf(stderr, "\n");
- }
- }
- missing_noxkb++;
- miss_noxkb[k] = 1;
- } else {
- miss_noxkb[k] = 0;
- }
- k++;
- }
- n = k;
-
- XFree_wr(keymap);
- if (missing_noxkb == 0 && syms_per_keycode > 4 && syms_gt_4 >= 0) {
- /* we used to have syms_gt_4 >= 8, now always on. */
- if (! raw_fb_str) {
- rfbLog("\n");
- rfbLog("XKEYBOARD: number of keysyms per keycode %d is greater\n", syms_per_keycode);
- rfbLog(" than 4 and %d keysyms are mapped above 4.\n", syms_gt_4);
- rfbLog(" Automatically switching to -xkb mode.\n");
- rfbLog(" If this makes the key mapping worse you can\n");
- rfbLog(" disable it with the \"-noxkb\" option.\n");
- rfbLog(" Also, remember \"-remap DEAD\" for accenting characters.\n");
- rfbLog("\n");
- }
-
- use_xkb_modtweak = 1;
- return;
-
- } else if (missing_noxkb == 0) {
- if (! raw_fb_str) {
- rfbLog("\n");
- rfbLog("XKEYBOARD: all %d \"must have\" keysyms accounted for.\n", n);
- rfbLog(" Not automatically switching to -xkb mode.\n");
- rfbLog(" If some keys still cannot be typed, try using -xkb.\n");
- rfbLog(" Also, remember \"-remap DEAD\" for accenting characters.\n");
- rfbLog("\n");
- }
- return;
- }
-
- for (k=0; k<n; k++) {
- miss_xkb[k] = 1;
- }
-
- for (kc = 0; kc < 0x100; kc++) {
- for (grp = 0; grp < GRP; grp++) {
- for (lvl = 0; lvl < LVL; lvl++) {
- /* look up the Keysym, if any */
- keysym = XkbKeycodeToKeysym(dpy, kc, grp, lvl);
- if (keysym == NoSymbol) {
- continue;
- }
- for (k=0; k<n; k++) {
- if (keysym == must_have[k]) {
- miss_xkb[k] = 0;
- }
- }
- }
- }
- }
-
- for (k=0; k<n; k++) {
- if (miss_xkb[k]) {
- missing_xkb++;
- }
- }
-
- rfbLog("\n");
- if (missing_xkb < missing_noxkb) {
- rfbLog("XKEYBOARD:\n");
- rfbLog("Switching to -xkb mode to recover these keysyms:\n");
- } else {
- rfbLog("XKEYBOARD: \"must have\" keysyms better accounted"
- " for\n");
- rfbLog("under -noxkb mode: not switching to -xkb mode:\n");
- }
-
- rfbLog(" xkb noxkb Keysym (\"X\" means present)\n");
- rfbLog(" --- ----- -----------------------------\n");
- for (k=0; k<n; k++) {
- char *xx, *xn, *name;
-
- keysym = must_have[k];
- if (keysym == NoSymbol) {
- continue;
- }
- if (!miss_xkb[k] && !miss_noxkb[k]) {
- continue;
- }
- if (miss_xkb[k]) {
- xx = " ";
- } else {
- xx = " X ";
- }
- if (miss_noxkb[k]) {
- xn = " ";
- } else {
- xn = " X ";
- }
- name = XKeysymToString(keysym);
- rfbLog(" %s %s 0x%lx %s\n", xx, xn, keysym,
- name ? name : "null");
- }
- rfbLog("\n");
-
- if (missing_xkb < missing_noxkb) {
- rfbLog(" If this makes the key mapping worse you can\n");
- rfbLog(" disable it with the \"-noxkb\" option.\n");
- rfbLog("\n");
-
- use_xkb_modtweak = 1;
-
- } else {
- rfbLog(" If some keys still cannot be typed, try using"
- " -xkb.\n");
- rfbLog(" Also, remember \"-remap DEAD\" for accenting"
- " characters.\n");
- }
- rfbLog("\n");
-}
-
-/* sets up all the keymapping info via Xkb API */
-
-static void initialize_xkb_modtweak(void) {
- KeySym ks;
- int kc, grp, lvl, k;
- unsigned int state;
-
-/*
- * Here is a guide:
-
-Workarounds arrays:
-
-multi_key[] indicates which keycodes have Multi_key (Compose)
- bound to them.
-mode_switch[] indicates which keycodes have Mode_switch (AltGr)
- bound to them.
-shift_keys[] indicates which keycodes have Shift bound to them.
-skipkeycode[] indicates which keycodes are to be skipped
- for any lookups from -skip_keycodes option.
-
-Groups and Levels, here is an example:
-
- ^ --------
- | L2 | A AE |
- shift | |
- level L1 | a ae |
- --------
- G1 G2
-
- group ->
-
-Traditionally this it all a key could do. L1 vs. L2 selected via Shift
-and G1 vs. G2 selected via Mode_switch. Up to 4 Keysyms could be bound
-to a key. See initialize_modtweak() for an example of using that type
-of keymap from XGetKeyboardMapping().
-
-Xkb gives us up to 4 groups and 63 shift levels per key, with the
-situation being potentially different for each key. This is complicated,
-and I don't claim to understand it all, but in the following we just think
-of ranging over the group and level indices as covering all of the cases.
-This gives us an accurate view of the keymap. The main tricky part
-is mapping between group+level and modifier state.
-
-On current linux/XFree86 setups (Xkb is enabled by default) the
-information from XGetKeyboardMapping() (evidently the compat map)
-is incomplete and inaccurate, so we are really forced to use the
-Xkb API.
-
-xkbkeysyms[] For a (keycode,group,level) holds the KeySym (0 for none)
-xkbstate[] For a (keycode,group,level) holds the corresponding
- modifier state needed to get that KeySym
-xkbignore[] For a (keycode,group,level) which modifiers can be
- ignored (the 0 bits can be ignored).
-xkbmodifiers[] For the KeySym bound to this (keycode,group,level) store
- the modifier mask.
- *
- */
-
- RAWFB_RET_VOID
-
- /* initialize all the arrays: */
- for (kc = 0; kc < 0x100; kc++) {
- multi_key[kc] = 0;
- mode_switch[kc] = 0;
- skipkeycode[kc] = 0;
- shift_keys[kc] = 0;
-
- for (grp = 0; grp < GRP; grp++) {
- for (lvl = 0; lvl < LVL; lvl++) {
- xkbkeysyms[kc][grp][lvl] = NoSymbol;
- xkbmodifiers[kc][grp][lvl] = -1;
- xkbstate[kc][grp][lvl] = -1;
- }
- }
- }
-
- /*
- * the array is 256*LVL*GRP, but we can make the searched region
- * smaller by computing the actual ranges.
- */
- lvl_max = 0;
- grp_max = 0;
- kc_max = 0;
- kc_min = 0x100;
-
- /* first keycode for a modifier type (multi_key too) */
- kc1_shift = -1;
- kc1_control = -1;
- kc1_caplock = -1;
- kc1_alt = -1;
- kc1_meta = -1;
- kc1_numlock = -1;
- kc1_super = -1;
- kc1_hyper = -1;
- kc1_mode_switch = -1;
- kc1_iso_level3_shift = -1;
- kc1_multi_key = -1;
-
- /*
- * loop over all possible (keycode, group, level) triples
- * and record what we find for it:
- */
- if (debug_keyboard) {
- rfbLog("initialize_xkb_modtweak: XKB keycode -> keysyms "
- "mapping info:\n");
- }
- for (kc = 0; kc < 0x100; kc++) {
- for (grp = 0; grp < GRP; grp++) {
- for (lvl = 0; lvl < LVL; lvl++) {
- unsigned int ms, mods;
- int state_save = -1, mods_save = -1;
- KeySym ks2;
-
- /* look up the Keysym, if any */
- ks = XkbKeycodeToKeysym(dpy, kc, grp, lvl);
- xkbkeysyms[kc][grp][lvl] = ks;
-
- /* if no Keysym, on to next */
- if (ks == NoSymbol) {
- continue;
- }
- /*
- * for various workarounds, note where these special
- * keys are bound to.
- */
- if (ks == XK_Multi_key) {
- multi_key[kc] = lvl+1;
- }
- if (ks == XK_Mode_switch) {
- mode_switch[kc] = lvl+1;
- }
- if (ks == XK_Shift_L || ks == XK_Shift_R) {
- shift_keys[kc] = lvl+1;
- }
-
- if (ks == XK_Shift_L || ks == XK_Shift_R) {
- if (kc1_shift == -1) {
- kc1_shift = kc;
- }
- }
- if (ks == XK_Control_L || ks == XK_Control_R) {
- if (kc1_control == -1) {
- kc1_control = kc;
- }
- }
- if (ks == XK_Caps_Lock || ks == XK_Caps_Lock) {
- if (kc1_caplock == -1) {
- kc1_caplock = kc;
- }
- }
- if (ks == XK_Alt_L || ks == XK_Alt_R) {
- if (kc1_alt == -1) {
- kc1_alt = kc;
- }
- }
- if (ks == XK_Meta_L || ks == XK_Meta_R) {
- if (kc1_meta == -1) {
- kc1_meta = kc;
- }
- }
- if (ks == XK_Num_Lock) {
- if (kc1_numlock == -1) {
- kc1_numlock = kc;
- }
- }
- if (ks == XK_Super_L || ks == XK_Super_R) {
- if (kc1_super == -1) {
- kc1_super = kc;
- }
- }
- if (ks == XK_Hyper_L || ks == XK_Hyper_R) {
- if (kc1_hyper == -1) {
- kc1_hyper = kc;
- }
- }
- if (ks == XK_Mode_switch) {
- if (kc1_mode_switch == -1) {
- kc1_mode_switch = kc;
- }
- }
- if (ks == XK_ISO_Level3_Shift) {
- if (kc1_iso_level3_shift == -1) {
- kc1_iso_level3_shift = kc;
- }
- }
- if (ks == XK_Multi_key) { /* not a modifier.. */
- if (kc1_multi_key == -1) {
- kc1_multi_key = kc;
- }
- }
-
- /*
- * record maximum extent for group/level indices
- * and keycode range:
- */
- if (grp > grp_max) {
- grp_max = grp;
- }
- if (lvl > lvl_max) {
- lvl_max = lvl;
- }
- if (kc > kc_max) {
- kc_max = kc;
- }
- if (kc < kc_min) {
- kc_min = kc;
- }
-
- /*
- * lookup on *keysym* (i.e. not kc, grp, lvl)
- * and get the modifier mask. this is 0 for
- * most keysyms, only non zero for modifiers.
- */
- ms = XkbKeysymToModifiers(dpy, ks);
- xkbmodifiers[kc][grp][lvl] = ms;
-
- /*
- * Amusing heuristic (may have bugs). There are
- * 8 modifier bits, so 256 possible modifier
- * states. We loop over all of them for this
- * keycode (simulating Key "events") and ask
- * XkbLookupKeySym to tell us the Keysym. Once it
- * matches the Keysym we have for this (keycode,
- * group, level), gotten via XkbKeycodeToKeysym()
- * above, we then (hopefully...) know that state
- * of modifiers needed to generate this keysym.
- *
- * Yes... keep your fingers crossed.
- *
- * Note that many of the 256 states give the
- * Keysym, we just need one, and we take the
- * first one found.
- */
- state = 0;
- while(state < 256) {
- if (XkbLookupKeySym(dpy, kc, state, &mods,
- &ks2)) {
-
- /* save these for workaround below */
- if (state_save == -1) {
- state_save = state;
- mods_save = mods;
- }
- if (ks2 == ks) {
- /*
- * zero the irrelevant bits
- * by anding with mods.
- */
- xkbstate[kc][grp][lvl]
- = state & mods;
- /*
- * also remember the irrelevant
- * bits since it is handy.
- */
- xkbignore[kc][grp][lvl] = mods;
-
- break;
- }
- }
- state++;
- }
- if (xkbstate[kc][grp][lvl] == (unsigned int) -1
- && grp == 1) {
- /*
- * Hack on Solaris 9 for Mode_switch
- * for Group2 characters. We force the
- * Mode_switch modifier bit on.
- * XXX Need to figure out better what is
- * happening here. Is compat on somehow??
- */
- unsigned int ms2;
- ms2 = XkbKeysymToModifiers(dpy, XK_Mode_switch);
-
- xkbstate[kc][grp][lvl]
- = (state_save & mods_save) | ms2;
-
- xkbignore[kc][grp][lvl] = mods_save | ms2;
- }
-
- if (debug_keyboard) {
- char *str;
- fprintf(stderr, " %03d G%d L%d mod=%s ",
- kc, grp+1, lvl+1, bitprint(ms, 8));
- fprintf(stderr, "state=%s ",
- bitprint(xkbstate[kc][grp][lvl], 8));
- fprintf(stderr, "ignore=%s ",
- bitprint(xkbignore[kc][grp][lvl], 8));
- str = XKeysymToString(ks);
- fprintf(stderr, " ks=0x%08lx \"%s\"\n",
- ks, str ? str : "null");
- }
- }
- }
- }
-
- /*
- * kc_vec will be used in some places to find modifiers, etc
- * we apply some permutations to it as workarounds.
- */
- for (kc = 0; kc < 0x100; kc++) {
- kc_vec[kc] = kc;
- }
-
- if (kc1_mode_switch != -1 && kc1_iso_level3_shift != -1) {
- if (kc1_mode_switch < kc1_iso_level3_shift) {
- /* we prefer XK_ISO_Level3_Shift: */
- kc_vec[kc1_mode_switch] = kc1_iso_level3_shift;
- kc_vec[kc1_iso_level3_shift] = kc1_mode_switch;
- }
- }
- /* any more? need to watch for undoing the above. */
-
- /*
- * process the user supplied -skip_keycodes string.
- * This is presumably a list if "ghost" keycodes, the X server
- * thinks they exist, but they do not. ghosts can lead to
- * ambiguities in the reverse map: Keysym -> KeyCode + Modstate,
- * so if we can ignore them so much the better. Presumably the
- * user can never generate them from the physical keyboard.
- * There may be other reasons to deaden some keys.
- */
- if (skip_keycodes != NULL) {
- char *p, *str = strdup(skip_keycodes);
- p = strtok(str, ", \t\n\r");
- while (p) {
- k = 1;
- if (sscanf(p, "%d", &k) != 1 || k < 0 || k >= 0x100) {
- rfbLogEnable(1);
- rfbLog("invalid skip_keycodes: %s %s\n",
- skip_keycodes, p);
- clean_up_exit(1);
- }
- skipkeycode[k] = 1;
- p = strtok(NULL, ", \t\n\r");
- }
- free(str);
- }
- if (debug_keyboard) {
- fprintf(stderr, "grp_max=%d lvl_max=%d\n", grp_max, lvl_max);
- }
-}
-
-static short **score_hint = NULL;
-/*
- * Called on user keyboard input. Try to solve the reverse mapping
- * problem: KeySym (from VNC client) => KeyCode(s) to press to generate
- * it. The one-to-many KeySym => KeyCode mapping makes it difficult, as
- * does working out what changes to the modifier keypresses are needed.
- */
-static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
- rfbClientPtr client) {
-
- int kc, grp, lvl, i, kci;
- int kc_f[0x100], grp_f[0x100], lvl_f[0x100], state_f[0x100], found;
- int ignore_f[0x100];
- unsigned int state = 0;
-
-
- /* these are used for finding modifiers, etc */
- XkbStateRec kbstate;
- int got_kbstate = 0;
- int Kc_f, Grp_f = 0, Lvl_f = 0;
-# define KLAST 10
- static int Kc_last_down[KLAST];
- static KeySym Ks_last_down[KLAST];
- static int klast = 0, khints = 1, anydown = 1;
- static int cnt = 0;
-
- if (!client || !down || !keysym) {} /* unused vars warning: */
-
- RAWFB_RET_VOID
-
- X_LOCK;
-
- if (klast == 0) {
- int i, j;
- for (i=0; i<KLAST; i++) {
- Kc_last_down[i] = -1;
- Ks_last_down[i] = NoSymbol;
- }
- if (getenv("NOKEYHINTS")) {
- khints = 0;
- }
- if (getenv("NOANYDOWN")) {
- anydown = 0;
- }
- if (getenv("KEYSDOWN")) {
- klast = atoi(getenv("KEYSDOWN"));
- if (klast < 1) klast = 1;
- if (klast > KLAST) klast = KLAST;
- } else {
- klast = 3;
- }
- if (khints && score_hint == NULL) {
- score_hint = (short **) malloc(0x100 * sizeof(short *));
- for (i=0; i<0x100; i++) {
- score_hint[i] = (short *) malloc(0x100 * sizeof(short));
- }
-
- for (i=0; i<0x100; i++) {
- for (j=0; j<0x100; j++) {
- score_hint[i][j] = -1;
- }
- }
- }
- }
- cnt++;
- if (cnt % 100 && khints && score_hint != NULL) {
- int i, j;
- for (i=0; i<0x100; i++) {
- for (j=0; j<0x100; j++) {
- score_hint[i][j] = -1;
- }
- }
- }
-
- if (debug_keyboard) {
- char *str = XKeysymToString(keysym);
-
- if (debug_keyboard > 1) {
- rfbLog("----------start-xkb_tweak_keyboard (%s) "
- "--------\n", down ? "DOWN" : "UP");
- }
-
- rfbLog("xkb_tweak_keyboard: %s keysym=0x%x \"%s\"\n",
- down ? "down" : "up", (int) keysym, str ? str : "null");
- }
-
- /*
- * set everything to not-yet-found.
- * these "found" arrays (*_f) let us dynamically consider the
- * one-to-many Keysym -> Keycode issue. we set the size at 256,
- * but of course only very few will be found.
- */
- for (i = 0; i < 0x100; i++) {
- kc_f[i] = -1;
- grp_f[i] = -1;
- lvl_f[i] = -1;
- state_f[i] = -1;
- ignore_f[i] = -1;
- }
- found = 0;
-
- /*
- * loop over all (keycode, group, level) triples looking for
- * matching keysyms. Amazingly this isn't slow (but maybe if
- * you type really fast...). Hash lookup into a linked list of
- * (keycode,grp,lvl) triples would be the way to improve this
- * in the future if needed.
- */
- for (kc = kc_min; kc <= kc_max; kc++) {
- for (grp = 0; grp < grp_max+1; grp++) {
- for (lvl = 0; lvl < lvl_max+1; lvl++) {
- if (keysym != xkbkeysyms[kc][grp][lvl]) {
- continue;
- }
- /* got a keysym match */
- state = xkbstate[kc][grp][lvl];
-
- if (debug_keyboard > 1) {
- char *s1, *s2;
- s1 = XKeysymToString(XKeycodeToKeysym(dpy,
- kc, 0));
- if (! s1) s1 = "null";
- s2 = XKeysymToString(keysym);
- if (! s2) s2 = "null";
- fprintf(stderr, " got match kc=%03d=0x%02x G%d"
- " L%d ks=0x%x \"%s\" (basesym: \"%s\")\n",
- kc, kc, grp+1, lvl+1, keysym, s2, s1);
- fprintf(stderr, " need state: %s\n",
- bitprint(state, 8));
- fprintf(stderr, " ignorable : %s\n",
- bitprint(xkbignore[kc][grp][lvl], 8));
- }
-
- /* save it if state is OK and not told to skip */
- if (state == (unsigned int) -1) {
- continue;
- }
- if (skipkeycode[kc] && debug_keyboard) {
- fprintf(stderr, " xxx skipping keycode: %d "
- "G%d/L%d\n", kc, grp+1, lvl+1);
- }
- if (skipkeycode[kc]) {
- continue;
- }
- if (found > 0 && kc == kc_f[found-1]) {
- /* ignore repeats for same keycode */
- continue;
- }
- kc_f[found] = kc;
- grp_f[found] = grp;
- lvl_f[found] = lvl;
- state_f[found] = state;
- ignore_f[found] = xkbignore[kc][grp][lvl];
- found++;
- }
- }
- }
-
-#define PKBSTATE \
- fprintf(stderr, " --- current mod state:\n"); \
- fprintf(stderr, " mods : %s\n", bitprint(kbstate.mods, 8)); \
- fprintf(stderr, " base_mods : %s\n", bitprint(kbstate.base_mods, 8)); \
- fprintf(stderr, " latch_mods: %s\n", bitprint(kbstate.latched_mods, 8)); \
- fprintf(stderr, " lock_mods : %s\n", bitprint(kbstate.locked_mods, 8)); \
- fprintf(stderr, " compat : %s\n", bitprint(kbstate.compat_state, 8));
-
- /*
- * Now get the current state of the keyboard from the X server.
- * This seems to be the safest way to go as opposed to our
- * keeping track of the modifier state on our own. Again,
- * this is fortunately not too slow.
- */
-
- if (debug_keyboard > 1) {
- /* get state early for debug output */
- XkbGetState(dpy, XkbUseCoreKbd, &kbstate);
- got_kbstate = 1;
- PKBSTATE
- }
-
- if (!found && add_keysyms && keysym && ! IsModifierKey(keysym)) {
- int new_kc = add_keysym(keysym);
- if (new_kc != 0) {
- found = 1;
- kc_f[0] = new_kc;
- grp_f[0] = 0;
- lvl_f[0] = 0;
- state_f[0] = 0;
- }
- }
-
- if (!found && debug_keyboard) {
- char *str = XKeysymToString(keysym);
- fprintf(stderr, " *** NO key found for: 0x%x %s "
- "*keystroke ignored*\n", keysym, str ? str : "null");
- }
- if (!found) {
- X_UNLOCK;
- return;
- }
-
- /*
- * we try to optimize here if found > 1
- * e.g. minimize lvl or grp, or other things to give
- * "safest" scenario to simulate the keystrokes.
- */
-
- if (found > 1) {
- if (down) {
- int l, score[0x100];
- int best = 0, best_score = -1;
- /* need to break the tie... */
- if (! got_kbstate) {
- XkbGetState(dpy, XkbUseCoreKbd, &kbstate);
- got_kbstate = 1;
- }
- if (khints && keysym < 0x100) {
- int ks = (int) keysym, j;
- for (j=0; j< 0x100; j++) {
- score_hint[ks][j] = -1;
- }
- }
- for (l=0; l < found; l++) {
- int myscore = 0, b = 0x1, i;
- int curr, curr_state = kbstate.mods;
- int need, need_state = state_f[l];
- int ignore_state = ignore_f[l];
-
- /* see how many modifiers need to be changed */
- for (i=0; i<8; i++) {
- curr = b & curr_state;
- need = b & need_state;
- if (! (b & ignore_state)) {
- ;
- } else if (curr == need) {
- ;
- } else {
- myscore++;
- }
- b = b << 1;
- }
- myscore *= 100;
-
- /* throw in some minimization of lvl too: */
- myscore += 2*lvl_f[l] + grp_f[l];
-
- /*
- * XXX since we now internally track
- * keycode_state[], we could throw that into
- * the score as well. I.e. if it is already
- * down, it is pointless to think we can
- * press it down further! E.g.
- * myscore += 1000 * keycode_state[kc_f[l]];
- * Also could watch multiple modifier
- * problem, e.g. Shift+key -> Alt
- * keycode = 125 on my keyboard.
- */
-
- score[l] = myscore;
- if (debug_keyboard > 1) {
- fprintf(stderr, " *** score for "
- "keycode %03d: %4d\n",
- kc_f[l], myscore);
- }
- if (khints && keysym < 0x100 && kc_f[l] < 0x100) {
- score_hint[(int) keysym][kc_f[l]] = (short) score[l];
- }
- }
- for (l=0; l < found; l++) {
- int myscore = score[l];
- if (best_score == -1 || myscore < best_score) {
- best = l;
- best_score = myscore;
- }
- }
- Kc_f = kc_f[best];
- Grp_f = grp_f[best];
- Lvl_f = lvl_f[best];
- state = state_f[best];
-
- } else {
- /* up */
- int i, Kc_loc = -1;
- Kc_f = -1;
-
- /* first try the scores we remembered when the key went down: */
- if (khints && keysym < 0x100) {
- /* low keysyms, ascii, only */
- int ks = (int) keysym;
- int ok = 1, lbest = 0, l;
- short sbest = -1;
- for (l=0; l < found; l++) {
- if (kc_f[l] < 0x100) {
- int key = (int) kc_f[l];
- if (! keycode_state[key]) {
- continue;
- }
- if (score_hint[ks][key] < 0) {
- ok = 0;
- break;
- }
- if (sbest < 0 || score_hint[ks][key] < sbest) {
- sbest = score_hint[ks][key];
- lbest = l;
- }
- } else {
- ok = 0;
- break;
- }
- }
- if (ok && sbest != -1) {
- Kc_f = kc_f[lbest];
- }
- if (debug_keyboard && Kc_f != -1) {
- fprintf(stderr, " UP: found via score_hint, s/l=%d/%d\n",
- sbest, lbest);
- }
- }
-
- /* next look at our list of recently pressed down keys */
- if (Kc_f == -1) {
- for (i=klast-1; i>=0; i--) {
- /*
- * some people type really fast and leave
- * lots of keys down before releasing
- * them. this gives problem on weird
- * qwerty+dvorak keymappings where each
- * alpha character is on TWO keys.
- */
- if (keysym == Ks_last_down[i]) {
- int l;
- for (l=0; l < found; l++) {
- if (Kc_last_down[i] == kc_f[l]) {
- int key = (int) kc_f[l];
- if (keycode_state[key]) {
- Kc_f = Kc_last_down[i];
- Kc_loc = i;
- break;
- }
- }
- }
- }
- if (Kc_f != -1) {
- break;
- }
- }
- if (debug_keyboard && Kc_f != -1) {
- fprintf(stderr, " UP: found via klast, i=%d\n", Kc_loc);
- }
- }
-
- /* next just check for "best" one that is down */
- if (Kc_f == -1 && anydown) {
- int l;
- int best = -1, lbest = 0;
- /*
- * If it is already down, that is
- * a great hint. Use it.
- *
- * note: keycode_state is internal and
- * ignores someone pressing keys on the
- * physical display (but is updated
- * periodically to clean out stale info).
- */
- for (l=0; l < found; l++) {
- int key = (int) kc_f[l];
- int j, jmatch = -1;
-
- if (! keycode_state[key]) {
- continue;
- }
- /* break ties based on lowest XKeycodeToKeysym index */
- for (j=0; j<8; j++) {
- KeySym ks = XKeycodeToKeysym(dpy, kc_f[l], j);
- if (ks != NoSymbol && ks == keysym) {
- jmatch = j;
- break;
- }
- }
- if (jmatch == -1) {
- continue;
- }
- if (best == -1 || jmatch < best) {
- best = jmatch;
- lbest = l;
- }
- }
- if (best != -1) {
- Kc_f = kc_f[lbest];
- }
- if (debug_keyboard && Kc_f != -1) {
- fprintf(stderr, " UP: found via downlist, l=%d\n", lbest);
- }
- }
-
- /* next, use the first one found that is down */
- if (Kc_f == -1) {
- int l;
- for (l=0; l < found; l++) {
- int key = (int) kc_f[l];
- if (keycode_state[key]) {
- Kc_f = kc_f[l];
- break;
- }
- }
- if (debug_keyboard && Kc_f != -1) {
- fprintf(stderr, " UP: set to first one down, kc_f[%d]!!\n", l);
- }
- }
-
- /* last, use the first one found */
- if (Kc_f == -1) {
- /* hope for the best... XXX check mods */
- Kc_f = kc_f[0];
- if (debug_keyboard && Kc_f != -1) {
- fprintf(stderr, " UP: set to first one at all, kc_f[0]!!\n");
- }
- }
- }
- } else {
- Kc_f = kc_f[0];
- Grp_f = grp_f[0];
- Lvl_f = lvl_f[0];
- state = state_f[0];
- }
-
- if (debug_keyboard && found > 1) {
- int l;
- char *str;
- fprintf(stderr, " *** found more than one keycode: ");
- for (l = 0; l < found; l++) {
- fprintf(stderr, "%03d ", kc_f[l]);
- }
- for (l = 0; l < found; l++) {
- str = XKeysymToString(XKeycodeToKeysym(dpy,kc_f[l],0));
- fprintf(stderr, " \"%s\"", str ? str : "null");
- }
- fprintf(stderr, ", picked this one: %03d (last down: %03d)\n",
- Kc_f, Kc_last_down[0]);
- }
-
- if (sloppy_keys) {
- int new_kc;
- if (sloppy_key_check(Kc_f, down, keysym, &new_kc)) {
- Kc_f = new_kc;
- }
- }
-
- if (down) {
- /*
- * need to set up the mods for tweaking and other workarounds
- */
- int needmods[8], sentmods[8], Ilist[8], keystate[256];
- int involves_multi_key, shift_is_down;
- int i, j, b, curr, need;
- unsigned int ms;
- KeySym ks;
- Bool dn;
-
- /* remember these to aid the subsequent up case: */
- for (i=KLAST-1; i >= 1; i--) {
- Ks_last_down[i] = Ks_last_down[i-1];
- Kc_last_down[i] = Kc_last_down[i-1];
- }
- Ks_last_down[0] = keysym;
- Kc_last_down[0] = Kc_f;
-
- if (! got_kbstate) {
- /* get the current modifier state if we haven't yet */
- XkbGetState(dpy, XkbUseCoreKbd, &kbstate);
- got_kbstate = 1;
- }
-
- /*
- * needmods[] whether or not that modifier bit needs
- * something done to it.
- * < 0 means no,
- * 0 means needs to go up.
- * 1 means needs to go down.
- *
- * -1, -2, -3 are used for debugging info to indicate
- * why nothing needs to be done with the modifier, see below.
- *
- * sentmods[] is the corresponding keycode to use
- * to achieve the needmods[] requirement for the bit.
- */
-
- for (i=0; i<8; i++) {
- needmods[i] = -1;
- sentmods[i] = 0;
- }
-
- /*
- * Loop over the 8 modifier bits and check if the current
- * setting is what we need it to be or whether it should
- * be changed (by us sending some keycode event)
- *
- * If nothing needs to be done to it record why:
- * -1 the modifier bit is ignored.
- * -2 the modifier bit is ignored, but is correct anyway.
- * -3 the modifier bit is correct.
- */
-
- b = 0x1;
- for (i=0; i<8; i++) {
- curr = b & kbstate.mods;
- need = b & state;
-
- if (! (b & xkbignore[Kc_f][Grp_f][Lvl_f])) {
- /* irrelevant modifier bit */
- needmods[i] = -1;
- if (curr == need) needmods[i] = -2;
- } else if (curr == need) {
- /* already correct */
- needmods[i] = -3;
- } else if (! curr && need) {
- /* need it down */
- needmods[i] = 1;
- } else if (curr && ! need) {
- /* need it up */
- needmods[i] = 0;
- }
-
- b = b << 1;
- }
-
- /*
- * Again we dynamically probe the X server for information,
- * this time for the state of all the keycodes. Useful
- * info, and evidently is not too slow...
- */
- get_keystate(keystate);
-
- /*
- * We try to determine if Shift is down (since that can
- * screw up ISO_Level3_Shift manipulations).
- */
- shift_is_down = 0;
-
- for (kc = kc_min; kc <= kc_max; kc++) {
- if (skipkeycode[kc] && debug_keyboard) {
- fprintf(stderr, " xxx skipping keycode: "
- "%d\n", kc);
- }
- if (skipkeycode[kc]) {
- continue;
- }
- if (shift_keys[kc] && keystate[kc]) {
- shift_is_down = kc;
- break;
- }
- }
-
- /*
- * Now loop over the modifier bits and try to deduce the
- * keycode presses/release require to match the desired
- * state.
- */
- for (i=0; i<8; i++) {
- if (needmods[i] < 0 && debug_keyboard > 1) {
- int k = -needmods[i] - 1;
- char *words[] = {"ignorable",
- "bitset+ignorable", "bitset"};
- fprintf(stderr, " +++ needmods: mod=%d is "
- "OK (%s)\n", i, words[k]);
- }
- if (needmods[i] < 0) {
- continue;
- }
-
- b = 1 << i;
-
- if (debug_keyboard > 1) {
- fprintf(stderr, " +++ needmods: mod=%d %s "
- "need it to be: %d %s\n", i, bitprint(b, 8),
- needmods[i], needmods[i] ? "down" : "up");
- }
-
- /*
- * Again, an inefficient loop, this time just
- * looking for modifiers...
- *
- * note the use of kc_vec to prefer XK_ISO_Level3_Shift
- * over XK_Mode_switch.
- */
- for (kci = kc_min; kci <= kc_max; kci++) {
- for (grp = 0; grp < grp_max+1; grp++) {
- for (lvl = 0; lvl < lvl_max+1; lvl++) {
- int skip = 1, dbmsg = 0;
-
- kc = kc_vec[kci];
-
- ms = xkbmodifiers[kc][grp][lvl];
- if (! ms || ms != (unsigned int) b) {
- continue;
- }
-
- if (skipkeycode[kc] && debug_keyboard) {
- fprintf(stderr, " xxx skipping keycode:"
- " %d G%d/L%d\n", kc, grp+1, lvl+1);
- }
- if (skipkeycode[kc]) {
- continue;
- }
-
- ks = xkbkeysyms[kc][grp][lvl];
- if (! ks) {
- continue;
- }
-
- if (ks == XK_Shift_L) {
- skip = 0;
- } else if (ks == XK_Shift_R) {
- skip = 0;
- } else if (ks == XK_Mode_switch) {
- skip = 0;
- } else if (ks == XK_ISO_Level3_Shift) {
- skip = 0;
- }
-
- if (watch_capslock && kbstate.locked_mods & LockMask) {
- if (keysym >= 'A' && keysym <= 'Z') {
- if (ks == XK_Shift_L || ks == XK_Shift_R) {
- if (debug_keyboard > 1) {
- fprintf(stderr, " A-Z caplock skip Shift\n");
- }
- skip = 1;
- } else if (ks == XK_Caps_Lock) {
- if (debug_keyboard > 1) {
- fprintf(stderr, " A-Z caplock noskip CapsLock\n");
- }
- skip = 0;
- }
- }
- }
- /*
- * Alt, Meta, Control, Super,
- * Hyper, Num, Caps are skipped.
- *
- * XXX need more work on Locks,
- * and non-standard modifiers.
- * (e.g. XF86_Next_VMode using
- * Ctrl+Alt)
- */
- if (debug_keyboard > 1) {
- char *str = XKeysymToString(ks);
- int kt = keystate[kc];
- fprintf(stderr, " === for mod=%s "
- "found kc=%03d/G%d/L%d it is %d "
- "%s skip=%d (%s)\n", bitprint(b,8),
- kc, grp+1, lvl+1, kt, kt ?
- "down" : "up ", skip, str ?
- str : "null");
- }
-
- if (! skip && needmods[i] !=
- keystate[kc] && sentmods[i] == 0) {
- sentmods[i] = kc;
- dbmsg = 1;
- }
-
- if (debug_keyboard > 1 && dbmsg) {
- int nm = needmods[i];
- fprintf(stderr, " >>> we choose "
- "kc=%03d=0x%02x to change it to: "
- "%d %s\n", kc, kc, nm, nm ?
- "down" : "up");
- }
-
- }
- }
- }
- }
- for (i=0; i<8; i++) {
- /*
- * reverse order is useful for tweaking
- * ISO_Level3_Shift before Shift, but assumes they
- * are in that order (i.e. Shift is first bit).
- */
- int reverse = 1;
- if (reverse) {
- Ilist[i] = 7 - i;
- } else {
- Ilist[i] = i;
- }
- }
-
- /*
- * check to see if Multi_key is bound to one of the Mods
- * we have to tweak
- */
- involves_multi_key = 0;
- for (j=0; j<8; j++) {
- i = Ilist[j];
- if (sentmods[i] == 0) continue;
- dn = (Bool) needmods[i];
- if (!dn) continue;
- if (multi_key[sentmods[i]]) {
- involves_multi_key = i+1;
- }
- }
-
- if (involves_multi_key && shift_is_down && needmods[0] < 0) {
- /*
- * Workaround for Multi_key and shift.
- * Assumes Shift is bit 1 (needmods[0])
- */
- if (debug_keyboard) {
- fprintf(stderr, " ^^^ trying to avoid "
- "inadvertent Multi_key from Shift "
- "(doing %03d up now)\n", shift_is_down);
- }
- XTestFakeKeyEvent_wr(dpy, shift_is_down, False,
- CurrentTime);
- } else {
- involves_multi_key = 0;
- }
-
- for (j=0; j<8; j++) {
- /* do the Mod ups */
- i = Ilist[j];
- if (sentmods[i] == 0) continue;
- dn = (Bool) needmods[i];
- if (dn) continue;
- XTestFakeKeyEvent_wr(dpy, sentmods[i], dn, CurrentTime);
- }
- for (j=0; j<8; j++) {
- /* next, do the Mod downs */
- i = Ilist[j];
- if (sentmods[i] == 0) continue;
- dn = (Bool) needmods[i];
- if (!dn) continue;
- XTestFakeKeyEvent_wr(dpy, sentmods[i], dn, CurrentTime);
- }
-
- if (involves_multi_key) {
- /*
- * Reverse workaround for Multi_key and shift.
- */
- if (debug_keyboard) {
- fprintf(stderr, " vvv trying to avoid "
- "inadvertent Multi_key from Shift "
- "(doing %03d down now)\n", shift_is_down);
- }
- XTestFakeKeyEvent_wr(dpy, shift_is_down, True,
- CurrentTime);
- }
-
- /*
- * With the above modifier work done, send the actual keycode:
- */
- XTestFakeKeyEvent_wr(dpy, Kc_f, (Bool) down, CurrentTime);
-
- /*
- * Now undo the modifier work:
- */
- for (j=7; j>=0; j--) {
- /* reverse Mod downs we did */
- i = Ilist[j];
- if (sentmods[i] == 0) continue;
- dn = (Bool) needmods[i];
- if (!dn) continue;
- XTestFakeKeyEvent_wr(dpy, sentmods[i], !dn,
- CurrentTime);
- }
- for (j=7; j>=0; j--) {
- /* finally reverse the Mod ups we did */
- i = Ilist[j];
- if (sentmods[i] == 0) continue;
- dn = (Bool) needmods[i];
- if (dn) continue;
- XTestFakeKeyEvent_wr(dpy, sentmods[i], !dn,
- CurrentTime);
- }
-
- } else { /* for up case, hopefully just need to pop it up: */
-
- XTestFakeKeyEvent_wr(dpy, Kc_f, (Bool) down, CurrentTime);
- }
- X_UNLOCK;
-}
-#endif
-
-/*
- * For tweaking modifiers wrt the Alt-Graph key, etc.
- */
-#define LEFTSHIFT 1
-#define RIGHTSHIFT 2
-#define ALTGR 4
-static char mod_state = 0;
-
-static char modifiers[0x100];
-static KeyCode keycodes[0x100];
-static KeyCode left_shift_code, right_shift_code, altgr_code, iso_level3_code;
-
-/* workaround for X11R5, Latin 1 only */
-#ifndef XConvertCase
-#define XConvertCase(sym, lower, upper) \
-*(lower) = sym; \
-*(upper) = sym; \
-if (sym >> 8 == 0) { \
- if ((sym >= XK_A) && (sym <= XK_Z)) \
- *(lower) += (XK_a - XK_A); \
- else if ((sym >= XK_a) && (sym <= XK_z)) \
- *(upper) -= (XK_a - XK_A); \
- else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) \
- *(lower) += (XK_agrave - XK_Agrave); \
- else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) \
- *(upper) -= (XK_agrave - XK_Agrave); \
- else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) \
- *(lower) += (XK_oslash - XK_Ooblique); \
- else if ((sym >= XK_oslash) && (sym <= XK_thorn)) \
- *(upper) -= (XK_oslash - XK_Ooblique); \
-}
-#endif
-
-char *short_kmbcf(char *str) {
- int i, saw_k = 0, saw_m = 0, saw_b = 0, saw_c = 0, saw_f = 0, n = 10;
- char *p, tmp[10];
-
- for (i=0; i<n; i++) {
- tmp[i] = '\0';
- }
-
- p = str;
- i = 0;
- while (*p) {
- if ((*p == 'K' || *p == 'k') && !saw_k) {
- tmp[i++] = 'K';
- saw_k = 1;
- } else if ((*p == 'M' || *p == 'm') && !saw_m) {
- tmp[i++] = 'M';
- saw_m = 1;
- } else if ((*p == 'B' || *p == 'b') && !saw_b) {
- tmp[i++] = 'B';
- saw_b = 1;
- } else if ((*p == 'C' || *p == 'c') && !saw_c) {
- tmp[i++] = 'C';
- saw_c = 1;
- } else if ((*p == 'F' || *p == 'f') && !saw_f) {
- tmp[i++] = 'F';
- saw_f = 1;
- }
- p++;
- }
- return(strdup(tmp));
-}
-
-void initialize_allowed_input(void) {
- char *str;
-
- if (allowed_input_normal) {
- free(allowed_input_normal);
- allowed_input_normal = NULL;
- }
- if (allowed_input_view_only) {
- free(allowed_input_view_only);
- allowed_input_view_only = NULL;
- }
-
- if (! allowed_input_str) {
- allowed_input_normal = strdup("KMBCF");
- allowed_input_view_only = strdup("");
- } else {
- char *p, *str = strdup(allowed_input_str);
- p = strchr(str, ',');
- if (p) {
- allowed_input_view_only = strdup(p+1);
- *p = '\0';
- allowed_input_normal = strdup(str);
- } else {
- allowed_input_normal = strdup(str);
- allowed_input_view_only = strdup("");
- }
- free(str);
- }
-
- /* shorten them */
- str = short_kmbcf(allowed_input_normal);
- free(allowed_input_normal);
- allowed_input_normal = str;
-
- str = short_kmbcf(allowed_input_view_only);
- free(allowed_input_view_only);
- allowed_input_view_only = str;
-
- if (screen) {
- rfbClientIteratorPtr iter;
- rfbClientPtr cl;
-
- iter = rfbGetClientIterator(screen);
- while( (cl = rfbClientIteratorNext(iter)) ) {
- ClientData *cd = (ClientData *) cl->clientData;
-
- if (! cd) {
- continue;
- }
-#if 0
-rfbLog("cd: %p\n", cd);
-rfbLog("cd->input: %s\n", cd->input);
-rfbLog("cd->login_viewonly: %d\n", cd->login_viewonly);
-rfbLog("allowed_input_view_only: %s\n", allowed_input_view_only);
-#endif
-
- if (cd->input[0] == '=') {
- ; /* custom setting */
- } else if (cd->login_viewonly) {
- if (*allowed_input_view_only != '\0') {
- cl->viewOnly = FALSE;
- cd->input[0] = '\0';
- strncpy(cd->input,
- allowed_input_view_only, CILEN);
- } else {
- cl->viewOnly = TRUE;
- }
- } else {
- if (allowed_input_normal) {
- cd->input[0] = '\0';
- strncpy(cd->input,
- allowed_input_normal, CILEN);
- }
- }
- }
- rfbReleaseClientIterator(iter);
- }
-}
-
-void initialize_modtweak(void) {
-#if NO_X11
- RAWFB_RET_VOID
- return;
-#else
- KeySym keysym, *keymap;
- int i, j, minkey, maxkey, syms_per_keycode;
- int use_lowest_index = 0;
-
- if (use_xkb_modtweak) {
- initialize_xkb_modtweak();
- return;
- }
- memset(modifiers, -1, sizeof(modifiers));
- for (i=0; i<0x100; i++) {
- keycodes[i] = NoSymbol;
- }
-
- RAWFB_RET_VOID
-
- if (getenv("MODTWEAK_LOWEST")) {
- use_lowest_index = 1;
- }
-
- X_LOCK;
- XDisplayKeycodes(dpy, &minkey, &maxkey);
-
- keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
- &syms_per_keycode);
-
- /* handle alphabetic char with only one keysym (no upper + lower) */
- for (i = minkey; i <= maxkey; i++) {
- KeySym lower, upper;
- /* 2nd one */
- keysym = keymap[(i - minkey) * syms_per_keycode + 1];
- if (keysym != NoSymbol) {
- continue;
- }
- /* 1st one */
- keysym = keymap[(i - minkey) * syms_per_keycode + 0];
- if (keysym == NoSymbol) {
- continue;
- }
- XConvertCase(keysym, &lower, &upper);
- if (lower != upper) {
- keymap[(i - minkey) * syms_per_keycode + 0] = lower;
- keymap[(i - minkey) * syms_per_keycode + 1] = upper;
- }
- }
- for (i = minkey; i <= maxkey; i++) {
- if (debug_keyboard) {
- if (i == minkey) {
- rfbLog("initialize_modtweak: keycode -> "
- "keysyms mapping info:\n");
- }
- fprintf(stderr, " %03d ", i);
- }
- for (j = 0; j < syms_per_keycode; j++) {
- if (debug_keyboard) {
- char *sym;
-#if 0
- sym =XKeysymToString(XKeycodeToKeysym(dpy,i,j));
-#else
- keysym = keymap[(i-minkey)*syms_per_keycode+j];
- sym = XKeysymToString(keysym);
-#endif
- fprintf(stderr, "%-18s ", sym ? sym : "null");
- if (j == syms_per_keycode - 1) {
- fprintf(stderr, "\n");
- }
- }
- if (j >= 4) {
- /*
- * Something wacky in the keymapping.
- * Ignore these non Shift/AltGr chords
- * for now... n.b. we try to automatically
- * switch to -xkb for this case.
- */
- continue;
- }
- keysym = keymap[ (i - minkey) * syms_per_keycode + j ];
- if ( keysym >= ' ' && keysym < 0x100
- && i == XKeysymToKeycode(dpy, keysym) ) {
- if (use_lowest_index && keycodes[keysym] != NoSymbol) {
- continue;
- }
- keycodes[keysym] = i;
- modifiers[keysym] = j;
- }
- }
- }
-
- left_shift_code = XKeysymToKeycode(dpy, XK_Shift_L);
- right_shift_code = XKeysymToKeycode(dpy, XK_Shift_R);
- altgr_code = XKeysymToKeycode(dpy, XK_Mode_switch);
- iso_level3_code = NoSymbol;
-#ifdef XK_ISO_Level3_Shift
- iso_level3_code = XKeysymToKeycode(dpy, XK_ISO_Level3_Shift);
-#endif
-
- XFree_wr ((void *) keymap);
-
- X_UNLOCK;
-#endif /* NO_X11 */
-}
-
-/*
- * does the actual tweak:
- */
-static void tweak_mod(signed char mod, rfbBool down) {
- rfbBool is_shift = mod_state & (LEFTSHIFT|RIGHTSHIFT);
- Bool dn = (Bool) down;
- KeyCode altgr = altgr_code;
-
- RAWFB_RET_VOID
-
- if (mod < 0) {
- if (debug_keyboard) {
- rfbLog("tweak_mod: Skip: down=%d index=%d\n", down,
- (int) mod);
- }
- return;
- }
- if (debug_keyboard) {
- rfbLog("tweak_mod: Start: down=%d index=%d mod_state=0x%x"
- " is_shift=%d\n", down, (int) mod, (int) mod_state,
- is_shift);
- }
-
- if (use_iso_level3 && iso_level3_code) {
- altgr = iso_level3_code;
- }
-
- X_LOCK;
- if (is_shift && mod != 1) {
- if (mod_state & LEFTSHIFT) {
- XTestFakeKeyEvent_wr(dpy, left_shift_code, !dn, CurrentTime);
- }
- if (mod_state & RIGHTSHIFT) {
- XTestFakeKeyEvent_wr(dpy, right_shift_code, !dn, CurrentTime);
- }
- }
- if ( ! is_shift && mod == 1 ) {
- XTestFakeKeyEvent_wr(dpy, left_shift_code, dn, CurrentTime);
- }
- if ( altgr && (mod_state & ALTGR) && mod != 2 ) {
- XTestFakeKeyEvent_wr(dpy, altgr, !dn, CurrentTime);
- }
- if ( altgr && ! (mod_state & ALTGR) && mod == 2 ) {
- XTestFakeKeyEvent_wr(dpy, altgr, dn, CurrentTime);
- }
- X_UNLOCK;
-
- if (debug_keyboard) {
- rfbLog("tweak_mod: Finish: down=%d index=%d mod_state=0x%x"
- " is_shift=%d\n", down, (int) mod, (int) mod_state,
- is_shift);
- }
-}
-
-/*
- * tweak the modifier under -modtweak
- */
-static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
- rfbClientPtr client) {
-#if NO_X11
- RAWFB_RET_VOID
- if (!down || !keysym || !client) {}
- return;
-#else
- KeyCode k;
- int tweak = 0;
-
- RAWFB_RET_VOID
-
- if (use_xkb_modtweak) {
- xkb_tweak_keyboard(down, keysym, client);
- return;
- }
- if (debug_keyboard) {
- rfbLog("modifier_tweak_keyboard: %s keysym=0x%x\n",
- down ? "down" : "up", (int) keysym);
- }
-
-#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 ) {
- unsigned int state = 0;
- tweak = 1;
- if (watch_capslock && keysym >= 'A' && keysym <= 'Z') {
- X_LOCK;
- state = mask_state();
- X_UNLOCK;
- }
- if (state & LockMask) {
- /* capslock set for A-Z, so no tweak */
- X_LOCK;
- k = XKeysymToKeycode(dpy, (KeySym) keysym);
- X_UNLOCK;
- tweak = 0;
- } else {
- tweak_mod(modifiers[keysym], True);
- k = keycodes[keysym];
- }
- } else {
- X_LOCK;
- k = XKeysymToKeycode(dpy, (KeySym) keysym);
- X_UNLOCK;
- }
- if (k == NoSymbol && add_keysyms && ! IsModifierKey(keysym)) {
- int new_kc = add_keysym(keysym);
- if (new_kc) {
- k = new_kc;
- }
- }
-
- if (sloppy_keys) {
- int new_kc;
- if (sloppy_key_check((int) k, down, keysym, &new_kc)) {
- k = (KeyCode) new_kc;
- }
- }
-
- if (debug_keyboard) {
- char *str = XKeysymToString(keysym);
- rfbLog("modifier_tweak_keyboard: KeySym 0x%x \"%s\" -> "
- "KeyCode 0x%x%s\n", (int) keysym, str ? str : "null",
- (int) k, k ? "" : " *ignored*");
- }
- if ( k != NoSymbol ) {
- X_LOCK;
- XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime);
- X_UNLOCK;
- }
-
- if ( tweak ) {
- tweak_mod(modifiers[keysym], False);
- }
-#endif /* NO_X11 */
-}
-
-void initialize_keyboard_and_pointer(void) {
-
-#ifdef MACOSX
- if (macosx_console) {
- initialize_remap(remap_file);
- initialize_pointer_map(pointer_remap);
- }
-#endif
-
- RAWFB_RET_VOID
-
- if (use_modifier_tweak) {
- initialize_modtweak();
- }
-
- initialize_remap(remap_file);
- initialize_pointer_map(pointer_remap);
-
- X_LOCK;
- clear_modifiers(1);
- if (clear_mods == 1) {
- clear_modifiers(0);
- }
- if (clear_mods == 3) {
- clear_locks();
- }
- X_UNLOCK;
-}
-
-void get_allowed_input(rfbClientPtr client, allowed_input_t *input) {
- ClientData *cd;
- char *str;
-
- input->keystroke = 0;
- input->motion = 0;
- input->button = 0;
- input->clipboard = 0;
- input->files = 0;
-
- if (! client) {
- input->keystroke = 1;
- input->motion = 1;
- input->button = 1;
- input->clipboard = 1;
- input->files = 1;
- return;
- }
-
- cd = (ClientData *) client->clientData;
-
- if (! cd) {
- return;
- }
-
- if (cd->input[0] != '-') {
- str = cd->input;
- } else if (client->viewOnly) {
- if (allowed_input_view_only) {
- str = allowed_input_view_only;
- } else {
- str = "";
- }
- } else {
- if (allowed_input_normal) {
- str = allowed_input_normal;
- } else {
- str = "KMBCF";
- }
- }
-if (0) fprintf(stderr, "GAI: %s - %s\n", str, cd->input);
-
- while (*str) {
- if (*str == 'K') {
- input->keystroke = 1;
- } else if (*str == 'M') {
- input->motion = 1;
- } else if (*str == 'B') {
- input->button = 1;
- } else if (*str == 'C') {
- input->clipboard = 1;
- } else if (*str == 'F') {
- input->files = 1;
- }
- str++;
- }
-}
-
-static void apply_remap(rfbKeySym *keysym, int *isbutton) {
- if (keyremaps) {
- keyremap_t *remap = keyremaps;
- while (remap != NULL) {
- if (remap->before == *keysym) {
- *keysym = remap->after;
- *isbutton = remap->isbutton;
- if (debug_keyboard) {
- char *str1, *str2;
- X_LOCK;
- str1 = XKeysymToString(remap->before);
- str2 = XKeysymToString(remap->after);
- rfbLog("keyboard(): remapping keysym: "
- "0x%x \"%s\" -> 0x%x \"%s\"\n",
- (int) remap->before,
- str1 ? str1 : "null",
- (int) remap->after,
- remap->isbutton ? "button" :
- str2 ? str2 : "null");
- X_UNLOCK;
- }
- break;
- }
- remap = remap->next;
- }
- }
-}
-
-/* for -pipeinput mode */
-static void pipe_keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
- int can_input = 0, uid = 0, isbutton = 0;
- allowed_input_t input;
- char *name;
- ClientData *cd = (ClientData *) client->clientData;
-
- apply_remap(&keysym, &isbutton);
-
- if (isbutton) {
- int mask, button = (int) keysym;
- int x = cursor_x, y = cursor_y;
- char *b, bstr[32];
-
- if (!down) {
- return;
- }
- if (debug_keyboard) {
- rfbLog("keyboard(): remapping keystroke to button %d"
- " click\n", button);
- }
- dtime0(&last_key_to_button_remap_time);
-
- /*
- * This in principle can be a little dicey... i.e. even
- * remap the button click to keystroke sequences!
- * Usually just will simulate the button click.
- */
-
- /* loop over possible multiclicks: Button123 */
- sprintf(bstr, "%d", button);
- b = bstr;
- while (*b != '\0') {
- char t[2];
- int butt;
- t[0] = *b;
- t[1] = '\0';
- if (sscanf(t, "%d", &butt) == 1) {
- mask = 1<<(butt-1);
- pointer_event(mask, x, y, client);
- mask = 0;
- pointer_event(mask, x, y, client);
- }
- b++;
- }
- return;
- }
-
- if (pipeinput_int == PIPEINPUT_VID) {
- v4l_key_command(down, keysym, client);
- } else if (pipeinput_int == PIPEINPUT_CONSOLE) {
- console_key_command(down, keysym, client);
- } else if (pipeinput_int == PIPEINPUT_UINPUT) {
- uinput_key_command(down, keysym, client);
- } else if (pipeinput_int == PIPEINPUT_MACOSX) {
- macosx_key_command(down, keysym, client);
- } else if (pipeinput_int == PIPEINPUT_VNC) {
- vnc_reflect_send_key((uint32_t) keysym, down);
- }
- if (pipeinput_fh == NULL) {
- return;
- }
-
- if (! view_only) {
- get_allowed_input(client, &input);
- if (input.keystroke) {
- can_input = 1; /* XXX distinguish later */
- }
- }
- if (cd) {
- uid = cd->uid;
- }
- if (! can_input) {
- uid = -uid;
- }
-
- X_LOCK;
- name = XKeysymToString(keysym);
- X_UNLOCK;
-
- fprintf(pipeinput_fh, "Keysym %d %d %u %s %s\n", uid, down,
- keysym, name ? name : "null", down ? "KeyPress" : "KeyRelease");
-
- fflush(pipeinput_fh);
- check_pipeinput();
-}
-
-typedef struct keyevent {
- rfbKeySym sym;
- rfbBool down;
- double time;
-} keyevent_t;
-
-#define KEY_HIST 256
-static int key_history_idx = -1;
-static keyevent_t key_history[KEY_HIST];
-
-double typing_rate(double time_window, int *repeating) {
- double dt = 1.0, now = dnow();
- KeySym key = NoSymbol;
- int i, idx, cnt = 0, repeat_keys = 0;
-
- if (key_history_idx == -1) {
- if (repeating) {
- *repeating = 0;
- }
- return 0.0;
- }
- if (time_window > 0.0) {
- dt = time_window;
- }
- for (i=0; i<KEY_HIST; i++) {
- idx = key_history_idx - i;
- if (idx < 0) {
- idx += KEY_HIST;
- }
- if (! key_history[idx].down) {
- continue;
- }
- if (now > key_history[idx].time + dt) {
- break;
- }
- cnt++;
- if (key == NoSymbol) {
- key = key_history[idx].sym;
- repeat_keys = 1;
- } else if (key == key_history[idx].sym) {
- repeat_keys++;
- }
- }
-
- if (repeating) {
- if (repeat_keys >= 2) {
- *repeating = repeat_keys;
- } else {
- *repeating = 0;
- }
- }
-
- /*
- * n.b. keyrate could seem very high with libvncserver buffering them
- * so avoid using small dt.
- */
- return ((double) cnt)/dt;
-}
-
-int skip_cr_when_scaling(char *mode) {
- int got = 0;
-
- if (!scaling) {
- return 0;
- }
-
- if (scaling_copyrect != scaling_copyrect0) {
- /* user override via -scale: */
- if (! scaling_copyrect) {
- return 1;
- } else {
- return 0;
- }
- }
- if (*mode == 's') {
- got = got_scrollcopyrect;
- } else if (*mode == 'w') {
- got = got_wirecopyrect;
- }
- if (scaling_copyrect || got) {
- int lat, rate;
- int link = link_rate(&lat, &rate);
- if (link == LR_DIALUP) {
- return 1;
- } else if (rate < 25) {
- /* the fill-in of the repair may be too slow */
- return 1;
- } else {
- return 0;
- }
- } else {
- return 1;
- }
-}
-
-/*
- * key event handler. See the above functions for contortions for
- * running under -modtweak.
- */
-static rfbClientPtr last_keyboard_client = NULL;
-
-void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
- KeyCode k;
- int idx, isbutton = 0;
- allowed_input_t input;
- time_t now = time(NULL);
- double tnow;
- static int skipped_last_down;
- static rfbBool last_down;
- static rfbKeySym last_keysym = NoSymbol;
- static rfbKeySym max_keyrepeat_last_keysym = NoSymbol;
- static double max_keyrepeat_last_time = 0.0;
- static double max_keyrepeat_always = -1.0;
-
- if (threads_drop_input) {
- return;
- }
-
- dtime0(&tnow);
- got_keyboard_calls++;
-
- if (debug_keyboard) {
- char *str;
- X_LOCK;
- str = XKeysymToString((KeySym) keysym);
- X_UNLOCK;
- rfbLog("# keyboard(%s, 0x%x \"%s\") uip=%d %.4f\n",
- down ? "down":"up", (int) keysym, str ? str : "null",
- unixpw_in_progress, tnow - x11vnc_start);
- }
-
- if (keysym <= 0) {
- rfbLog("keyboard: skipping 0x0 keysym\n");
- return;
- }
-
- if (unixpw_in_progress) {
- if (unixpw_denied) {
- rfbLog("keyboard: ignoring keystroke 0x%x in "
- "unixpw_denied=1 state\n", (int) keysym);
- return;
- }
- if (client != unixpw_client) {
- rfbLog("keyboard: skipping other client in unixpw\n");
- return;
- }
-
- unixpw_keystroke(down, keysym, 0);
-
- return;
- }
-
- if (skip_duplicate_key_events) {
- if (keysym == last_keysym && down == last_down) {
- if (debug_keyboard) {
- rfbLog("skipping dup key event: %d 0x%x\n",
- down, keysym);
- }
- return;
- }
- }
-
- if (skip_lockkeys) {
- /* we don't handle XK_ISO*_Lock or XK_Kana_Lock ... */
- if (keysym == XK_Scroll_Lock || keysym == XK_Num_Lock ||
- keysym == XK_Caps_Lock || keysym == XK_Shift_Lock) {
- if (debug_keyboard) {
- rfbLog("skipping lock key event: %d 0x%x\n",
- down, keysym);
- }
- return;
- } else if (keysym >= XK_KP_0 && keysym <= XK_KP_9) {
- /* ugh this is probably what they meant... assume NumLock. */
- if (debug_keyboard) {
- rfbLog("changed KP digit to regular digit: %d 0x%x\n",
- down, keysym);
- }
- keysym = (keysym - XK_KP_0) + XK_0;
- } else if (keysym == XK_KP_Decimal) {
- if (debug_keyboard) {
- rfbLog("changed XK_KP_Decimal to XK_period: %d 0x%x\n",
- down, keysym);
- }
- keysym = XK_period;
- }
- }
-
- INPUT_LOCK;
-
- last_down = down;
- last_keysym = keysym;
- last_keyboard_time = tnow;
-
- last_rfb_down = down;
- last_rfb_keysym = keysym;
- last_rfb_keytime = tnow;
- last_rfb_key_accepted = FALSE;
-
- if (key_history_idx == -1) {
- for (idx=0; idx<KEY_HIST; idx++) {
- key_history[idx].sym = NoSymbol;
- key_history[idx].down = FALSE;
- key_history[idx].time = 0.0;
- }
- }
- idx = ++key_history_idx;
- if (key_history_idx >= KEY_HIST) {
- key_history_idx = 0;
- idx = 0;
- }
- key_history[idx].sym = keysym;
- key_history[idx].down = down;
- key_history[idx].time = tnow;
-
- if (down && (keysym == XK_Alt_L || keysym == XK_Super_L)) {
- int i, k, run = 0, ups = 0;
- double delay = 1.0;
- KeySym ks;
- for (i=0; i<16; i++) {
- k = idx - i;
- if (k < 0) k += KEY_HIST;
- if (!key_history[k].down) {
- ups++;
- continue;
- }
- ks = key_history[k].sym;
- if (key_history[k].time < tnow - delay) {
- break;
- } else if (ks == keysym && ks == XK_Alt_L) {
- run++;
- } else if (ks == keysym && ks == XK_Super_L) {
- run++;
- } else {
- break;
- }
- }
- if (ups < 2) {
- ;
- } else if (run == 3 && keysym == XK_Alt_L) {
- rfbLog("3*Alt_L, calling: refresh_screen(0)\n");
- refresh_screen(0);
- } else if (run == 4 && keysym == XK_Alt_L) {
- rfbLog("4*Alt_L, setting: do_copy_screen\n");
- do_copy_screen = 1;
- } else if (run == 5 && keysym == XK_Alt_L) {
- ;
- } else if (run == 3 && keysym == XK_Super_L) {
- rfbLog("3*Super_L, calling: set_xdamage_mark()\n");
- set_xdamage_mark(0, 0, dpy_x, dpy_y);
- } else if (run == 4 && keysym == XK_Super_L) {
- rfbLog("4*Super_L, calling: check_xrecord_reset()\n");
- check_xrecord_reset(1);
- } else if (run == 5 && keysym == XK_Super_L) {
- rfbLog("5*Super_L, calling: push_black_screen(0)\n");
- push_black_screen(0);
- }
- }
-
-#ifdef MAX_KEYREPEAT
- if (max_keyrepeat_always < 0.0) {
- if (getenv("MAX_KEYREPEAT")) {
- max_keyrepeat_always = atof(getenv("MAX_KEYREPEAT"));
- } else {
- max_keyrepeat_always = 0.0;
- }
- }
- if (max_keyrepeat_always > 0.0) {
- max_keyrepeat_time = max_keyrepeat_always;
- }
-#else
- if (0) {max_keyrepeat_always=0;}
-#endif
- if (!down && skipped_last_down) {
- int db = debug_scroll;
- if (keysym == max_keyrepeat_last_keysym) {
- skipped_last_down = 0;
- if (db) rfbLog("--- scroll keyrate skipping 0x%lx %s "
- "%.4f %.4f\n", keysym, down ? "down":"up ",
- tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
- INPUT_UNLOCK;
- return;
- }
- }
- if (down && max_keyrepeat_time > 0.0) {
- int skip = 0;
- int db = debug_scroll;
-
- if (max_keyrepeat_last_keysym != NoSymbol &&
- max_keyrepeat_last_keysym != keysym) {
- ;
- } else {
- if (tnow < max_keyrepeat_last_time+max_keyrepeat_time) {
- skip = 1;
- }
- }
- max_keyrepeat_time = 0.0;
- if (skip) {
- if (db) rfbLog("--- scroll keyrate skipping 0x%lx %s "
- "%.4f %.4f\n", keysym, down ? "down":"up ",
- tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
- max_keyrepeat_last_keysym = keysym;
- skipped_last_down = 1;
- INPUT_UNLOCK;
- return;
- } else {
- if (db) rfbLog("--- scroll keyrate KEEPING 0x%lx %s "
- "%.4f %.4f\n", keysym, down ? "down":"up ",
- tnow - x11vnc_start, tnow - max_keyrepeat_last_time);
- }
- }
- max_keyrepeat_last_keysym = keysym;
- max_keyrepeat_last_time = tnow;
- skipped_last_down = 0;
- last_rfb_key_accepted = TRUE;
-
- if (pipeinput_fh != NULL || pipeinput_int) {
- pipe_keyboard(down, keysym, client); /* MACOSX here. */
- if (! pipeinput_tee) {
- if (! view_only || raw_fb) { /* raw_fb hack */
- last_keyboard_client = client;
- last_event = last_input = now;
- last_keyboard_input = now;
-
- last_keysym = keysym;
-
- last_rfb_down = down;
- last_rfb_keysym = keysym;
- last_rfb_keytime = tnow;
- last_rfb_key_injected = dnow();
-
- got_user_input++;
- got_keyboard_input++;
- }
- INPUT_UNLOCK;
- return;
- }
- }
-
- if (view_only) {
- INPUT_UNLOCK;
- return;
- }
- get_allowed_input(client, &input);
- if (! input.keystroke) {
- INPUT_UNLOCK;
- return;
- }
-
- track_mod_state(keysym, down, TRUE); /* ignores remaps */
-
- last_keyboard_client = client;
- last_event = last_input = now;
- last_keyboard_input = now;
-
- last_keysym = keysym;
-
- last_rfb_down = down;
- last_rfb_keysym = keysym;
- last_rfb_keytime = tnow;
- last_rfb_key_injected = dnow();
-
- got_user_input++;
- got_keyboard_input++;
-
- RAWFB_RET_VOID
-
-
- apply_remap(&keysym, &isbutton);
-
- if (use_xrecord && ! xrecording && down) {
-
- if (!strcmp(scroll_copyrect, "never")) {
- ;
- } else if (!strcmp(scroll_copyrect, "mouse")) {
- ;
- } else if (skip_cr_when_scaling("scroll")) {
- ;
- } else if (! xrecord_skip_keysym(keysym)) {
- snapshot_stack_list(0, 0.25);
- xrecord_watch(1, SCR_KEY);
- xrecord_set_by_keys = 1;
- xrecord_keysym = keysym;
- } else {
- if (debug_scroll) {
- char *str = XKeysymToString(keysym);
- rfbLog("xrecord_skip_keysym: %s\n",
- str ? str : "NoSymbol");
- }
- }
- }
-
- if (isbutton) {
- int mask, button = (int) keysym;
- char *b, bstr[32];
-
- if (! down) {
- INPUT_UNLOCK;
- return; /* nothing to send */
- }
- if (debug_keyboard) {
- rfbLog("keyboard(): remapping keystroke to button %d"
- " click\n", button);
- }
- dtime0(&last_key_to_button_remap_time);
-
- X_LOCK;
- /*
- * This in principle can be a little dicey... i.e. even
- * remap the button click to keystroke sequences!
- * Usually just will simulate the button click.
- */
-
- /* loop over possible multiclicks: Button123 */
- sprintf(bstr, "%d", button);
- b = bstr;
- while (*b != '\0') {
- char t[2];
- int butt;
- t[0] = *b;
- t[1] = '\0';
- if (sscanf(t, "%d", &butt) == 1) {
- mask = 1<<(butt-1);
- do_button_mask_change(mask, butt); /* down */
- mask = 0;
- do_button_mask_change(mask, butt); /* up */
- }
- b++;
- }
- XFlush_wr(dpy);
- X_UNLOCK;
- INPUT_UNLOCK;
- return;
- }
-
- if (use_modifier_tweak) {
- modifier_tweak_keyboard(down, keysym, client);
- X_LOCK;
- XFlush_wr(dpy);
- X_UNLOCK;
- INPUT_UNLOCK;
- return;
- }
-
- X_LOCK;
-
- k = XKeysymToKeycode(dpy, (KeySym) keysym);
-
- if (k == NoSymbol && add_keysyms && ! IsModifierKey(keysym)) {
- int new_kc = add_keysym(keysym);
- if (new_kc) {
- k = new_kc;
- }
- }
- if (debug_keyboard) {
- char *str = XKeysymToString(keysym);
- rfbLog("keyboard(): KeySym 0x%x \"%s\" -> KeyCode 0x%x%s\n",
- (int) keysym, str ? str : "null", (int) k,
- k ? "" : " *ignored*");
- }
-
- if ( k != NoSymbol ) {
- XTestFakeKeyEvent_wr(dpy, k, (Bool) down, CurrentTime);
- XFlush_wr(dpy);
- }
-
- X_UNLOCK;
- INPUT_UNLOCK;
-}
-
-
OpenPOWER on IntegriCloud