Get keyboard input from X11 on Linux

This commit is contained in:
erorcun 2021-02-18 03:44:02 +03:00
parent 48cec4a786
commit bf7280b55b
2 changed files with 305 additions and 8 deletions

View file

@ -342,10 +342,10 @@ project "re3"
libdirs { "vendor/openal-soft/libs/Win64" } libdirs { "vendor/openal-soft/libs/Win64" }
filter "platforms:linux*oal" filter "platforms:linux*oal"
links { "openal", "mpg123", "sndfile", "pthread" } links { "openal", "mpg123", "sndfile", "pthread", "X11" }
filter "platforms:bsd*oal" filter "platforms:bsd*oal"
links { "openal", "mpg123", "sndfile", "pthread" } links { "openal", "mpg123", "sndfile", "pthread", "X11" }
filter "platforms:macosx*oal" filter "platforms:macosx*oal"
links { "openal", "mpg123", "sndfile", "pthread" } links { "openal", "mpg123", "sndfile", "pthread" }

View file

@ -50,17 +50,30 @@ long _dwOperatingSystemVersion;
#include "Font.h" #include "Font.h"
#include "MemoryMgr.h" #include "MemoryMgr.h"
#define MAX_SUBSYSTEMS (16) // We found out that GLFW's keyboard input handling is still pretty delayed/not stable, so now we fetch input from X11 directly on Linux.
#if !defined _WIN32 && !defined __APPLE__ && !defined __SWITCH__ // && !defined WAYLAND
#define GET_KEYBOARD_INPUT_FROM_X11
#endif
#ifdef GET_KEYBOARD_INPUT_FROM_X11
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#define GLFW_EXPOSE_NATIVE_X11
#include <GLFW/glfw3native.h>
#endif
#ifdef _WIN32 #ifdef _WIN32
#define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h> #include <GLFW/glfw3native.h>
#endif #endif
#define MAX_SUBSYSTEMS (16)
rw::EngineOpenParams openParams; rw::EngineOpenParams openParams;
static RwBool ForegroundApp = TRUE; static RwBool ForegroundApp = TRUE;
static RwBool WindowIconified = FALSE;
static RwBool WindowFocused = TRUE;
static RwBool RwInitialised = FALSE; static RwBool RwInitialised = FALSE;
@ -322,7 +335,9 @@ psInitialize(void)
RsGlobal.ps = &PsGlobal; RsGlobal.ps = &PsGlobal;
PsGlobal.fullScreen = FALSE; PsGlobal.fullScreen = FALSE;
PsGlobal.cursorIsInWindow = TRUE; PsGlobal.cursorIsInWindow = FALSE;
WindowFocused = TRUE;
WindowIconified = FALSE;
PsGlobal.joy1id = -1; PsGlobal.joy1id = -1;
PsGlobal.joy2id = -1; PsGlobal.joy2id = -1;
@ -838,11 +853,15 @@ psSelectDevice()
return TRUE; return TRUE;
} }
#ifndef GET_KEYBOARD_INPUT_FROM_X11
void keypressCB(GLFWwindow* window, int key, int scancode, int action, int mods); void keypressCB(GLFWwindow* window, int key, int scancode, int action, int mods);
#endif
void resizeCB(GLFWwindow* window, int width, int height); void resizeCB(GLFWwindow* window, int width, int height);
void scrollCB(GLFWwindow* window, double xoffset, double yoffset); void scrollCB(GLFWwindow* window, double xoffset, double yoffset);
void cursorCB(GLFWwindow* window, double xpos, double ypos); void cursorCB(GLFWwindow* window, double xpos, double ypos);
void cursorEnterCB(GLFWwindow* window, int entered); void cursorEnterCB(GLFWwindow* window, int entered);
void windowFocusCB(GLFWwindow* window, int focused);
void windowIconifyCB(GLFWwindow* window, int iconified);
void joysChangeCB(int jid, int event); void joysChangeCB(int jid, int event);
bool IsThisJoystickBlacklisted(int i) bool IsThisJoystickBlacklisted(int i)
@ -930,11 +949,15 @@ void psPostRWinit(void)
RwVideoMode vm; RwVideoMode vm;
RwEngineGetVideoModeInfo(&vm, GcurSelVM); RwEngineGetVideoModeInfo(&vm, GcurSelVM);
#ifndef GET_KEYBOARD_INPUT_FROM_X11
glfwSetKeyCallback(PSGLOBAL(window), keypressCB); glfwSetKeyCallback(PSGLOBAL(window), keypressCB);
#endif
glfwSetFramebufferSizeCallback(PSGLOBAL(window), resizeCB); glfwSetFramebufferSizeCallback(PSGLOBAL(window), resizeCB);
glfwSetScrollCallback(PSGLOBAL(window), scrollCB); glfwSetScrollCallback(PSGLOBAL(window), scrollCB);
glfwSetCursorPosCallback(PSGLOBAL(window), cursorCB); glfwSetCursorPosCallback(PSGLOBAL(window), cursorCB);
glfwSetCursorEnterCallback(PSGLOBAL(window), cursorEnterCB); glfwSetCursorEnterCallback(PSGLOBAL(window), cursorEnterCB);
glfwSetWindowIconifyCallback(PSGLOBAL(window), windowIconifyCB);
glfwSetWindowFocusCallback(PSGLOBAL(window), windowFocusCB);
glfwSetJoystickCallback(joysChangeCB); glfwSetJoystickCallback(joysChangeCB);
_InputInitialiseJoys(); _InputInitialiseJoys();
@ -1286,6 +1309,10 @@ void scrollCB(GLFWwindow* window, double xoffset, double yoffset) {
PSGLOBAL(mouseWheel) = yoffset; PSGLOBAL(mouseWheel) = yoffset;
} }
bool lshiftStatus = false;
bool rshiftStatus = false;
#ifndef GET_KEYBOARD_INPUT_FROM_X11
int keymap[GLFW_KEY_LAST + 1]; int keymap[GLFW_KEY_LAST + 1];
static void static void
@ -1416,9 +1443,6 @@ initkeymap(void)
keymap[GLFW_KEY_MENU] = rsNULL; keymap[GLFW_KEY_MENU] = rsNULL;
} }
bool lshiftStatus = false;
bool rshiftStatus = false;
void void
keypressCB(GLFWwindow* window, int key, int scancode, int action, int mods) keypressCB(GLFWwindow* window, int key, int scancode, int action, int mods)
{ {
@ -1436,6 +1460,266 @@ keypressCB(GLFWwindow* window, int key, int scancode, int action, int mods)
} }
} }
#else
uint32 keymap[512]; // 256 ascii + 256 KeySyms between 0xff00 - 0xffff
bool keyStates[512];
uint32 keyCodeToKeymapIndex[256]; // cache for physical keys
#define KEY_MAP_OFFSET (0xff00 - 256)
static void
initkeymap(void)
{
Display *display = glfwGetX11Display();
int i;
for (i = 0; i < ARRAY_SIZE(keymap); i++)
keymap[i] = rsNULL;
// You can add new ASCII mappings to here freely (but beware that if right hand side of assignment isn't supported on CFont, it'll be blank/won't work on binding screen)
// Right hand side of assigments should always be uppercase counterpart of character
keymap[XK_space] = ' ';
keymap[XK_apostrophe] = '\'';
keymap[XK_ampersand] = '&';
keymap[XK_percent] = '%';
keymap[XK_dollar] = '$';
keymap[XK_comma] = ',';
keymap[XK_minus] = '-';
keymap[XK_period] = '.';
keymap[XK_slash] = '/';
keymap[XK_question] = '?';
keymap[XK_exclam] = '!';
keymap[XK_quotedbl] = '"';
keymap[XK_colon] = ':';
keymap[XK_semicolon] = ';';
keymap[XK_equal] = '=';
keymap[XK_bracketleft] = '[';
keymap[XK_backslash] = '\\';
keymap[XK_bracketright] = ']';
keymap[XK_grave] = '`';
keymap[XK_0] = '0';
keymap[XK_1] = '1';
keymap[XK_2] = '2';
keymap[XK_3] = '3';
keymap[XK_4] = '4';
keymap[XK_5] = '5';
keymap[XK_6] = '6';
keymap[XK_7] = '7';
keymap[XK_8] = '8';
keymap[XK_9] = '9';
keymap[XK_a] = 'A';
keymap[XK_b] = 'B';
keymap[XK_c] = 'C';
keymap[XK_d] = 'D';
keymap[XK_e] = 'E';
keymap[XK_f] = 'F';
keymap[XK_g] = 'G';
keymap[XK_h] = 'H';
keymap[XK_i] = 'I';
keymap[XK_I] = 'I'; // Turkish I problem
keymap[XK_j] = 'J';
keymap[XK_k] = 'K';
keymap[XK_l] = 'L';
keymap[XK_m] = 'M';
keymap[XK_n] = 'N';
keymap[XK_o] = 'O';
keymap[XK_p] = 'P';
keymap[XK_q] = 'Q';
keymap[XK_r] = 'R';
keymap[XK_s] = 'S';
keymap[XK_t] = 'T';
keymap[XK_u] = 'U';
keymap[XK_v] = 'V';
keymap[XK_w] = 'W';
keymap[XK_x] = 'X';
keymap[XK_y] = 'Y';
keymap[XK_z] = 'Z';
// Some of regional but ASCII characters that GTA supports
keymap[XK_agrave] = 0x00c0;
keymap[XK_aacute] = 0x00c1;
keymap[XK_acircumflex] = 0x00c2;
keymap[XK_adiaeresis] = 0x00c4;
keymap[XK_ae] = 0x00c6;
keymap[XK_egrave] = 0x00c8;
keymap[XK_eacute] = 0x00c9;
keymap[XK_ecircumflex] = 0x00ca;
keymap[XK_ediaeresis] = 0x00cb;
keymap[XK_igrave] = 0x00cc;
keymap[XK_iacute] = 0x00cd;
keymap[XK_icircumflex] = 0x00ce;
keymap[XK_idiaeresis] = 0x00cf;
keymap[XK_ccedilla] = 0x00c7;
keymap[XK_odiaeresis] = 0x00d6;
keymap[XK_udiaeresis] = 0x00dc;
// These are 0xff00 - 0xffff range of KeySym's, and subtracting KEY_MAP_OFFSET is needed
keymap[XK_Escape - KEY_MAP_OFFSET] = rsESC;
keymap[XK_Return - KEY_MAP_OFFSET] = rsENTER;
keymap[XK_Tab - KEY_MAP_OFFSET] = rsTAB;
keymap[XK_BackSpace - KEY_MAP_OFFSET] = rsBACKSP;
keymap[XK_Insert - KEY_MAP_OFFSET] = rsINS;
keymap[XK_Delete - KEY_MAP_OFFSET] = rsDEL;
keymap[XK_Right - KEY_MAP_OFFSET] = rsRIGHT;
keymap[XK_Left - KEY_MAP_OFFSET] = rsLEFT;
keymap[XK_Down - KEY_MAP_OFFSET] = rsDOWN;
keymap[XK_Up - KEY_MAP_OFFSET] = rsUP;
keymap[XK_Page_Up - KEY_MAP_OFFSET] = rsPGUP;
keymap[XK_Page_Down - KEY_MAP_OFFSET] = rsPGDN;
keymap[XK_Home - KEY_MAP_OFFSET] = rsHOME;
keymap[XK_End - KEY_MAP_OFFSET] = rsEND;
keymap[XK_Caps_Lock - KEY_MAP_OFFSET] = rsCAPSLK;
keymap[XK_Scroll_Lock - KEY_MAP_OFFSET] = rsSCROLL;
keymap[XK_Num_Lock - KEY_MAP_OFFSET] = rsNUMLOCK;
keymap[XK_Pause - KEY_MAP_OFFSET] = rsPAUSE;
keymap[XK_F1 - KEY_MAP_OFFSET] = rsF1;
keymap[XK_F2 - KEY_MAP_OFFSET] = rsF2;
keymap[XK_F3 - KEY_MAP_OFFSET] = rsF3;
keymap[XK_F4 - KEY_MAP_OFFSET] = rsF4;
keymap[XK_F5 - KEY_MAP_OFFSET] = rsF5;
keymap[XK_F6 - KEY_MAP_OFFSET] = rsF6;
keymap[XK_F7 - KEY_MAP_OFFSET] = rsF7;
keymap[XK_F8 - KEY_MAP_OFFSET] = rsF8;
keymap[XK_F9 - KEY_MAP_OFFSET] = rsF9;
keymap[XK_F10 - KEY_MAP_OFFSET] = rsF10;
keymap[XK_F11 - KEY_MAP_OFFSET] = rsF11;
keymap[XK_F12 - KEY_MAP_OFFSET] = rsF12;
keymap[XK_F13 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F14 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F15 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F16 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F17 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F18 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F19 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F20 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F21 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F22 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F23 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F24 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_F25 - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_KP_0 - KEY_MAP_OFFSET] = rsPADINS;
keymap[XK_KP_1 - KEY_MAP_OFFSET] = rsPADEND;
keymap[XK_KP_2 - KEY_MAP_OFFSET] = rsPADDOWN;
keymap[XK_KP_3 - KEY_MAP_OFFSET] = rsPADPGDN;
keymap[XK_KP_4 - KEY_MAP_OFFSET] = rsPADLEFT;
keymap[XK_KP_5 - KEY_MAP_OFFSET] = rsPAD5;
keymap[XK_KP_6 - KEY_MAP_OFFSET] = rsPADRIGHT;
keymap[XK_KP_7 - KEY_MAP_OFFSET] = rsPADHOME;
keymap[XK_KP_8 - KEY_MAP_OFFSET] = rsPADUP;
keymap[XK_KP_9 - KEY_MAP_OFFSET] = rsPADPGUP;
keymap[XK_KP_Insert - KEY_MAP_OFFSET] = rsPADINS;
keymap[XK_KP_End - KEY_MAP_OFFSET] = rsPADEND;
keymap[XK_KP_Down - KEY_MAP_OFFSET] = rsPADDOWN;
keymap[XK_KP_Page_Down - KEY_MAP_OFFSET] = rsPADPGDN;
keymap[XK_KP_Left - KEY_MAP_OFFSET] = rsPADLEFT;
keymap[XK_KP_Begin - KEY_MAP_OFFSET] = rsPAD5;
keymap[XK_KP_Right - KEY_MAP_OFFSET] = rsPADRIGHT;
keymap[XK_KP_Home - KEY_MAP_OFFSET] = rsPADHOME;
keymap[XK_KP_Up - KEY_MAP_OFFSET] = rsPADUP;
keymap[XK_KP_Page_Up - KEY_MAP_OFFSET] = rsPADPGUP;
keymap[XK_KP_Decimal - KEY_MAP_OFFSET] = rsPADDEL;
keymap[XK_KP_Divide - KEY_MAP_OFFSET] = rsDIVIDE;
keymap[XK_KP_Multiply - KEY_MAP_OFFSET] = rsTIMES;
keymap[XK_KP_Subtract - KEY_MAP_OFFSET] = rsMINUS;
keymap[XK_KP_Add - KEY_MAP_OFFSET] = rsPLUS;
keymap[XK_KP_Enter - KEY_MAP_OFFSET] = rsPADENTER;
keymap[XK_KP_Equal - KEY_MAP_OFFSET] = rsNULL;
keymap[XK_Shift_L - KEY_MAP_OFFSET] = rsLSHIFT;
keymap[XK_Control_L - KEY_MAP_OFFSET] = rsLCTRL;
keymap[XK_Alt_L - KEY_MAP_OFFSET] = rsLALT;
keymap[XK_Super_L - KEY_MAP_OFFSET] = rsLWIN;
keymap[XK_Shift_R - KEY_MAP_OFFSET] = rsRSHIFT;
keymap[XK_Control_R - KEY_MAP_OFFSET] = rsRCTRL;
keymap[XK_Alt_R - KEY_MAP_OFFSET] = rsRALT;
keymap[XK_Super_R - KEY_MAP_OFFSET] = rsRWIN;
keymap[XK_Menu - KEY_MAP_OFFSET] = rsNULL;
// Cache the key codes' key symbol equivelants, otherwise we will have to do it on each frame
// KeyCode is always in [0,255], and represents a physical key
int min_keycode, max_keycode, keysyms_per_keycode;
KeySym *keymap, *origkeymap;
char *keyboardLang = setlocale (LC_CTYPE, NULL);
setlocale(LC_CTYPE, "");
XDisplayKeycodes(display, &min_keycode, &max_keycode);
origkeymap = XGetKeyboardMapping(display, min_keycode, (max_keycode - min_keycode + 1), &keysyms_per_keycode);
keymap = origkeymap;
for (int i = min_keycode; i <= max_keycode; i++) {
int j, lastKeysym;
lastKeysym = keysyms_per_keycode - 1;
while ((lastKeysym >= 0) && (keymap[lastKeysym] == NoSymbol))
lastKeysym--;
for (j = 0; j <= lastKeysym; j++) {
KeySym ks = keymap[j];
if (ks == NoSymbol)
continue;
if (ks < 256) {
keyCodeToKeymapIndex[i] = ks;
break;
} else if (ks >= 0xff00 && ks < 0xffff) {
keyCodeToKeymapIndex[i] = ks - KEY_MAP_OFFSET;
break;
}
}
keymap += keysyms_per_keycode;
}
XFree(origkeymap);
setlocale(LC_CTYPE, keyboardLang);
}
#undef KEY_MAP_OFFSET
void checkKeyPresses()
{
Display *display = glfwGetX11Display();
char keys[32];
XQueryKeymap(display, keys);
for (int i = 0; i < sizeof(keys); i++) {
for (int j = 0; j < 8; j++) {
KeyCode keycode = 8 * i + j;
uint32 keymapIndex = keyCodeToKeymapIndex[keycode];
if (keymapIndex != 0) {
int rsCode = keymap[keymapIndex];
if (rsCode == rsNULL)
continue;
bool pressed = WindowFocused && !!(keys[i] & (1 << j));
// idk why R* does that
if (rsCode == rsLSHIFT)
lshiftStatus = pressed;
else if (rsCode == rsRSHIFT)
rshiftStatus = pressed;
if (keyStates[keymapIndex] != pressed) {
if (pressed) {
RsKeyboardEventHandler(rsKEYDOWN, &rsCode);
} else {
RsKeyboardEventHandler(rsKEYUP, &rsCode);
}
}
keyStates[keymapIndex] = pressed;
}
}
}
}
#endif
// R* calls that in ControllerConfig, idk why // R* calls that in ControllerConfig, idk why
void void
_InputTranslateShiftKeyUpDown(RsKeyCodes *rs) { _InputTranslateShiftKeyUpDown(RsKeyCodes *rs) {
@ -1460,6 +1744,16 @@ cursorEnterCB(GLFWwindow* window, int entered) {
PSGLOBAL(cursorIsInWindow) = !!entered; PSGLOBAL(cursorIsInWindow) = !!entered;
} }
void
windowFocusCB(GLFWwindow* window, int focused) {
WindowFocused = !!focused;
}
void
windowIconifyCB(GLFWwindow* window, int iconified) {
WindowIconified = !!iconified;
}
/* /*
***************************************************************************** *****************************************************************************
*/ */
@ -1712,6 +2006,9 @@ main(int argc, char *argv[])
#endif #endif
{ {
glfwPollEvents(); glfwPollEvents();
#ifdef GET_KEYBOARD_INPUT_FROM_X11
checkKeyPresses();
#endif
#ifndef MASTER #ifndef MASTER
if (gbModelViewer) { if (gbModelViewer) {
// This is TheModelViewerCore in LCS, but TheModelViewer on other state-machine III-VCs. // This is TheModelViewerCore in LCS, but TheModelViewer on other state-machine III-VCs.
@ -1849,7 +2146,7 @@ main(int argc, char *argv[])
case GS_FRONTEND: case GS_FRONTEND:
{ {
if(!glfwGetWindowAttrib(PSGLOBAL(window), GLFW_ICONIFIED)) if(!WindowIconified)
RsEventHandler(rsFRONTENDIDLE, nil); RsEventHandler(rsFRONTENDIDLE, nil);
#ifdef PS2_MENU #ifdef PS2_MENU