Skip to content

Commit

Permalink
Merge branch 'fix-unknown-keysym' of https://github.com/gujjwal00/tig…
Browse files Browse the repository at this point in the history
  • Loading branch information
CendioOssman committed Aug 6, 2024
2 parents ff50780 + f65433a commit e2bbd9f
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 19 deletions.
67 changes: 52 additions & 15 deletions unix/x0vncserver/XDesktop.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,43 @@ KeyCode XDesktop::XkbKeysymToKeycode(KeySym keysym) {
return keycode;
}

/*
* Keeps the list in LRU order by moving the used key to front of the list.
*/
static void onKeyUsed(std::list<AddedKeySym> &list, KeyCode usedKeycode) {
if (list.empty() || list.front().keycode == usedKeycode)
return;

std::list<AddedKeySym>::iterator it = list.begin();
++it;
for (; it != list.end(); ++it) {
AddedKeySym item = *it;
if (item.keycode == usedKeycode) {
list.erase(it);
list.push_front(item);
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.
*/
KeyCode XDesktop::getReusableKeycode(XkbDescPtr xkb) {
while (!addedKeysyms.empty()) {
AddedKeySym last = addedKeysyms.back();
addedKeysyms.pop_back();

// Make sure someone else hasn't modified the key
if (XkbKeyNumGroups(xkb, last.keycode) > 0 &&
XkbKeySymsPtr(xkb, last.keycode)[0] == last.keysym)
return last.keycode;
}
return 0;
}

KeyCode XDesktop::addKeysym(KeySym keysym)
{
int types[1];
Expand All @@ -426,6 +463,9 @@ KeyCode XDesktop::addKeysym(KeySym keysym)
}

if (key < xkb->min_key_code)
key = getReusableKeycode(xkb);

if (!key)
return 0;

memset(&changes, 0, sizeof(changes));
Expand Down Expand Up @@ -453,7 +493,7 @@ KeyCode XDesktop::addKeysym(KeySym keysym)

if (XkbChangeMap(dpy, xkb, &changes)) {
vlog.info("Added unknown keysym %s to keycode %d", XKeysymToString(keysym), key);
addedKeysyms[keysym] = key;
addedKeysyms.push_front({ syms[0], (KeyCode)key });
return key;
}

Expand All @@ -472,21 +512,17 @@ void XDesktop::deleteAddedKeysyms() {

KeyCode lowestKeyCode = xkb->max_key_code;
KeyCode highestKeyCode = xkb->min_key_code;
std::map<KeySym, KeyCode>::iterator it;
for (it = addedKeysyms.begin(); it != addedKeysyms.end(); it++) {
if (XkbKeyNumGroups(xkb, it->second) != 0) {
// Check if we are removing keysym we added ourself
if (XkbKeysymToKeycode(it->first) != it->second)
continue;
KeyCode keyCode = getReusableKeycode(xkb);
while (keyCode != 0) {
XkbChangeTypesOfKey(xkb, keyCode, 0, XkbGroup1Mask, nullptr, &changes);

XkbChangeTypesOfKey(xkb, it->second, 0, XkbGroup1Mask, nullptr, &changes);
if (keyCode < lowestKeyCode)
lowestKeyCode = keyCode;

if (it->second < lowestKeyCode)
lowestKeyCode = it->second;
if (keyCode > highestKeyCode)
highestKeyCode = keyCode;

if (it->second > highestKeyCode)
highestKeyCode = it->second;
}
keyCode = getReusableKeycode(xkb);
}

// Did we actually find something to remove?
Expand All @@ -497,8 +533,6 @@ void XDesktop::deleteAddedKeysyms() {
changes.first_key_sym = lowestKeyCode;
changes.num_key_syms = highestKeyCode - lowestKeyCode + 1;
XkbChangeMap(dpy, xkb, &changes);

addedKeysyms.clear();
}

KeyCode XDesktop::keysymToKeycode(KeySym keysym) {
Expand Down Expand Up @@ -552,6 +586,9 @@ void XDesktop::keyEvent(uint32_t keysym, uint32_t xtcode, bool down) {
else
pressedKeys.erase(keysym);

if (down)
onKeyUsed(addedKeysyms, keycode);

vlog.debug("%d %s", keycode, down ? "down" : "up");

XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
Expand Down
9 changes: 8 additions & 1 deletion unix/x0vncserver/XDesktop.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
class Geometry;
class XPixelBuffer;

struct AddedKeySym
{
KeySym keysym;
KeyCode keycode;
};

// number of XKb indicator leds to handle
#define XDESKTOP_N_LEDS 3

Expand Down Expand Up @@ -78,7 +84,7 @@ class XDesktop : public rfb::SDesktop,
bool haveXtest;
bool haveDamage;
int maxButtons;
std::map<KeySym, KeyCode> addedKeysyms;
std::list<AddedKeySym> addedKeysyms;
std::map<KeySym, KeyCode> pressedKeys;
bool running;
#ifdef HAVE_XDAMAGE
Expand All @@ -102,6 +108,7 @@ class XDesktop : public rfb::SDesktop,
protected:
#ifdef HAVE_XTEST
KeyCode XkbKeysymToKeycode(KeySym keysym);
KeyCode getReusableKeycode(XkbDescPtr xkb);
KeyCode addKeysym(KeySym keysym);
void deleteAddedKeysyms();
KeyCode keysymToKeycode(KeySym keysym);
Expand Down
3 changes: 3 additions & 0 deletions unix/xserver/hw/vnc/vncInput.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,9 @@ static void vncKeysymKeyboardEvent(KeySym keysym, int down)
/* Now press the actual key */
pressKey(vncKeyboardDev, keycode, TRUE, "keycode");

if(down)
vncOnKeyUsed(keycode);

/* And store the mapping so that we can do a proper release later */
for (i = 0;i < 256;i++) {
if (i == keycode)
Expand Down
1 change: 1 addition & 0 deletions unix/xserver/hw/vnc/vncInput.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
int vncIsAffectedByNumLock(KeyCode keycode);

KeyCode vncAddKeysym(KeySym keysym, unsigned state);
void vncOnKeyUsed(KeyCode usedKeycode);

#ifdef __cplusplus
}
Expand Down
94 changes: 91 additions & 3 deletions unix/xserver/hw/vnc/vncInputXKB.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include "list.h"
#include "xkbsrv.h"
#include "xkbstr.h"
#include "eventstr.h"
Expand All @@ -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);
Expand Down Expand Up @@ -218,6 +238,8 @@ void vncPrepareInputDevices(void)
*/
mieqSetHandler(ET_KeyPress, vncXkbProcessDeviceEvent);
mieqSetHandler(ET_KeyRelease, vncXkbProcessDeviceEvent);

xorg_list_init(&addedKeysyms);
}

unsigned vncGetKeyboardState(void)
Expand Down Expand Up @@ -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;
Expand All @@ -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));
Expand All @@ -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;
Expand Down Expand Up @@ -641,6 +727,8 @@ KeyCode vncAddKeysym(KeySym keysym, unsigned state)

XkbSendNotification(master, &changes, &cause);

saveAddedKeysym(key, syms[0]);

return key;
}

Expand Down

0 comments on commit e2bbd9f

Please sign in to comment.