Linux keyboard input fixup

This commit is contained in:
Allen Webster 2018-06-09 01:11:47 -07:00
parent 27da2172dc
commit 5e7e7bceba
1 changed files with 200 additions and 49 deletions

View File

@ -958,8 +958,7 @@ LinuxInputInit(Display *dpy, Window XWindow){
// Keyboard handling funcs // Keyboard handling funcs
// //
global Key_Code keycode_lookup_table[255]; #if 0
internal void internal void
LinuxKeycodeInit(Display* dpy){ LinuxKeycodeInit(Display* dpy){
@ -1018,7 +1017,9 @@ LinuxKeycodeInit(Display* dpy){
KeySym* syms = XGetKeyboardMapping(dpy, key_min, key_count, &syms_per_code); KeySym* syms = XGetKeyboardMapping(dpy, key_min, key_count, &syms_per_code);
if (!syms) return; if (syms == 0){
return;
}
int key = key_min; int key = key_min;
for(int i = 0; i < key_count * syms_per_code; ++i){ for(int i = 0; i < key_count * syms_per_code; ++i){
@ -1031,8 +1032,8 @@ LinuxKeycodeInit(Display* dpy){
} }
XFree(syms); XFree(syms);
} }
#endif
internal void internal void
LinuxPushKey(Key_Code code, Key_Code chr, Key_Code chr_nocaps, b8 *mods) LinuxPushKey(Key_Code code, Key_Code chr, Key_Code chr_nocaps, b8 *mods)
@ -1337,41 +1338,41 @@ LinuxX11WindowInit(int argc, char** argv, int* window_width, int* window_height)
internal void internal void
LinuxHandleX11Events(void) LinuxHandleX11Events(void)
{ {
static XEvent PrevEvent = {}; static XEvent prev_event = {};
b32 should_step = false; b32 should_step = false;
while (XPending(linuxvars.XDisplay)) while (XPending(linuxvars.XDisplay))
{ {
XEvent Event; XEvent event;
XNextEvent(linuxvars.XDisplay, &Event); XNextEvent(linuxvars.XDisplay, &event);
if (XFilterEvent(&Event, None) == True){ if (XFilterEvent(&event, None) == True){
continue; continue;
} }
switch (Event.type){ switch (event.type){
case KeyPress: { case KeyPress: {
should_step = true; should_step = true;
b32 is_hold = (PrevEvent.type == KeyRelease && b32 is_hold = (prev_event.type == KeyRelease &&
PrevEvent.xkey.time == Event.xkey.time && prev_event.xkey.time == event.xkey.time &&
PrevEvent.xkey.keycode == Event.xkey.keycode); prev_event.xkey.keycode == event.xkey.keycode);
b8 mods[MDFR_INDEX_COUNT] = {}; b8 mods[MDFR_INDEX_COUNT] = {};
mods[MDFR_HOLD_INDEX] = is_hold; mods[MDFR_HOLD_INDEX] = is_hold;
if (Event.xkey.state & ShiftMask) mods[MDFR_SHIFT_INDEX] = 1; if (event.xkey.state & ShiftMask) mods[MDFR_SHIFT_INDEX] = 1;
if (Event.xkey.state & ControlMask) mods[MDFR_CONTROL_INDEX] = 1; if (event.xkey.state & ControlMask) mods[MDFR_CONTROL_INDEX] = 1;
if (Event.xkey.state & LockMask) mods[MDFR_CAPS_INDEX] = 1; if (event.xkey.state & LockMask) mods[MDFR_CAPS_INDEX] = 1;
if (Event.xkey.state & Mod1Mask) mods[MDFR_ALT_INDEX] = 1; if (event.xkey.state & Mod1Mask) mods[MDFR_ALT_INDEX] = 1;
Event.xkey.state &= ~(ControlMask); event.xkey.state &= ~(ControlMask);
Status status; Status status;
KeySym keysym = NoSymbol; KeySym keysym = NoSymbol;
u8 buff[32] = {}; u8 buff[32] = {};
Xutf8LookupString(linuxvars.input_context, &Event.xkey, (char*)buff, sizeof(buff) - 1, &keysym, &status); Xutf8LookupString(linuxvars.input_context, &event.xkey, (char*)buff, sizeof(buff) - 1, &keysym, &status);
if (status == XBufferOverflow){ if (status == XBufferOverflow){
//TODO(inso): handle properly //TODO(inso): handle properly
@ -1380,14 +1381,26 @@ LinuxHandleX11Events(void)
LOG("FIXME: XBufferOverflow from LookupString.\n"); LOG("FIXME: XBufferOverflow from LookupString.\n");
} }
// don't push modifiers
if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R){
break;
}
u32 key = utf8_to_u32_unchecked(buff); u32 key = utf8_to_u32_unchecked(buff);
u32 key_no_caps = key; u32 key_no_caps = key;
if (mods[MDFR_CAPS_INDEX] && status == XLookupBoth && Event.xkey.keycode){ if (mods[MDFR_CAPS_INDEX] && status == XLookupBoth && event.xkey.keycode){
u8 buff_no_caps[32] = {0}; u8 buff_no_caps[32] = {0};
Event.xkey.state &= ~(LockMask); event.xkey.state &= ~(LockMask);
XLookupString(&Event.xkey, (char*)buff_no_caps, sizeof(buff_no_caps) - 1, NULL, NULL); Xutf8LookupString(linuxvars.input_context, &event.xkey, (char*)buff_no_caps, sizeof(buff_no_caps) - 1, NULL, &status);
if (status == XBufferOverflow){
//TODO(inso): handle properly
Xutf8ResetIC(linuxvars.input_context);
XSetICFocus(linuxvars.input_context);
LOG("FIXME: XBufferOverflow from LookupString.\n");
}
if (*buff_no_caps){ if (*buff_no_caps){
key_no_caps = utf8_to_u32_unchecked(buff_no_caps); key_no_caps = utf8_to_u32_unchecked(buff_no_caps);
@ -1397,17 +1410,156 @@ LinuxHandleX11Events(void)
if (key == '\r') key = '\n'; if (key == '\r') key = '\n';
if (key_no_caps == '\r') key_no_caps = '\n'; if (key_no_caps == '\r') key_no_caps = '\n';
// don't push modifiers
if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R){
break;
}
if (keysym == XK_ISO_Left_Tab){ if (keysym == XK_ISO_Left_Tab){
key = key_no_caps = '\t'; key = key_no_caps = '\t';
mods[MDFR_SHIFT_INDEX] = 1; mods[MDFR_SHIFT_INDEX] = 1;
} }
Key_Code special_key = keycode_lookup_table[(u8)Event.xkey.keycode]; //Key_Code special_key = keycode_lookup_table[keysym];
Key_Code special_key = 0;
switch (keysym){
case XK_BackSpace:
{
special_key = key_back;
}break;
case XK_Delete:
{
special_key = key_del;
}break;
case XK_Up:
{
special_key = key_up;
}break;
case XK_Down:
{
special_key = key_down;
}break;
case XK_Left:
{
special_key = key_left;
}break;
case XK_Right:
{
special_key = key_right;
}break;
case XK_Insert:
{
special_key = key_insert;
}break;
case XK_Home:
{
special_key = key_home;
}break;
case XK_End:
{
special_key = key_end;
}break;
case XK_Page_Up:
{
special_key = key_page_up;
}break;
case XK_Page_Down:
{
special_key = key_page_down;
}break;
case XK_Escape:
{
special_key = key_esc;
}break;
case XK_F1:
{
special_key = key_f1;
}break;
case XK_F2:
{
special_key = key_f2;
}break;
case XK_F3:
{
special_key = key_f3;
}break;
case XK_F4:
{
special_key = key_f4;
}break;
case XK_F5:
{
special_key = key_f5;
}break;
case XK_F6:
{
special_key = key_f6;
}break;
case XK_F7:
{
special_key = key_f7;
}break;
case XK_F8:
{
special_key = key_f8;
}break;
case XK_F9:
{
special_key = key_f9;
}break;
case XK_F10:
{
special_key = key_f10;
}break;
case XK_F11:
{
special_key = key_f11;
}break;
case XK_F12:
{
special_key = key_f12;
}break;
case XK_F13:
{
special_key = key_f13;
}break;
case XK_F14:
{
special_key = key_f14;
}break;
case XK_F15:
{
special_key = key_f15;
}break;
case XK_F16:
{
special_key = key_f16;
}break;
}
if (special_key){ if (special_key){
LinuxPushKey(special_key, 0, 0, mods); LinuxPushKey(special_key, 0, 0, mods);
@ -1424,13 +1576,13 @@ LinuxHandleX11Events(void)
case MotionNotify: { case MotionNotify: {
should_step = true; should_step = true;
linuxvars.input.mouse.x = Event.xmotion.x; linuxvars.input.mouse.x = event.xmotion.x;
linuxvars.input.mouse.y = Event.xmotion.y; linuxvars.input.mouse.y = event.xmotion.y;
}break; }break;
case ButtonPress: { case ButtonPress: {
should_step = true; should_step = true;
switch(Event.xbutton.button){ switch(event.xbutton.button){
case Button1: { case Button1: {
linuxvars.input.mouse.press_l = 1; linuxvars.input.mouse.press_l = 1;
linuxvars.input.mouse.l = 1; linuxvars.input.mouse.l = 1;
@ -1454,7 +1606,7 @@ LinuxHandleX11Events(void)
case ButtonRelease: { case ButtonRelease: {
should_step = true; should_step = true;
switch(Event.xbutton.button){ switch(event.xbutton.button){
case Button1: { case Button1: {
linuxvars.input.mouse.release_l = 1; linuxvars.input.mouse.release_l = 1;
linuxvars.input.mouse.l = 0; linuxvars.input.mouse.l = 0;
@ -1485,8 +1637,8 @@ LinuxHandleX11Events(void)
case ConfigureNotify: { case ConfigureNotify: {
should_step = true; should_step = true;
i32 w = Event.xconfigure.width; i32 w = event.xconfigure.width;
i32 h = Event.xconfigure.height; i32 h = event.xconfigure.height;
if (w != target.width || h != target.height){ if (w != target.width || h != target.height){
LinuxResizeTarget(w, h); LinuxResizeTarget(w, h);
@ -1494,32 +1646,31 @@ LinuxHandleX11Events(void)
}break; }break;
case MappingNotify: { case MappingNotify: {
if (Event.xmapping.request == MappingModifier || Event.xmapping.request == MappingKeyboard){ if (event.xmapping.request == MappingModifier || event.xmapping.request == MappingKeyboard){
XRefreshKeyboardMapping(&Event.xmapping); XRefreshKeyboardMapping(&event.xmapping);
LinuxKeycodeInit(linuxvars.XDisplay); //LinuxKeycodeInit(linuxvars.XDisplay);
} }
}break; }break;
case ClientMessage: { case ClientMessage: {
if ((Atom)Event.xclient.data.l[0] == linuxvars.atom_WM_DELETE_WINDOW) { if ((Atom)event.xclient.data.l[0] == linuxvars.atom_WM_DELETE_WINDOW) {
should_step = true; should_step = true;
linuxvars.keep_running = 0; linuxvars.keep_running = 0;
} }
else if ((Atom)Event.xclient.data.l[0] == linuxvars.atom__NET_WM_PING) { else if ((Atom)event.xclient.data.l[0] == linuxvars.atom__NET_WM_PING) {
Event.xclient.window = DefaultRootWindow(linuxvars.XDisplay); event.xclient.window = DefaultRootWindow(linuxvars.XDisplay);
XSendEvent( XSendEvent(
linuxvars.XDisplay, linuxvars.XDisplay,
Event.xclient.window, event.xclient.window,
False, False,
SubstructureRedirectMask | SubstructureNotifyMask, SubstructureRedirectMask | SubstructureNotifyMask,
&Event &event);
);
} }
}break; }break;
// NOTE(inso): Someone wants us to give them the clipboard data. // NOTE(inso): Someone wants us to give them the clipboard data.
case SelectionRequest: { case SelectionRequest: {
XSelectionRequestEvent request = Event.xselectionrequest; XSelectionRequestEvent request = event.xselectionrequest;
XSelectionEvent response = {}; XSelectionEvent response = {};
response.type = SelectionNotify; response.type = SelectionNotify;
@ -1584,14 +1735,14 @@ LinuxHandleX11Events(void)
// NOTE(inso): Another program is now the clipboard owner. // NOTE(inso): Another program is now the clipboard owner.
case SelectionClear: { case SelectionClear: {
if (Event.xselectionclear.selection == linuxvars.atom_CLIPBOARD){ if (event.xselectionclear.selection == linuxvars.atom_CLIPBOARD){
linuxvars.clipboard_outgoing.size = 0; linuxvars.clipboard_outgoing.size = 0;
} }
}break; }break;
// NOTE(inso): A program is giving us the clipboard data we asked for. // NOTE(inso): A program is giving us the clipboard data we asked for.
case SelectionNotify: { case SelectionNotify: {
XSelectionEvent* e = (XSelectionEvent*)&Event; XSelectionEvent* e = (XSelectionEvent*)&event;
if (e->selection == linuxvars.atom_CLIPBOARD && e->target == linuxvars.atom_UTF8_STRING && e->property != None){ if (e->selection == linuxvars.atom_CLIPBOARD && e->target == linuxvars.atom_UTF8_STRING && e->property != None){
Atom type; Atom type;
int fmt; int fmt;
@ -1619,8 +1770,8 @@ LinuxHandleX11Events(void)
}break; }break;
default: { default: {
if (Event.type == linuxvars.xfixes_selection_event){ if (event.type == linuxvars.xfixes_selection_event){
XFixesSelectionNotifyEvent* sne = (XFixesSelectionNotifyEvent*)&Event; XFixesSelectionNotifyEvent* sne = (XFixesSelectionNotifyEvent*)&event;
if (sne->subtype == XFixesSelectionNotify && sne->owner != linuxvars.XWindow){ if (sne->subtype == XFixesSelectionNotify && sne->owner != linuxvars.XWindow){
XConvertSelection(linuxvars.XDisplay, linuxvars.atom_CLIPBOARD, linuxvars.atom_UTF8_STRING, linuxvars.atom_CLIPBOARD, linuxvars.XWindow, CurrentTime); XConvertSelection(linuxvars.XDisplay, linuxvars.atom_CLIPBOARD, linuxvars.atom_UTF8_STRING, linuxvars.atom_CLIPBOARD, linuxvars.XWindow, CurrentTime);
} }
@ -1628,7 +1779,7 @@ LinuxHandleX11Events(void)
}break; }break;
} }
PrevEvent = Event; prev_event = event;
} }
if (should_step){ if (should_step){
@ -1771,7 +1922,7 @@ main(int argc, char **argv){
linuxvars.input_style = input_result.best_style; linuxvars.input_style = input_result.best_style;
linuxvars.input_context = input_result.xic; linuxvars.input_context = input_result.xic;
LinuxKeycodeInit(linuxvars.XDisplay); //LinuxKeycodeInit(linuxvars.XDisplay);
Cursor xcursors[APP_MOUSE_CURSOR_COUNT] = { Cursor xcursors[APP_MOUSE_CURSOR_COUNT] = {
None, None,