diff options
Diffstat (limited to 'unix/xserver/hw/vnc/vncInputXKB.c')
-rw-r--r-- | unix/xserver/hw/vnc/vncInputXKB.c | 94 |
1 files changed, 91 insertions, 3 deletions
diff --git a/unix/xserver/hw/vnc/vncInputXKB.c b/unix/xserver/hw/vnc/vncInputXKB.c index d5fe286a..77983482 100644 --- a/unix/xserver/hw/vnc/vncInputXKB.c +++ b/unix/xserver/hw/vnc/vncInputXKB.c @@ -30,6 +30,7 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> +#include "list.h" #include "xkbsrv.h" #include "xkbstr.h" #include "eventstr.h" @@ -56,6 +57,25 @@ static const KeyCode fakeKeys[] = { #endif }; +typedef struct +{ + KeySym keysym; + KeyCode keycode; + struct xorg_list entry; +} AddedKeySym; + +/* + * If a KeySym recieved from client is not mapped to any KeyCode, it needs to be + * mapped to an unused KeyCode to generate required key events. + * + * This list tracks such assignments. A KeyCode from this list can be reused if + * we run out of unused KeyCodes. + * + * Items in this list are maintained in LRU order, with most recently used key + * in front. + */ +static struct xorg_list addedKeysyms; + static void vncXkbProcessDeviceEvent(int screenNum, InternalEvent *event, DeviceIntPtr dev); @@ -218,6 +238,8 @@ void vncPrepareInputDevices(void) */ mieqSetHandler(ET_KeyPress, vncXkbProcessDeviceEvent); mieqSetHandler(ET_KeyRelease, vncXkbProcessDeviceEvent); + + xorg_list_init(&addedKeysyms); } unsigned vncGetKeyboardState(void) @@ -568,6 +590,68 @@ int vncIsAffectedByNumLock(KeyCode keycode) return 1; } +static void saveAddedKeysym(KeyCode code, KeySym sym) +{ + AddedKeySym* item; + + item = malloc(sizeof(AddedKeySym)); + if (!item) + return; + + item->keycode = code; + item->keysym = sym; + xorg_list_add(&item->entry, &addedKeysyms); +} + +/* + * Keeps the list in LRU order by moving the used key to front of the list. + */ +void vncOnKeyUsed(KeyCode usedKeycode) +{ + AddedKeySym* it; + + if (xorg_list_is_empty(&addedKeysyms)) + return; + + it = xorg_list_first_entry(&addedKeysyms, AddedKeySym, entry); + if (it->keycode == usedKeycode) + return; + + xorg_list_for_each_entry(it, &addedKeysyms, entry) { + if (it->keycode == usedKeycode) { + xorg_list_del(&it->entry); + xorg_list_add(&it->entry, &addedKeysyms); + break; + } + } +} + +/* + * Returns keycode of oldest item from list of manually added keysyms. + * The item is removed from the list. + * Returns 0 if no usable keycode is found. + */ +static KeyCode getReusableKeycode(XkbDescPtr xkb) +{ + AddedKeySym* last; + KeyCode result; + + result = 0; + while (result == 0 && !xorg_list_is_empty(&addedKeysyms)) { + last = xorg_list_last_entry(&addedKeysyms, AddedKeySym, entry); + + // Make sure someone else hasn't modified the key + if (XkbKeyNumGroups(xkb, last->keycode) > 0 && + XkbKeySymsPtr(xkb, last->keycode)[0] == last->keysym && + (xkb->names == NULL || xkb->names->keys[last->keycode].name[0] == 'T')) + result = last->keycode; + + xorg_list_del(&last->entry); + free(last); + } + return result; +} + KeyCode vncAddKeysym(KeySym keysym, unsigned state) { DeviceIntPtr master; @@ -589,6 +673,9 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state) } if (key < xkb->min_key_code) + key = getReusableKeycode(xkb); + + if (!key) return 0; memset(&changes, 0, sizeof(changes)); @@ -600,9 +687,8 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state) * Tools like xkbcomp get confused if there isn't a name * assigned to the keycode we're trying to use. */ - if (xkb->names && xkb->names->keys && - (xkb->names->keys[key].name[0] == '\0')) { - xkb->names->keys[key].name[0] = 'I'; + if (xkb->names && xkb->names->keys) { + xkb->names->keys[key].name[0] = 'T'; xkb->names->keys[key].name[1] = '0' + (key / 100) % 10; xkb->names->keys[key].name[2] = '0' + (key / 10) % 10; xkb->names->keys[key].name[3] = '0' + (key / 1) % 10; @@ -641,6 +727,8 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state) XkbSendNotification(master, &changes, &cause); + saveAddedKeysym(key, syms[0]); + return key; } |