linux keycode physical/language switch, numpad tweaks
This commit is contained in:
parent
4ae8883d4c
commit
8b8fd3314d
|
@ -164,6 +164,7 @@ struct Linux_Vars {
|
||||||
Linux_Input_Chunk input;
|
Linux_Input_Chunk input;
|
||||||
int xkb_event;
|
int xkb_event;
|
||||||
int xkb_group; // active keyboard layout (0-3)
|
int xkb_group; // active keyboard layout (0-3)
|
||||||
|
KeyCode prev_filtered_key;
|
||||||
|
|
||||||
Key_Mode key_mode;
|
Key_Mode key_mode;
|
||||||
|
|
||||||
|
@ -1035,66 +1036,16 @@ linux_x11_init(int argc, char** argv, Plat_Settings* settings) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
global Key_Code keycode_lookup_table[255];
|
global Key_Code keycode_lookup_table_physical[255];
|
||||||
|
global Key_Code keycode_lookup_table_language[255];
|
||||||
|
|
||||||
|
struct SymCode {
|
||||||
|
KeySym sym;
|
||||||
|
Key_Code code;
|
||||||
|
};
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
linux_keycode_init(Display* dpy){
|
linux_keycode_init_common(Display* dpy, Key_Code* keycode_lookup_table, SymCode* sym_table, SymCode* p, size_t sym_table_size){
|
||||||
|
|
||||||
block_zero_array(keycode_lookup_table);
|
|
||||||
|
|
||||||
// Find these keys by physical position, and map to QWERTY KeyCodes
|
|
||||||
#define K(k) glue(KeyCode_, k)
|
|
||||||
static const u8 positional_keys[] = {
|
|
||||||
K(1), K(2), K(3), K(4), K(5), K(6), K(7), K(8), K(9), K(0), K(Minus), K(Equal),
|
|
||||||
K(Q), K(W), K(E), K(R), K(T), K(Y), K(U), K(I), K(O), K(P), K(LeftBracket), K(RightBracket),
|
|
||||||
K(A), K(S), K(D), K(F), K(G), K(H), K(J), K(K), K(L), K(Semicolon), K(Quote), /*uk hash*/0,
|
|
||||||
K(Z), K(X), K(C), K(V), K(B), K(N), K(M), K(Comma), K(Period), K(ForwardSlash), 0, 0
|
|
||||||
};
|
|
||||||
#undef K
|
|
||||||
|
|
||||||
// XKB gives the alphanumeric keys names like AE01 -> E is the row (from B-E), 01 is the column (01-12).
|
|
||||||
// to get key names in .ps file: setxkbmap -print | xkbcomp - - | xkbprint -label name - out.ps
|
|
||||||
|
|
||||||
static const int ncols = 12;
|
|
||||||
static const int nrows = 4;
|
|
||||||
|
|
||||||
for(int i = XkbMinLegalKeyCode; i <= XkbMaxLegalKeyCode; ++i) {
|
|
||||||
const char* name = linuxvars.xkb->names->keys[i].name;
|
|
||||||
|
|
||||||
// alphanumeric keys
|
|
||||||
|
|
||||||
if(name[0] == 'A' && name[1] >= 'B' && name[1] <= 'E') {
|
|
||||||
int row = (nrows - 1) - (name[1] - 'B');
|
|
||||||
int col = (name[2] - '0') * 10 + (name[3] - '0') - 1;
|
|
||||||
|
|
||||||
if(row >= 0 && row < nrows && col >= 0 && col < ncols) {
|
|
||||||
keycode_lookup_table[i] = positional_keys[row * ncols + col];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// numpad
|
|
||||||
|
|
||||||
else if(name[0] == 'K' && name[1] == 'P' && name[2] >= '0' && name[2] <= '9' && !name[3]) {
|
|
||||||
keycode_lookup_table[i] = KeyCode_NumPad0 + name[2] - '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// a few special cases:
|
|
||||||
|
|
||||||
else if(memcmp(name, "TLDE", XkbKeyNameLength) == 0) {
|
|
||||||
keycode_lookup_table[i] = KeyCode_Tick;
|
|
||||||
} else if(memcmp(name, "BKSL", XkbKeyNameLength) == 0) {
|
|
||||||
keycode_lookup_table[i] = KeyCode_BackwardSlash;
|
|
||||||
} else if(memcmp(name, "LSGT", XkbKeyNameLength) == 0) {
|
|
||||||
// UK extra key between left shift and Z
|
|
||||||
// it prints \ and | with shift. KeyCode_Backslash will be where UK # is.
|
|
||||||
keycode_lookup_table[i] = KeyCode_Ex0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the rest by their key label
|
|
||||||
struct SymCode { KeySym sym; Key_Code code; };
|
|
||||||
SymCode sym_table[108];
|
|
||||||
SymCode* p = sym_table;
|
|
||||||
|
|
||||||
*p++ = { XK_space, KeyCode_Space };
|
*p++ = { XK_space, KeyCode_Space };
|
||||||
*p++ = { XK_Tab, KeyCode_Tab };
|
*p++ = { XK_Tab, KeyCode_Tab };
|
||||||
|
@ -1142,7 +1093,7 @@ linux_keycode_init(Display* dpy){
|
||||||
*p++ = { XK_KP_Enter, KeyCode_Return }; // NumPadEnter?
|
*p++ = { XK_KP_Enter, KeyCode_Return }; // NumPadEnter?
|
||||||
|
|
||||||
const int table_size = p - sym_table;
|
const int table_size = p - sym_table;
|
||||||
Assert(table_size < ArrayCount(sym_table));
|
Assert(table_size < sym_table_size);
|
||||||
|
|
||||||
Key_Code next_extra = KeyCode_Ex1;
|
Key_Code next_extra = KeyCode_Ex1;
|
||||||
const Key_Code max_extra = KeyCode_Ex29;
|
const Key_Code max_extra = KeyCode_Ex29;
|
||||||
|
@ -1159,6 +1110,26 @@ linux_keycode_init(Display* dpy){
|
||||||
for(j = 0; j < table_size; ++j) {
|
for(j = 0; j < table_size; ++j) {
|
||||||
if(sym_table[j].sym == sym) {
|
if(sym_table[j].sym == sym) {
|
||||||
keycode_lookup_table[i] = sym_table[j].code;
|
keycode_lookup_table[i] = sym_table[j].code;
|
||||||
|
//printf("lookup %s = %d\n", key_code_name[sym_table[j].code], i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(j != table_size){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// nothing found - try with shift held (needed for e.g. belgian numbers to bind).
|
||||||
|
KeySym shift_sym = NoSymbol;
|
||||||
|
|
||||||
|
if(!XkbTranslateKeyCode(linuxvars.xkb, i, XkbBuildCoreState(ShiftMask, linuxvars.xkb_group), NULL, &shift_sym)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(j = 0; j < table_size; ++j) {
|
||||||
|
if(sym_table[j].sym == shift_sym) {
|
||||||
|
keycode_lookup_table[i] = sym_table[j].code;
|
||||||
|
//printf("lookup %s = %d\n", key_code_name[sym_table[j].code], i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1168,6 +1139,109 @@ linux_keycode_init(Display* dpy){
|
||||||
keycode_lookup_table[i] = next_extra++;
|
keycode_lookup_table[i] = next_extra++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
linux_keycode_init_language(Display* dpy, Key_Code* keycode_lookup_table){
|
||||||
|
SymCode sym_table[300];
|
||||||
|
SymCode* p = sym_table;
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i <= 26; ++i) {
|
||||||
|
*p++ = { XK_a + i, KeyCode_A + i};
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i <= 26; ++i) {
|
||||||
|
*p++ = { XK_A + i, KeyCode_A + i};
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i <= 9; ++i) {
|
||||||
|
*p++ = { XK_0 + i, KeyCode_0 + i};
|
||||||
|
}
|
||||||
|
|
||||||
|
*p++ = { XK_grave, KeyCode_Tick };
|
||||||
|
*p++ = { XK_minus, KeyCode_Minus };
|
||||||
|
*p++ = { XK_equal, KeyCode_Equal };
|
||||||
|
*p++ = { XK_bracketleft, KeyCode_LeftBracket };
|
||||||
|
*p++ = { XK_bracketright, KeyCode_RightBracket };
|
||||||
|
*p++ = { XK_semicolon, KeyCode_Semicolon };
|
||||||
|
*p++ = { XK_apostrophe, KeyCode_Quote };
|
||||||
|
*p++ = { XK_comma, KeyCode_Comma };
|
||||||
|
*p++ = { XK_period, KeyCode_Period };
|
||||||
|
*p++ = { XK_slash, KeyCode_ForwardSlash };
|
||||||
|
*p++ = { XK_backslash, KeyCode_BackwardSlash };
|
||||||
|
|
||||||
|
linux_keycode_init_common(dpy, keycode_lookup_table, sym_table, p, ArrayCount(sym_table));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
linux_keycode_init_physical(Display* dpy, Key_Code* keycode_lookup_table){
|
||||||
|
|
||||||
|
// Find common keys by their key label
|
||||||
|
SymCode sym_table[100];
|
||||||
|
linux_keycode_init_common(dpy, keycode_lookup_table, sym_table, sym_table, ArrayCount(sym_table));
|
||||||
|
|
||||||
|
// Find these keys by physical position, and map to QWERTY KeyCodes
|
||||||
|
#define K(k) glue(KeyCode_, k)
|
||||||
|
static const u8 positional_keys[] = {
|
||||||
|
K(1), K(2), K(3), K(4), K(5), K(6), K(7), K(8), K(9), K(0), K(Minus), K(Equal),
|
||||||
|
K(Q), K(W), K(E), K(R), K(T), K(Y), K(U), K(I), K(O), K(P), K(LeftBracket), K(RightBracket),
|
||||||
|
K(A), K(S), K(D), K(F), K(G), K(H), K(J), K(K), K(L), K(Semicolon), K(Quote), /*uk hash*/0,
|
||||||
|
K(Z), K(X), K(C), K(V), K(B), K(N), K(M), K(Comma), K(Period), K(ForwardSlash), 0, 0
|
||||||
|
};
|
||||||
|
#undef K
|
||||||
|
|
||||||
|
// XKB gives the alphanumeric keys names like AE01 -> E is the row (from B-E), 01 is the column (01-12).
|
||||||
|
// to get key names in .ps file: setxkbmap -print | xkbcomp - - | xkbprint -label name - out.ps
|
||||||
|
|
||||||
|
static const int ncols = 12;
|
||||||
|
static const int nrows = 4;
|
||||||
|
|
||||||
|
for(int i = XkbMinLegalKeyCode; i <= XkbMaxLegalKeyCode; ++i) {
|
||||||
|
const char* name = linuxvars.xkb->names->keys[i].name;
|
||||||
|
|
||||||
|
// alphanumeric keys
|
||||||
|
|
||||||
|
if(name[0] == 'A' && name[1] >= 'B' && name[1] <= 'E') {
|
||||||
|
int row = (nrows - 1) - (name[1] - 'B');
|
||||||
|
int col = (name[2] - '0') * 10 + (name[3] - '0') - 1;
|
||||||
|
|
||||||
|
if(row >= 0 && row < nrows && col >= 0 && col < ncols) {
|
||||||
|
keycode_lookup_table[i] = positional_keys[row * ncols + col];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// numpad
|
||||||
|
|
||||||
|
else if(name[0] == 'K' && name[1] == 'P' && name[2] >= '0' && name[2] <= '9' && !name[3]) {
|
||||||
|
|
||||||
|
// don't overwrite - for e.g. laptops with numpad keys embedded in the normal ones, toggling with numlock
|
||||||
|
if(keycode_lookup_table[i] == 0) {
|
||||||
|
keycode_lookup_table[i] = KeyCode_NumPad0 + name[2] - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// a few special cases:
|
||||||
|
|
||||||
|
else if(memcmp(name, "TLDE", XkbKeyNameLength) == 0) {
|
||||||
|
keycode_lookup_table[i] = KeyCode_Tick;
|
||||||
|
} else if(memcmp(name, "BKSL", XkbKeyNameLength) == 0) {
|
||||||
|
keycode_lookup_table[i] = KeyCode_BackwardSlash;
|
||||||
|
} else if(memcmp(name, "LSGT", XkbKeyNameLength) == 0) {
|
||||||
|
// UK extra key between left shift and Z
|
||||||
|
// it prints \ and | with shift. KeyCode_Backslash will be where UK # is.
|
||||||
|
keycode_lookup_table[i] = KeyCode_Ex0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
linux_keycode_init(Display* dpy){
|
||||||
|
block_zero_array(keycode_lookup_table_physical);
|
||||||
|
block_zero_array(keycode_lookup_table_language);
|
||||||
|
|
||||||
|
linux_keycode_init_physical(dpy, keycode_lookup_table_physical);
|
||||||
|
linux_keycode_init_language(dpy, keycode_lookup_table_language);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -1341,6 +1415,33 @@ linux_filter_text(Arena* arena, u8* buf, int len) {
|
||||||
return SCu8(result, outp - result);
|
return SCu8(result, outp - result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal KeyCode
|
||||||
|
linux_numlock_convert(KeyCode in){
|
||||||
|
static const KeyCode lookup[] = {
|
||||||
|
KeyCode_Insert,
|
||||||
|
KeyCode_End,
|
||||||
|
KeyCode_Down,
|
||||||
|
KeyCode_PageDown,
|
||||||
|
KeyCode_Left,
|
||||||
|
0,
|
||||||
|
KeyCode_Right,
|
||||||
|
KeyCode_Home,
|
||||||
|
KeyCode_Up,
|
||||||
|
KeyCode_PageUp,
|
||||||
|
0, 0, 0,
|
||||||
|
KeyCode_Delete,
|
||||||
|
};
|
||||||
|
|
||||||
|
if(in >= KeyCode_NumPad0 && in <= KeyCode_NumPadDot) {
|
||||||
|
KeyCode ret = lookup[in - KeyCode_NumPad0];
|
||||||
|
if(ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
linux_handle_x11_events() {
|
linux_handle_x11_events() {
|
||||||
static XEvent prev_event = {};
|
static XEvent prev_event = {};
|
||||||
|
@ -1350,12 +1451,22 @@ linux_handle_x11_events() {
|
||||||
XEvent event;
|
XEvent event;
|
||||||
XNextEvent(linuxvars.dpy, &event);
|
XNextEvent(linuxvars.dpy, &event);
|
||||||
|
|
||||||
|
b32 filtered = false;
|
||||||
if (XFilterEvent(&event, None) == True){
|
if (XFilterEvent(&event, None) == True){
|
||||||
|
filtered = true;
|
||||||
|
if(event.type != KeyPress && event.type != KeyRelease) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 event_id = (u64)event.xkey.serial << 32 | event.xkey.time;
|
||||||
|
|
||||||
switch(event.type) {
|
switch(event.type) {
|
||||||
case KeyPress: {
|
case KeyPress: {
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
linuxvars.key_mode = KeyMode_Physical;
|
||||||
|
|
||||||
should_step = true;
|
should_step = true;
|
||||||
|
|
||||||
Input_Modifier_Set_Fixed* mods = &linuxvars.input.pers.modifiers;
|
Input_Modifier_Set_Fixed* mods = &linuxvars.input.pers.modifiers;
|
||||||
|
@ -1383,12 +1494,41 @@ linux_handle_x11_events() {
|
||||||
add_modifier(mods, KeyCode_Shift);
|
add_modifier(mods, KeyCode_Shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
Key_Code key = keycode_lookup_table[(u8)event.xkey.keycode];
|
Key_Code key;
|
||||||
//printf("key %d = %s\n", event.xkey.keycode, key_code_name[key]);
|
if(linuxvars.key_mode == KeyMode_Physical) {
|
||||||
|
key = keycode_lookup_table_physical[(u8)event.xkey.keycode];
|
||||||
|
} else {
|
||||||
|
key = keycode_lookup_table_language[(u8)event.xkey.keycode];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(state & Mod2Mask)) {
|
||||||
|
key = linux_numlock_convert(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("key %d = %s (f:%d)\n", event.xkey.keycode, key_code_name[key], filtered);
|
||||||
|
|
||||||
|
b32 is_dead = false;
|
||||||
|
if (keysym >= XK_dead_grave && keysym <= XK_dead_greek && len == 0) {
|
||||||
|
is_dead = true;
|
||||||
|
printf(" *** Set Dead Key flag here!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_dead && filtered) {
|
||||||
|
linuxvars.prev_filtered_key = key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a keycode for the key after the dead key
|
||||||
|
if(!key && linuxvars.prev_filtered_key) {
|
||||||
|
key = linuxvars.prev_filtered_key;
|
||||||
|
linuxvars.prev_filtered_key = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Input_Event* key_event = NULL;
|
Input_Event* key_event = NULL;
|
||||||
if(key) {
|
if(key) {
|
||||||
add_modifier(mods, key);
|
add_modifier(mods, key);
|
||||||
|
// printf(" push key %d\n", key);
|
||||||
|
|
||||||
key_event = push_input_event(&linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
key_event = push_input_event(&linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
||||||
key_event->kind = InputEventKind_KeyStroke;
|
key_event->kind = InputEventKind_KeyStroke;
|
||||||
key_event->key.code = key;
|
key_event->key.code = key;
|
||||||
|
@ -1399,6 +1539,7 @@ linux_handle_x11_events() {
|
||||||
if(status == XLookupChars || status == XLookupBoth) {
|
if(status == XLookupChars || status == XLookupBoth) {
|
||||||
String_Const_u8 str = linux_filter_text(&linuxvars.frame_arena, buf, len);
|
String_Const_u8 str = linux_filter_text(&linuxvars.frame_arena, buf, len);
|
||||||
if(str.size) {
|
if(str.size) {
|
||||||
|
// printf(" push txt %d\n", key);
|
||||||
text_event = push_input_event(&linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
text_event = push_input_event(&linuxvars.frame_arena, &linuxvars.input.trans.event_list);
|
||||||
text_event->kind = InputEventKind_TextInsert;
|
text_event->kind = InputEventKind_TextInsert;
|
||||||
text_event->text.string = str;
|
text_event->text.string = str;
|
||||||
|
@ -1408,7 +1549,6 @@ linux_handle_x11_events() {
|
||||||
if(key_event && text_event) {
|
if(key_event && text_event) {
|
||||||
key_event->key.first_dependent_text = text_event;
|
key_event->key.first_dependent_text = text_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case KeyRelease: {
|
case KeyRelease: {
|
||||||
|
@ -1422,7 +1562,17 @@ linux_handle_x11_events() {
|
||||||
set_modifier(mods, KeyCode_CapsLock, state & LockMask);
|
set_modifier(mods, KeyCode_CapsLock, state & LockMask);
|
||||||
set_modifier(mods, KeyCode_Alt, state & Mod1Mask);
|
set_modifier(mods, KeyCode_Alt, state & Mod1Mask);
|
||||||
|
|
||||||
Key_Code key = keycode_lookup_table[(u8)event.xkey.keycode];
|
Key_Code key;
|
||||||
|
if(linuxvars.key_mode == KeyMode_Physical) {
|
||||||
|
key = keycode_lookup_table_physical[(u8)event.xkey.keycode];
|
||||||
|
} else {
|
||||||
|
key = keycode_lookup_table_language[(u8)event.xkey.keycode];
|
||||||
|
}
|
||||||
|
|
||||||
|
// num lock off -> convert KP keys to Insert, Home, End etc.
|
||||||
|
if(!(state & Mod2Mask)) {
|
||||||
|
key = linux_numlock_convert(key);
|
||||||
|
}
|
||||||
|
|
||||||
Input_Event* key_event = NULL;
|
Input_Event* key_event = NULL;
|
||||||
if(key) {
|
if(key) {
|
||||||
|
|
Loading…
Reference in New Issue