Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:12.3
xorg-x11-Xvnc
N_tigervnc_keyboard-layout-handling.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor