Merge pull request #46 from mbattista/multiple-keys
pressing key with multiple pressed keys
This commit is contained in:
commit
6d38ea71b9
@ -245,14 +245,7 @@ func (manager *RemoteManager) GetScreenSize() *types.ScreenSize {
|
||||
}
|
||||
|
||||
func (manager *RemoteManager) SetKeyboardLayout(layout string) {
|
||||
// Workaround for https://github.com/m1k1o/neko/issues/45
|
||||
// When pressing `shift` + `,` instead of `<` comes `>`.
|
||||
variant := ""
|
||||
if layout == "us" {
|
||||
variant = "mac" // TODO: Test all keys.
|
||||
}
|
||||
|
||||
exec.Command("setxkbmap", layout, variant).Run()
|
||||
exec.Command("setxkbmap", layout).Run()
|
||||
}
|
||||
|
||||
func (manager *RemoteManager) SetKeyboardModifiers(NumLock int, CapsLock int, ScrollLock int) {
|
||||
|
@ -6,6 +6,48 @@ static char *NAME = ":0.0";
|
||||
static int REGISTERED = 0;
|
||||
static int DIRTY = 0;
|
||||
|
||||
xkeys_t *xKeysHead = NULL;
|
||||
|
||||
void XKeysInsert(KeySym keysym, KeyCode keycode) {
|
||||
xkeys_t *node = (xkeys_t *) malloc(sizeof(xkeys_t));
|
||||
|
||||
node->keysym = keysym;
|
||||
node->keycode = keycode;
|
||||
node->next = xKeysHead;
|
||||
xKeysHead = node;
|
||||
}
|
||||
|
||||
KeyCode XKeysPop(KeySym keysym) {
|
||||
KeyCode keycode = 0;
|
||||
xkeys_t *node = xKeysHead,
|
||||
*previous = NULL;
|
||||
int i = 0;
|
||||
|
||||
while (node) {
|
||||
if (node->keysym == keysym) {
|
||||
keycode = node->keycode;
|
||||
|
||||
if (!previous)
|
||||
xKeysHead = node->next;
|
||||
else
|
||||
previous->next = node->next;
|
||||
|
||||
free(node);
|
||||
return keycode;
|
||||
}
|
||||
|
||||
previous = node;
|
||||
node = node->next;
|
||||
if (i++ > 120) {
|
||||
// this should NEVER HAPPEN
|
||||
fprintf(stderr, "[FATAL-ERROR] XKeysPop() in xorg.c: reached maximum loop limit! Something is wrong\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Display *getXDisplay(void) {
|
||||
/* Close the display if displayName has changed */
|
||||
if (DIRTY) {
|
||||
@ -23,7 +65,7 @@ Display *getXDisplay(void) {
|
||||
}
|
||||
|
||||
if (DISPLAY == NULL) {
|
||||
fputs("Could not open main display\n", stderr);
|
||||
fprintf(stderr, "[FATAL-ERROR] XKeysPop() in xorg.c: Could not open main display!");
|
||||
} else if (!REGISTERED) {
|
||||
atexit(&XDisplayClose);
|
||||
REGISTERED = 1;
|
||||
@ -96,13 +138,56 @@ void XButton(unsigned int button, int down) {
|
||||
}
|
||||
}
|
||||
|
||||
void XKey(unsigned long key, int down) {
|
||||
if (key != 0) {
|
||||
Display *display = getXDisplay();
|
||||
KeyCode code = XKeysymToKeycode(display, key);
|
||||
// From: https://github.com/TigerVNC/tigervnc/blob/0946e298075f8f7b6d63e552297a787c5f84d27c/unix/x0vncserver/XDesktop.cxx#L343-L379
|
||||
KeyCode XkbKeysymToKeycode(Display *dpy, KeySym keysym) {
|
||||
XkbDescPtr xkb;
|
||||
XkbStateRec state;
|
||||
unsigned int mods;
|
||||
unsigned keycode;
|
||||
|
||||
// Map non-existing keysyms to new keycodes
|
||||
if(code == 0) {
|
||||
xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
|
||||
if (!xkb)
|
||||
return 0;
|
||||
|
||||
XkbGetState(dpy, XkbUseCoreKbd, &state);
|
||||
// XkbStateFieldFromRec() doesn't work properly because
|
||||
// state.lookup_mods isn't properly updated, so we do this manually
|
||||
mods = XkbBuildCoreState(XkbStateMods(&state), state.group);
|
||||
|
||||
for (keycode = xkb->min_key_code;
|
||||
keycode <= xkb->max_key_code;
|
||||
keycode++) {
|
||||
KeySym cursym;
|
||||
unsigned int out_mods;
|
||||
XkbTranslateKeyCode(xkb, keycode, mods, &out_mods, &cursym);
|
||||
if (cursym == keysym)
|
||||
break;
|
||||
}
|
||||
|
||||
if (keycode > xkb->max_key_code)
|
||||
keycode = 0;
|
||||
|
||||
XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
|
||||
|
||||
// Shift+Tab is usually ISO_Left_Tab, but RFB hides this fact. Do
|
||||
// another attempt if we failed the initial lookup
|
||||
if ((keycode == 0) && (keysym == XK_Tab) && (mods & ShiftMask))
|
||||
return XkbKeysymToKeycode(dpy, XK_ISO_Left_Tab);
|
||||
|
||||
return keycode;
|
||||
}
|
||||
|
||||
void XKey(KeySym key, int down) {
|
||||
Display *display = getXDisplay();
|
||||
KeyCode code = 0;
|
||||
|
||||
if (!down)
|
||||
code = XKeysPop(key);
|
||||
|
||||
if (!code)
|
||||
code = XkbKeysymToKeycode(display, key);
|
||||
|
||||
if (!code) {
|
||||
int min, max, numcodes;
|
||||
XDisplayKeycodes(display, &min, &max);
|
||||
XGetKeyboardMapping(display, min, max-min, &numcodes);
|
||||
@ -113,10 +198,15 @@ void XKey(unsigned long key, int down) {
|
||||
XChangeKeyboardMapping(display, code, numcodes, keysym_list, 1);
|
||||
}
|
||||
|
||||
if (!code)
|
||||
return;
|
||||
|
||||
if (down)
|
||||
XKeysInsert(key, code);
|
||||
|
||||
XTestFakeKeyEvent(display, code, down, CurrentTime);
|
||||
XSync(display, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void XClipboardSet(char *src) {
|
||||
clipboard_c *cb = getClipboard();
|
||||
|
@ -75,7 +75,7 @@ func KeyDown(code uint64) error {
|
||||
|
||||
debounce_key[code] = time.Now()
|
||||
|
||||
C.XKey(C.ulong(code), C.int(1))
|
||||
C.XKey(C.KeySym(code), C.int(1))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -103,7 +103,7 @@ func KeyUp(code uint64) error {
|
||||
|
||||
delete(debounce_key, code)
|
||||
|
||||
C.XKey(C.ulong(code), C.int(0))
|
||||
C.XKey(C.KeySym(code), C.int(0))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,12 @@
|
||||
extern void goCreateScreenSize(int index, int width, int height, int mwidth, int mheight);
|
||||
extern void goSetScreenRates(int index, int rate_index, short rate);
|
||||
|
||||
typedef struct xkeys_t {
|
||||
KeySym keysym;
|
||||
KeyCode keycode;
|
||||
struct xkeys_t *next;
|
||||
} xkeys_t;
|
||||
|
||||
/* Returns the main display, closed either on exit or when closeMainDisplay()
|
||||
* is invoked. This removes a bit of the overhead of calling XOpenDisplay() &
|
||||
* XCloseDisplay() everytime the main display needs to be used.
|
||||
|
Reference in New Issue
Block a user