void AutoTypePlatformX11::unload() { // Restore the KeyboardMapping to its original state. AddKeysym(NoSymbol); if (m_keysymTable) { XFree(m_keysymTable); } if (m_xkb) { XkbFreeKeyboard(m_xkb, XkbAllComponentsMask, True); } m_loaded = false; }
void KeyEvent(CARD32 keysym, Bool down) { int i; unsigned state, new_state; KeyCode keycode; unsigned level_three_mask; KeyCode shift_press = 0, level_three_press = 0; KeyCode *shift_release = NULL, *level_three_release = NULL; /* * Release events must match the press event, so look up what * keycode we sent for the press. */ if (!down) { for (i = 0; i < 256; i++) { if (pressedKeys[i] == keysym) { pressedKeys[i] = NoSymbol; PressKey(kbdDevice, i, FALSE, "keycode"); mieqProcessInputEvents(); return; } } /* * This can happen quite often as we ignore some * key presses. */ if (xkbDebug) rfbLog("Unexpected release of keysym 0x%x\n", keysym); return; } /* * Since we are checking the current state to determine if we need * to fake modifiers, we must make sure that everything put on the * input queue is processed before we start. Otherwise, shift may be * stuck down. */ mieqProcessInputEvents(); state = GetKeyboardState(); keycode = KeysymToKeycode(keysym, state, &new_state); /* Try some equivalent keysyms if we couldn't find a perfect match */ if (keycode == 0) { for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym[0]); i++) { KeySym altsym; if (altKeysym[i].a == keysym) altsym = altKeysym[i].b; else if (altKeysym[i].b == keysym) altsym = altKeysym[i].a; else continue; keycode = KeysymToKeycode(altsym, state, &new_state); if (keycode != 0) break; } } /* We don't have lock synchronisation... */ if (IsLockModifier(keycode, new_state) && ignoreLockModifiers) { if (xkbDebug) rfbLog("Ignoring lock key (e.g. caps lock)\n"); return; } /* No matches. Will have to add a new entry... */ if (keycode == 0) { keycode = AddKeysym(keysym, state); if (keycode == 0) { rfbLog("ERROR: Could not add new keysym 0x%x\n", keysym); return; } rfbLog("Mapped unknown keysym 0x%x to keycode %d\n", keysym, keycode); /* * The state given to addKeysym() is just a hint and * the actual result might still require some state * changes. */ keycode = KeysymToKeycode(keysym, state, &new_state); if (keycode == 0) { rfbLog("ERROR: Cannot generate keycode for newly-added keysym 0x%x\n", keysym); return; } } /* * X11 generally lets shift toggle the keys on the numeric pad * the same way NumLock does. This is however not the case on * other systems like Windows. As a result, some applications * get confused when we do a fake shift to get the same effect * that having NumLock active would produce. * * Until we have proper NumLock synchronisation (so we can * avoid faking shift), we try to avoid the fake shifts if we * can use an alternative keysym. */ if (((state & ShiftMask) != (new_state & ShiftMask)) && avoidShiftNumLock && IsAffectedByNumLock(keycode)) { KeyCode keycode2 = 0; unsigned new_state2; if (xkbDebug) rfbLog("Finding alternative to keysym 0x%x to avoid fake shift for numpad\n", keysym); for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym[0]); i++) { KeySym altsym; if (altKeysym[i].a == keysym) altsym = altKeysym[i].b; else if (altKeysym[i].b == keysym) altsym = altKeysym[i].a; else continue; keycode2 = KeysymToKeycode(altsym, state, &new_state2); if (keycode2 == 0) continue; if (((state & ShiftMask) != (new_state2 & ShiftMask)) && IsAffectedByNumLock(keycode2)) continue; break; } if (i == sizeof(altKeysym) / sizeof(altKeysym[0])) { if (xkbDebug) rfbLog("No alternative keysym found\n"); } else { keycode = keycode2; new_state = new_state2; } } /* * "Shifted Tab" is a bit of a mess. Some systems have varying, * special keysyms for this symbol. VNC mandates that clients * should always send the plain XK_Tab keysym and the server * should deduce the meaning based on current Shift state. * To comply with this, we will find the keycode that sends * XK_Tab, and make sure that Shift isn't cleared. This can * possibly result in a different keysym than XK_Tab, but that * is the desired behaviour. * * Note: We never get ISO_Left_Tab here because it's already * been translated in VNCSConnectionST. */ if (keysym == XK_Tab && (state & ShiftMask)) new_state |= ShiftMask; /* * We need a bigger state change than just shift, * so we need to know what the mask is for level 3 shifts. */ if ((new_state & ~ShiftMask) != (state & ~ShiftMask)) level_three_mask = GetLevelThreeMask(); else level_three_mask = 0; shift_press = level_three_press = 0; /* Need a fake press or release of shift? */ if (!(state & ShiftMask) && (new_state & ShiftMask) && fakeShift) { shift_press = PressShift(); if (shift_press == 0) { rfbLog("ERROR: Unable to find modifier key for Shift key press\n"); return; } PressKey(kbdDevice, shift_press, TRUE, "temp shift"); } else if ((state & ShiftMask) && !(new_state & ShiftMask) && fakeShift) { int index = 0; KeyCode *shift_release = ReleaseShift(); if (!shift_release) { rfbLog("ERROR: Unable to find modifier key(s) for Shift key release\n"); return; } while (shift_release[index]) PressKey(kbdDevice, shift_release[index++], FALSE, "temp shift"); } /* Need a fake press or release of level three shift? */ if (!(state & level_three_mask) && (new_state & level_three_mask) && fakeShift) { level_three_press = PressLevelThree(); if (level_three_press == 0) { rfbLog("ERROR: Unable to find modifier key for ISO_Level3_Shift/Mode_Switch key press\n"); return; } PressKey(kbdDevice, level_three_press, TRUE, "temp level 3 shift"); } else if ((state & level_three_mask) && !(new_state & level_three_mask) && fakeShift) { int index = 0; level_three_release = ReleaseLevelThree(); if (!level_three_release) { rfbLog("ERROR: Unable to find modifier key(s) for ISO_Level3_Shift/Mode_Switch key release\n"); return; } while (level_three_release[index]) PressKey(kbdDevice, level_three_release[index++], FALSE, "temp level 3 shift"); } /* Now press the actual key */ PressKey(kbdDevice, keycode, TRUE, "keycode"); /* And store the mapping so that we can do a proper release later */ for (i = 0; i < 256; i++) { if (i == keycode) continue; if (pressedKeys[i] == keysym) { rfbLog("ERROR: Keysym 0x%x generated by both keys %d and %d\n", keysym, i, keycode); pressedKeys[i] = NoSymbol; } } pressedKeys[keycode] = keysym; /* Undo any fake level three shift */ if (level_three_press != 0) PressKey(kbdDevice, level_three_press, FALSE, "temp level 3 shift"); else if (level_three_release) { int index = 0; while (level_three_release[index]) PressKey(kbdDevice, level_three_release[index++], TRUE, "temp level 3 shift"); free(level_three_release); } /* Undo any fake shift */ if (shift_press != 0) PressKey(kbdDevice, shift_press, FALSE, "temp shift"); else if (shift_release) { int index = 0; while (shift_release[index]) PressKey(kbdDevice, shift_release[index++], TRUE, "temp shift"); free(shift_release); } /* * 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(); }