File N_tigervnc_keyboard-layout-handling.patch of Package xorg-x11-Xvnc
Author: Michal Srb <msrb@novell.com>
Subject: Handle keyboard layouts same as tightvnc.
Patch-Mainline: Never
This patch exchanges the core part of input handling of tigervnc with code from tightvnc with Matthias Hopf's patches.
--- a/hw/vnc/Input.cc 2012-08-29 10:56:37.000000000 +0200
+++ b/hw/vnc/Input.cc 2012-12-07 16:11:08.000000000 +0100
@@ -25,6 +25,7 @@
#include "Input.h"
#include "xorg-version.h"
#include "vncExtInit.h"
+#include "keyboard.h"
extern "C" {
#define public c_public
@@ -76,8 +77,6 @@
static int pointerProc(DeviceIntPtr pDevice, int onoff);
static int keyboardProc(DeviceIntPtr pDevice, int onoff);
-static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col);
-static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col);
/* Event queue is shared between all devices. */
#if XORG == 15
@@ -338,188 +337,6 @@
((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
/*
- * ModifierState is a class which helps simplify generating a "fake" press or
- * release of shift, ctrl, alt, etc. An instance of the class is created for
- * every modifier which may need to be pressed or released. Then either
- * press() or release() may be called to make sure that the corresponding keys
- * are in the right state. The destructor of the class automatically reverts
- * to the previous state. Each modifier may have multiple keys associated with
- * it, so in the case of a fake release, this may involve releasing more than
- * one key.
- */
-
-class ModifierState {
-public:
- ModifierState(DeviceIntPtr _dev, int _modIndex)
- : modIndex(_modIndex), nKeys(0), keys(0), pressed(false),
- dev(_dev) {}
-
- ~ModifierState()
- {
- for (int i = 0; i < nKeys; i++)
- pressKey(dev, keys[i], !pressed, "fake keycode");
- delete [] keys;
- }
-
- void press()
- {
- int state, maxKeysPerMod, keycode;
-#if XORG >= 17
- KeyCode *modmap = NULL;
-#if XORG >= 111
- state = XkbStateFieldFromRec(&dev->master->key->xkbInfo->state);
-#else /* XORG >= 111 */
- state = XkbStateFieldFromRec(&dev->u.master->key->xkbInfo->state);
-#endif /* XORG >= 111 */
-#else
- KeyClassPtr keyc = dev->key;
- state = keyc->state;
-#endif
- if ((state & (1 << modIndex)) != 0)
- return;
-
-#if XORG >= 17
- if (generate_modkeymap(serverClient, dev, &modmap,
- &maxKeysPerMod) != Success) {
- vlog.error("generate_modkeymap failed");
- return;
- }
-
- if (maxKeysPerMod == 0) {
- vlog.debug("Keyboard has no modifiers");
- xfree(modmap);
- return;
- }
-
- keycode = modmap[modIndex * maxKeysPerMod];
- xfree(modmap);
-#else
- maxKeysPerMod = keyc->maxKeysPerModifier;
- keycode = keyc->modifierKeyMap[modIndex * maxKeysPerMod];
-#endif
- tempKeyEvent(keycode, true, maxKeysPerMod);
- pressed = true;
- }
-
- void release()
- {
- int state, maxKeysPerMod;
- KeyClassPtr keyc;
-#if XORG >= 17
- KeyCode *modmap = NULL;
-
-#if XORG >= 111
- keyc = dev->master->key;
-#else /* XORG >= 111 */
- keyc = dev->u.master->key;
-#endif /* XORG >= 111 */
- state = XkbStateFieldFromRec(&keyc->xkbInfo->state);
-#else
- keyc = dev->key;
- state = keyc->state;
-#endif
- if ((state & (1 << modIndex)) == 0)
- return;
-
-#if XORG >= 17
- if (generate_modkeymap(serverClient, dev, &modmap,
- &maxKeysPerMod) != Success) {
- vlog.error("generate_modkeymap failed");
- return;
- }
-
- if (maxKeysPerMod == 0) {
- vlog.debug("Keyboard has no modifiers");
- xfree(modmap);
- return;
- }
-#else
- maxKeysPerMod = keyc->maxKeysPerModifier;
-#endif
-
- for (int k = 0; k < maxKeysPerMod; k++) {
- int keycode;
- int index = modIndex * maxKeysPerMod + k;
-#if XORG >= 17
- keycode = modmap[index];
-#else
- keycode = keyc->modifierKeyMap[index];
-#endif
- if (keycode && IS_PRESSED(keyc, keycode))
- tempKeyEvent(keycode, false, maxKeysPerMod);
- }
-#if XORG >= 17
- xfree(modmap);
-#endif
- }
-
-private:
- void tempKeyEvent(int keycode, bool down, int maxKeysPerMod)
- {
- if (keycode) {
- if (!keys) keys = new int[maxKeysPerMod];
- keys[nKeys++] = keycode;
- pressKey(dev, keycode, down, "fake keycode");
- }
- }
-
- int modIndex;
- int nKeys;
- int *keys;
- bool pressed;
- DeviceIntPtr dev;
-};
-
-
-/* altKeysym is a table of alternative keysyms which have the same meaning. */
-
-static struct altKeysym_t {
- KeySym a, b;
-} altKeysym[] = {
- { 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_KP_Space, XK_space },
- { XK_KP_Tab, XK_Tab },
- { XK_KP_Enter, XK_Return },
- { XK_KP_F1, XK_F1 },
- { XK_KP_F2, XK_F2 },
- { XK_KP_F3, XK_F3 },
- { XK_KP_F4, XK_F4 },
- { XK_KP_Home, XK_Home },
- { XK_KP_Left, XK_Left },
- { XK_KP_Up, XK_Up },
- { XK_KP_Right, XK_Right },
- { XK_KP_Down, XK_Down },
- { XK_KP_Page_Up, XK_Page_Up },
- { XK_KP_Page_Down, XK_Page_Down },
- { XK_KP_End, XK_End },
- { XK_KP_Begin, XK_Begin },
- { XK_KP_Insert, XK_Insert },
- { XK_KP_Delete, XK_Delete },
- { XK_KP_Equal, XK_equal },
- { XK_KP_Multiply, XK_asterisk },
- { XK_KP_Add, XK_plus },
- { XK_KP_Separator, XK_comma },
- { XK_KP_Subtract, XK_minus },
- { XK_KP_Decimal, XK_period },
- { XK_KP_Divide, XK_slash },
- { XK_KP_0, XK_0 },
- { XK_KP_1, XK_1 },
- { XK_KP_2, XK_2 },
- { XK_KP_3, XK_3 },
- { XK_KP_4, XK_4 },
- { XK_KP_5, XK_5 },
- { XK_KP_6, XK_6 },
- { XK_KP_7, XK_7 },
- { XK_KP_8, XK_8 },
- { XK_KP_9, XK_9 },
-};
-
-/*
* keyEvent() - work out the best keycode corresponding to the keysym sent by
* the viewer. This is non-trivial because we can't assume much about the
* local keyboard layout. We must also find out which column of the keyboard
@@ -595,19 +412,155 @@
}
#endif
+static void vncXConvertCase(KeySym sym, KeySym *lower, KeySym *upper)
+{
+ *lower = sym;
+ *upper = sym;
+ switch(sym >> 8) {
+ case 0: /* Latin 1 */
+ 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);
+ break;
+ case 1: /* Latin 2 */
+ /* Assume the KeySym is a legal value (ignore discontinuities) */
+ if (sym == XK_Aogonek)
+ *lower = XK_aogonek;
+ else if (sym >= XK_Lstroke && sym <= XK_Sacute)
+ *lower += (XK_lstroke - XK_Lstroke);
+ else if (sym >= XK_Scaron && sym <= XK_Zacute)
+ *lower += (XK_scaron - XK_Scaron);
+ else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
+ *lower += (XK_zcaron - XK_Zcaron);
+ else if (sym == XK_aogonek)
+ *upper = XK_Aogonek;
+ else if (sym >= XK_lstroke && sym <= XK_sacute)
+ *upper -= (XK_lstroke - XK_Lstroke);
+ else if (sym >= XK_scaron && sym <= XK_zacute)
+ *upper -= (XK_scaron - XK_Scaron);
+ else if (sym >= XK_zcaron && sym <= XK_zabovedot)
+ *upper -= (XK_zcaron - XK_Zcaron);
+ else if (sym >= XK_Racute && sym <= XK_Tcedilla)
+ *lower += (XK_racute - XK_Racute);
+ else if (sym >= XK_racute && sym <= XK_tcedilla)
+ *upper -= (XK_racute - XK_Racute);
+ break;
+ case 2: /* Latin 3 */
+ /* Assume the KeySym is a legal value (ignore discontinuities) */
+ if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
+ *lower += (XK_hstroke - XK_Hstroke);
+ else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
+ *lower += (XK_gbreve - XK_Gbreve);
+ else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
+ *upper -= (XK_hstroke - XK_Hstroke);
+ else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
+ *upper -= (XK_gbreve - XK_Gbreve);
+ else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
+ *lower += (XK_cabovedot - XK_Cabovedot);
+ else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
+ *upper -= (XK_cabovedot - XK_Cabovedot);
+ break;
+ case 3: /* Latin 4 */
+ /* Assume the KeySym is a legal value (ignore discontinuities) */
+ if (sym >= XK_Rcedilla && sym <= XK_Tslash)
+ *lower += (XK_rcedilla - XK_Rcedilla);
+ else if (sym >= XK_rcedilla && sym <= XK_tslash)
+ *upper -= (XK_rcedilla - XK_Rcedilla);
+ else if (sym == XK_ENG)
+ *lower = XK_eng;
+ else if (sym == XK_eng)
+ *upper = XK_ENG;
+ else if (sym >= XK_Amacron && sym <= XK_Umacron)
+ *lower += (XK_amacron - XK_Amacron);
+ else if (sym >= XK_amacron && sym <= XK_umacron)
+ *upper -= (XK_amacron - XK_Amacron);
+ break;
+ case 6: /* Cyrillic */
+ /* Assume the KeySym is a legal value (ignore discontinuities) */
+ if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
+ *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
+ else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
+ *upper += (XK_Serbian_DJE - XK_Serbian_dje);
+ else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
+ *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
+ else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
+ *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
+ break;
+ case 7: /* Greek */
+ /* Assume the KeySym is a legal value (ignore discontinuities) */
+ if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
+ *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+ else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
+ sym != XK_Greek_iotaaccentdieresis &&
+ sym != XK_Greek_upsilonaccentdieresis)
+ *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+ else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
+ *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
+ else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
+ sym != XK_Greek_finalsmallsigma)
+ *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
+ break;
+ }
+}
+
+
+/* In-server and highly changed version of XkbKeycodeToKeysym */
+static KeySym
+_XkbKeycodeToKeysym(XkbDescPtr xkb, KeyCode kc, int group, int level)
+{
+ KeySym ks;
+
+ if ((kc<xkb->min_key_code)||(kc>xkb->max_key_code))
+ return NoSymbol;
+ /* Treat single group elements as present in all groups */
+ if (XkbKeyNumGroups (xkb,kc) == 1)
+ group = 0;
+ if ((group<0)||(level<0)||(group>=XkbKeyNumGroups(xkb,kc)))
+ return NoSymbol;
+ if (level < XkbKeyGroupWidth(xkb, kc, group))
+ ks = XkbKeySymEntry(xkb, kc, level, group);
+ else
+ ks = NoSymbol;
+ /* Treat 'K' as 'K K', */
+ if (ks == NoSymbol && (level & 1) && level-1 < XkbKeyGroupWidth(xkb, kc, group))
+ ks = XkbKeySymEntry(xkb, kc, level-1, group);
+ return ks;
+}
+
void InputDevice::keyEvent(rdr::U32 keysym, bool down)
{
+ XkbSrvInfoPtr xkbInfo;
+ int group, level;
+ int keyCode = 0;
+ Bool fakeShiftPress = FALSE;
+ Bool fakeShiftLRelease = FALSE;
+ Bool fakeShiftRRelease = FALSE;
+ Bool shiftMustBeReleased = FALSE;
+ Bool shiftMustBePressed = FALSE;
+ Bool fakeLevel3Press = FALSE;
+ Bool fakeLevel3Release = FALSE;
+ Bool level3MustBeReleased = FALSE;
+ Bool level3MustBePressed = FALSE;
#if XORG < 17
DeviceIntPtr master;
#endif
KeyClassPtr keyc;
KeySymsPtr keymap = NULL;
KeySym *map = NULL;
- KeyCode minKeyCode, maxKeyCode;
+ KeyCode minKeyCode;
KeyCode *modmap = NULL;
int mapWidth;
unsigned int i;
- int j, k, state, maxKeysPerMod;
+ int j, k, maxKeysPerMod;
#if XORG >= 17
KeybdCtrl ctrl;
#endif
@@ -650,18 +603,14 @@
if (maxKeysPerMod == 0)
vlog.debug("Keyboard has no modifiers");
-
- state = XkbStateFieldFromRec(&keyc->xkbInfo->state);
#else
keyc = keyboardDev->key;
- state = keyc->state;
maxKeysPerMod = keyc->maxKeysPerModifier;
keymap = &keyc->curKeySyms;
modmap = keyc->modifierKeyMap;
#endif
map = keymap->map;
minKeyCode = keymap->minKeyCode;
- maxKeyCode = keymap->maxKeyCode;
mapWidth = keymap->mapWidth;
#if XORG >= 17
@@ -677,7 +626,7 @@
#endif
/* find which modifier Mode_switch is on. */
- int modeSwitchMapIndex = 0;
+ int modeSwitchKeyCode = 0;
for (i = 3; i < 8; i++) {
for (k = 0; k < maxKeysPerMod; k++) {
int index = i * maxKeysPerMod + k;
@@ -689,7 +638,7 @@
for (j = 0; j < mapWidth; j++) {
if (map[(keycode - minKeyCode) * mapWidth + j]
== XK_Mode_switch) {
- modeSwitchMapIndex = i;
+ modeSwitchKeyCode = modmap[i * maxKeysPerMod];
goto ModeSwitchFound;
}
}
@@ -698,9 +647,7 @@
ModeSwitchFound:
int kc;
- int col = 0;
-#if XORG >= 17
if ((kc = isModifier(keymap, modmap, maxKeysPerMod, keysym)) != -1) {
/*
* It is a modifier key event.
@@ -712,241 +659,174 @@
FREE_MAPS;
return;
}
-
- goto press;
}
-#endif
- if (maxKeysPerMod != 0) {
- if ((state & (1 << ShiftMapIndex)) != 0)
- col |= 1;
- if (modeSwitchMapIndex != 0 &&
- ((state & (1 << modeSwitchMapIndex))) != 0)
- col |= 2;
+ /* Incomplete maps may create NoSymbol - which lets us
+ * select and/or overwrite otherwise valid entries.
+ * E.g Level3+a in serbian layout creates NoSymbol on os11.4
+ * 2011-05-24 mhopf@suse.de */
+ if (keysym == NoSymbol) {
+ ErrorF("KbdAddEvent: ignoring illegal NoSymbol\n");
+ return;
+ }
+
+ xkbInfo = inputInfo.keyboard->key->xkbInfo;
+ group = xkbInfo->state.group;
+ level = (IS_PRESSED(inputInfo.keyboard->key, ISO_LEVEL3_KEY_CODE) ? 2 : 0) |
+ (XkbStateFieldFromRec(&xkbInfo->state) & ShiftMask ? 1 : 0);
+#ifdef DEBUG
+ ErrorF ("VNCkbd:\t%s Sym %04x\n", down ? "+":"-", (int)keysym);
+#endif
+ for (keyCode = MIN_KEY_CODE; keyCode < MIN_KEY_CODE + NO_OF_KEYS; keyCode++) {
+ /* Check whether keysym is reachable in current group
+ * by any shift/Level3_shift state (preferrable w/o change).
+ * This doesn't do real modifyer analysis, only Shift and Level3_Shift.
+ * 2011-05-23 mhopf@suse.de */
+ if (_XkbKeycodeToKeysym(xkbInfo->desc, keyCode, group, level) == keysym)
+ break;
+ if (_XkbKeycodeToKeysym(xkbInfo->desc, keyCode, group, level ^ 2) == keysym) {
+ if (level & 2)
+ level3MustBeReleased = TRUE;
+ else
+ level3MustBePressed = TRUE;
+ break;
+ }
+ if (_XkbKeycodeToKeysym(xkbInfo->desc, keyCode, group, level ^ 1) == keysym) {
+ if (level & 1)
+ shiftMustBeReleased = TRUE;
+ else
+ shiftMustBePressed = TRUE;
+ break;
+ }
+ if (_XkbKeycodeToKeysym(xkbInfo->desc, keyCode, group, level ^ 3) == keysym) {
+ if (level & 2)
+ level3MustBeReleased = TRUE;
+ else
+ level3MustBePressed = TRUE;
+ if (level & 1)
+ shiftMustBeReleased = TRUE;
+ else
+ shiftMustBePressed = TRUE;
+ break;
+ }
}
+ if (keyCode == MIN_KEY_CODE + NO_OF_KEYS)
+ keyCode = 0;
- kc = KeysymToKeycode(keymap, keysym, &col);
-
- /*
- * Sort out the "shifted Tab" mess. If we are sent a shifted Tab,
- * generate a local shifted Tab regardless of what the "shifted Tab"
- * keysym is on the local keyboard (it might be Tab, ISO_Left_Tab or
- * HP's private BackTab keysym, and quite possibly some others too).
- * We never get ISO_Left_Tab here because it's already been translated
- * in VNCSConnectionST.
- */
- if (maxKeysPerMod != 0 && keysym == XK_Tab &&
- ((state & (1 << ShiftMapIndex))) != 0)
- col |= 1;
-
- if (kc == 0) {
- /*
- * Not a direct match in the local keyboard mapping. Check for
- * alternative keysyms with the same meaning.
- */
- for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym_t); i++) {
- if (keysym == altKeysym[i].a)
- kc = KeysymToKeycode(keymap, altKeysym[i].b,
- &col);
- else if (keysym == altKeysym[i].b)
- kc = KeysymToKeycode(keymap, altKeysym[i].a,
- &col);
- if (kc)
+ if (!keyCode) {
+ KeySym lower, upper;
+ KeySymsPtr keySyms = XkbGetCoreMap(inputInfo.keyboard);
+
+ /* we don't have an existing keycode - make one up on the fly and add
+ it to the keyboard mapping. Thanks to Vlad Harchev for pointing
+ out problems with non-ascii capitalisation. */
+
+ /* Find free index for current group. */
+ for (keyCode = MIN_KEY_CODE; keyCode < MIN_KEY_CODE + NO_OF_KEYS; keyCode++) {
+ /* A keyCode is free if no groups are assigned at all */
+ if (XkbKeyNumGroups(xkbInfo->desc, keyCode) == 0)
break;
}
- }
- if (kc == 0) {
- /* Dynamically add a new key to the keyboard mapping. */
- for (kc = maxKeyCode; kc >= minKeyCode; kc--) {
- if (map[(kc - minKeyCode) * mapWidth] != 0)
- continue;
-
- map[(kc - minKeyCode) * mapWidth] = keysym;
- col = 0;
+ if (keyCode == MIN_KEY_CODE + NO_OF_KEYS) {
+ ErrorF("KbdAddEvent: ignoring KeySym 0x%x - no free KeyCodes\n",
+ (int)keysym);
+ free (keySyms->map);
+ free (keySyms);
+ return;
+ }
- vlog.info("Added unknown keysym 0x%x to keycode %d",
- keysym, kc);
+ vncXConvertCase(keysym, &lower, &upper);
-#if XORG < 17
-#if XORG == 15
- master = inputInfo.keyboard;
-#else
- master = keyboardDev->u.master;
-#endif
- void *slave = dixLookupPrivate(&master->devPrivates,
- CoreDevicePrivateKey);
- if (keyboardDev == slave) {
- dixSetPrivate(&master->devPrivates,
- CoreDevicePrivateKey, NULL);
-#if XORG == 15
- SwitchCoreKeyboard(keyboardDev);
-#else
- CopyKeyClass(keyboardDev, master);
-#endif
+ /* Generic layouts needs to set the full map width.
+ * Weird enough, mapWidth seems too big...
+ * 2011-05-23 mhopf@suse.de */
+ for (i = 0; i < (keySyms->mapWidth & ~1); i += 2) {
+ if (lower == upper) {
+ keySyms->map[(keyCode - MIN_KEY_CODE) * keySyms->mapWidth + i] = keysym;
+ keySyms->map[(keyCode - MIN_KEY_CODE) * keySyms->mapWidth + i + 1] = NoSymbol;
+ } else {
+ keySyms->map[(keyCode - MIN_KEY_CODE) * keySyms->mapWidth + i] = lower;
+ keySyms->map[(keyCode - MIN_KEY_CODE) * keySyms->mapWidth + i + 1] = upper;
}
-#else /* XORG < 17 */
- XkbApplyMappingChange(keyboardDev, keymap, minKeyCode,
- maxKeyCode - minKeyCode + 1,
- NULL, serverClient);
-#if XORG >= 111
- XkbCopyDeviceKeymap(keyboardDev->master, keyboardDev);
-#else
- XkbCopyDeviceKeymap(keyboardDev->u.master, keyboardDev);
-#endif
-#endif /* XORG < 17 */
- break;
}
- }
+ if (lower != upper) {
+ if (keysym == lower)
+ shiftMustBeReleased = TRUE;
+ else
+ shiftMustBePressed = TRUE;
+ }
+ level3MustBeReleased = TRUE;
- if (kc < minKeyCode) {
- vlog.info("Keyboard mapping full - ignoring unknown keysym "
- "0x%x",keysym);
- FREE_MAPS;
- return;
- }
+ XkbApplyMappingChange(inputInfo.keyboard, keySyms, keyCode, 1, NULL, serverClient);
-#if XORG < 17
- /*
- * See if it's a modifier key. If so, then don't do any auto-repeat,
- * because the X server will translate each press into a release
- * followed by a press.
- */
- for (i = 0; i < 8; i++) {
- for (k = 0; k < maxKeysPerMod; k++) {
- int index = i * maxKeysPerMod + k;
- if (kc == modmap[index] && IS_PRESSED(keyc,kc) && down) {
- FREE_MAPS;
- return;
- }
- }
- }
-#else
- /*
- * If you would like to press a key which is already pressed then
- * viewer didn't send the "release" event. In this case release it
- * before the press.
- */
- if (IS_PRESSED(keyc, kc) && down) {
- vlog.debug("KeyRelease for %d wasn't sent, releasing", kc);
- pressKey(keyboardDev, kc, false, "fixing keycode");
+ ErrorF("KbdAddEvent: unknown KeySym 0x%x - allocating KeyCode %d\n",
+ (int)keysym, keyCode);
+ free (keySyms->map);
+ free (keySyms);
}
+
+#ifdef DEBUG
+ ErrorF ("\t%s Sym %04x Code%3d\tState x%02x %s%s%s\tSh %s%s\tL3 %s%s\n",
+ down ? "+":"-", (int)keysym, keyCode, XkbStateFieldFromRec(&xkbInfo->state),
+ IS_PRESSED(inputInfo.keyboard->key, SHIFT_L_KEY_CODE) ? "Sl":"",
+ IS_PRESSED(inputInfo.keyboard->key, SHIFT_R_KEY_CODE) ? "Sr":"",
+ IS_PRESSED(inputInfo.keyboard->key, ISO_LEVEL3_KEY_CODE) ? "L3":"",
+ shiftMustBePressed ? "+":"", shiftMustBeReleased ? "-":"",
+ level3MustBePressed ? "+":"", level3MustBeReleased ? "-":"");
#endif
- if (maxKeysPerMod != 0) {
- ModifierState shift(keyboardDev, ShiftMapIndex);
- ModifierState modeSwitch(keyboardDev, modeSwitchMapIndex);
- if (down) {
- if (col & 1)
- shift.press();
- else
- shift.release();
- if (modeSwitchMapIndex) {
- if (col & 2)
- modeSwitch.press();
- else
- modeSwitch.release();
+ if (down) {
+ if (level3MustBePressed && !(level & 2)) {
+ fakeLevel3Press = TRUE;
+ pressKey(inputInfo.keyboard, modeSwitchKeyCode, true, "keycode");
+ }
+ if (level3MustBeReleased && (level & 2)) {
+ fakeLevel3Release = TRUE;
+ pressKey(inputInfo.keyboard, modeSwitchKeyCode, false, "keycode");
+ }
+ if (shiftMustBePressed && !(level & 1)) {
+ fakeShiftPress = TRUE;
+ pressKey(inputInfo.keyboard, SHIFT_L_KEY_CODE, true, "keycode");
+ }
+ if (shiftMustBeReleased && (level & 1)) {
+ if (IS_PRESSED(inputInfo.keyboard->key, SHIFT_L_KEY_CODE)) {
+ fakeShiftLRelease = TRUE;
+ pressKey(inputInfo.keyboard, SHIFT_L_KEY_CODE, false, "keycode");
+ }
+ if (IS_PRESSED(inputInfo.keyboard->key, SHIFT_R_KEY_CODE)) {
+ fakeShiftRRelease = TRUE;
+ pressKey(inputInfo.keyboard, SHIFT_R_KEY_CODE, false, "keycode");
}
}
- /*
- * Ensure ModifierState objects are not destroyed before
- * pressKey call, otherwise fake modifier keypress can be lost.
- */
- pressKey(keyboardDev, kc, down, "keycode");
- } else {
-press:
- pressKey(keyboardDev, kc, down, "keycode");
}
+ pressKey(inputInfo.keyboard, keyCode, down, "keycode");
- FREE_MAPS;
-
- /*
- * When faking a modifier we are putting a keycode (which can
- * currently activate the desired modifier) on the input
- * queue. A future modmap change can change the mapping so
- * that this keycode means something else entirely. Guard
- * against this by processing the queue now.
- */
- mieqProcessInputEvents();
-}
-
-static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col)
-{
- int per = keymap->mapWidth;
- KeySym *syms;
- KeySym lsym, usym;
-
- if ((col < 0) || ((col >= per) && (col > 3)) ||
- (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode))
- return NoSymbol;
-
- syms = &keymap->map[(keycode - keymap->minKeyCode) * per];
- if (col >= 4)
- return syms[col];
-
- if (col > 1) {
- while ((per > 2) && (syms[per - 1] == NoSymbol))
- per--;
- if (per < 3)
- col -= 2;
- }
-
- if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) {
- XkbConvertCase
- (syms[col&~1], &lsym, &usym);
- if (!(col & 1))
- return lsym;
- /*
- * I'm commenting out this logic because it's incorrect even
- * though it was copied from the Xlib sources. The X protocol
- * book quite clearly states that where a group consists of
- * element 1 being a non-alphabetic keysym and element 2 being
- * NoSymbol that you treat the second element as being the
- * same as the first. This also tallies with the behaviour
- * produced by the installed Xlib on my linux box (I believe
- * this is because it uses some XKB code rather than the
- * original Xlib code - compare XKBBind.c with KeyBind.c in
- * lib/X11).
- */
-#if 0
- else if (usym == lsym)
- return NoSymbol;
-#endif
- else
- return usym;
+ if (fakeShiftPress) {
+ pressKey(inputInfo.keyboard, SHIFT_L_KEY_CODE, false, "keycode");
}
-
- return syms[col];
-}
-
-/*
- * KeysymToKeycode() - find the keycode and column corresponding to the given
- * keysym. The value of col passed in should be the column determined from the
- * current shift state. If the keysym can be found in that column we prefer
- * that to finding it in a different column (which would require fake events to
- * alter the shift state).
- */
-static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col)
-{
- int i, j;
-
- j = *col;
- for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
- if (KeyCodetoKeySym(keymap, i, j) == ks)
- return i;
+ if (fakeShiftLRelease) {
+ pressKey(inputInfo.keyboard, SHIFT_L_KEY_CODE, true, "keycode");
}
-
- for (j = 0; j < keymap->mapWidth; j++) {
- for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
- if (KeyCodetoKeySym(keymap, i, j) == ks) {
- *col = j;
- return i;
- }
- }
+ if (fakeShiftRRelease) {
+ pressKey(inputInfo.keyboard, SHIFT_R_KEY_CODE, true, "keycode");
+ }
+ if (fakeLevel3Press) {
+ pressKey(inputInfo.keyboard, modeSwitchKeyCode, false, "keycode");
+ }
+ if (fakeLevel3Release) {
+ pressKey(inputInfo.keyboard, modeSwitchKeyCode, true, "keycode");
}
- return 0;
+ /*
+ * When faking a modifier we are putting a keycode (which can
+ * currently activate the desired modifier) on the input
+ * queue. A future modmap change can change the mapping so
+ * that this keycode means something else entirely. Guard
+ * against this by processing the queue now.
+ */
+ mieqProcessInputEvents();
}
#if XORG < 17
--- /dev/null 2012-11-14 14:33:23.674578655 +0100
+++ b/hw/vnc/keyboard.h 2012-11-09 17:06:22.000000000 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2002 Alan Hourihane. All Rights Reserved.
+ *
+ * This 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.
+ *
+ * This software 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 this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#define MIN_KEY_CODE 8
+#define MAX_KEY_CODE 255
+#define NO_OF_KEYS (MAX_KEY_CODE - MIN_KEY_CODE + 1)
+#define GLYPHS_PER_KEY 4
+
+#define CONTROL_L_KEY_CODE (MIN_KEY_CODE + 29)
+#define CONTROL_R_KEY_CODE (MIN_KEY_CODE + 101)
+#define SHIFT_L_KEY_CODE (MIN_KEY_CODE + 42)
+#define SHIFT_R_KEY_CODE (MIN_KEY_CODE + 54)
+#define META_L_KEY_CODE (MIN_KEY_CODE + 107)
+#define META_R_KEY_CODE (MIN_KEY_CODE + 108)
+#define ALT_L_KEY_CODE (MIN_KEY_CODE + 56)
+#define ALT_R_KEY_CODE (MIN_KEY_CODE + 105)
+#define ISO_LEVEL3_KEY_CODE ALT_R_KEY_CODE