#include "app.h"
#include <X11/Xutil.h>
#include <X11/extensions/XTest.h>
int inputInit(Input *in, App *app) {
LOGDBG("input: init");
in->app = app;
in->mappedKeyCode = 0;
in->mappedPressed = 0;
LOGDBG("input: init: connect to X11");
in->dpy = XOpenDisplay(NULL);
if (!in->dpy)
return LOGERR("input: init: cannot connect to X11");
LOGDBG("input: init: search free keycode for temporary mappings");
int kk = 0, kc0 = 0, kc1 = 0;
XDisplayKeycodes(in->dpy, &kc0, &kc1);
KeySym *ks = XGetKeyboardMapping(in->dpy, kc0, kc1 - kc0 + 1, &kk);
for(int kc = kc0; kc <= kc1; ++kc) {
int found = 1;
for(int i = 0; i < kk; ++i, ++ks)
if (ks[kc*kk + i]) { found = 0; break; }
if (found)
{ in->mappedKeyCode = kc; break; }
}
return 1;
LOGDBG("input: init: found keycode %d", in->mappedKeyCode);
if (!in->mappedKeyCode)
LOGWRN("input: init: cannot found free keycode for temporary mappings, some keys may not work");
return 1;
}
void inputDeinit(Input *in) {
LOGDBG("input: deinit");
XCloseDisplay(in->dpy);
}
void inputEvent(Input *in, unsigned int keySym, int press) {
LOGDBG("input: event: keySym=%u press=%d", keySym, press);
KeyCode keycode = XKeysymToKeycode(in->dpy, keySym);
if (!keycode) {
if (!in->mappedKeyCode) {
LOGWRN("input: event: no keycode mapped to keySym[%u], and no free keycodes for temporary mapping", keySym);
return;
}
keycode = in->mappedKeyCode;
LOGDBG("input: event: temporary remap: keySym[%u] -> keycode[%hhu]", keySym, keycode);
if (in->mappedPressed) {
LOGWRN("input: event: temporary remap: mapped keys collision, release previously mapped key");
XTestFakeKeyEvent(in->dpy, keycode, False, CurrentTime);
XSync(in->dpy, False);
}
KeySym ks[2];
XConvertCase(keySym, &ks[0], &ks[1]);
LOGDBG("input: event: temporary remap: keySym[%u] -> keySyms[%lu, %lu]", keySym, ks[0], ks[1]);
XChangeKeyboardMapping(in->dpy, keycode, ks[0] == ks[1] ? 1 : 2, ks, 1);
XSync(in->dpy, False);
}
if (keycode == in->mappedKeyCode)
in->mappedPressed = press;
LOGDBG("input: event: keycode=%hhu press=%d", keycode, press);
XTestFakeKeyEvent(in->dpy, keycode, press, CurrentTime);
XSync(in->dpy, False);
}