Skip to content

Commit

Permalink
feature: linux/win: add global detection options for keyboard (#15)
Browse files Browse the repository at this point in the history
* feature: linux/win: add global detection options for keyboard

- #14

add global detection options for keyboard
- linux: use x11 extension - XInput2
- windows: enable global detection permissions

Signed-off-by: SPeak <speakshen@163.com>

* update

---------

Signed-off-by: SPeak <speakshen@163.com>
  • Loading branch information
Sunrisepeak authored Mar 11, 2024
1 parent 9b815d3 commit 5a3d3f5
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 20 deletions.
2 changes: 1 addition & 1 deletion docs/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
```bash
sudo add-apt-repository ppa:xmake-io/xmake
sudo apt-get update
sudo apt-get install g++ gdb xmake make mesa-common-dev git -y
sudo apt-get install g++ gdb xmake make mesa-common-dev git libx11-dev libxi-dev -y
```

### Windows
Expand Down
1 change: 1 addition & 0 deletions include/PAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class PAL {
public:
static bool gamepadConnected;
static dstruct::Vector<std::string> KeyMapTable;
static unsigned int globalDetectWinID;
};

}
Expand Down
64 changes: 47 additions & 17 deletions platform/linux_platform_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
// X11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XInput2.h> // libxi-dev

namespace khistory {

static Display* display = nullptr;
static Window gCurrentWindowId = 0;
static int gExtensionOpcode = 0;

static void list_windows(Display *display, Window root, int depth, dstruct::Vector<PAL::WindowInfo> &wInfos) {
Window parent;
Expand Down Expand Up @@ -78,12 +81,27 @@ void PAL::platformInit() {

DSTRUCT_ASSERT(display != nullptr);

PAL::globalDetectWinID = DefaultRootWindow(display);

// init key map table
for (int keycode = 0; keycode < 256; keycode++) {
char *keyName = XKeysymToString(XKeycodeToKeysym(display, keycode, 0));
if (keyName) PAL::KeyMapTable[keycode] = keyName;
for (char& c : PAL::KeyMapTable[keycode]) c = std::toupper(c);
}

// Check for XInput 2 extension
int event, error;
if (!XQueryExtension(display, "XInputExtension", &gExtensionOpcode, &event, &error)) {
printf("X Input extension not available. (tips: sudo apt install libxi-dev)\n");
}

// Check the version of XInput
int major = 2, minor = 0;
if (XIQueryVersion(display, &major, &minor) == BadRequest) {
printf("XInput2 not available. Server supports version %d.%d\n", major, minor);
}

}

dstruct::Vector<PAL::WindowInfo> PAL::platformWindowInfos() {
Expand All @@ -98,44 +116,56 @@ dstruct::Vector<PAL::WindowInfo> PAL::platformWindowInfos() {
}

dstruct::Vector<PAL::KeyData> PAL::platformKeyDetect(unsigned int wID) {
static Window currentWindowId = DefaultRootWindow(display);
dstruct::Vector<PAL::KeyData> keyEventVec;
PAL::KeyData kd { 0, false };
XEvent event;

//printf ("platformKeyDetect\n");

if (gCurrentWindowId != wID) {
//printf ("platformKeyDetect: window id, from %ld to %ld\n", gCurrentWindowId, wID);

// Listen for XI_KeyPress events
XIEventMask evmasks[1];
unsigned char mask[(XI_LASTEVENT + 7)/8] = { 0 };

evmasks[0].deviceid = XIAllDevices;
evmasks[0].mask_len = sizeof(mask);
evmasks[0].mask = mask;

XISetMask(evmasks[0].mask, XI_KeyPress);
XISetMask(evmasks[0].mask, XI_KeyRelease);

XISelectEvents(display, wID, evmasks, 1);
XSync(display, false); // sync event set

if (currentWindowId != wID) {
XSelectInput(display, currentWindowId, 0);
currentWindowId = wID;
XSelectInput(display, currentWindowId, KeyPressMask | KeyReleaseMask);
//printf ("platformKeyDetect: window id, from %ld to %ld\n", currentWindowId, wID);
gCurrentWindowId = wID;
}

while(XEventsQueued(display, QueuedAfterFlush) > 0) {
XNextEvent(display, &event);
kd.key = event.xkey.keycode;
switch (event.type) {
case KeyPress:
if (event.xcookie.type == GenericEvent && event.xcookie.extension == gExtensionOpcode) {
XGetEventData(display, &event.xcookie);
XIDeviceEvent* xideviceevent = reinterpret_cast<XIDeviceEvent*>(event.xcookie.data);
kd.key = xideviceevent->detail; // event.xkey.keycode;
if (event.xcookie.evtype == XI_KeyPress) {
kd.pressed = true;
break;
case KeyRelease:
} else if (event.xcookie.evtype == XI_KeyRelease) {
kd.pressed = false;
break;
default: {
//printf ("Other Event...!\n");
//DSTRUCT_ASSERT(false);
}
//printf("key %ld-%d: %d\n", event.xkey.keycode, kd.pressed, xideviceevent->detail);
XFreeEventData(display, &event.xcookie);
keyEventVec.push(kd);
}
keyEventVec.push(kd);
}

//printf ("platformKeyDetect end");
return keyEventVec;
}

void PAL::platformDeinit() {
//XUngrabKeyboard(display, CurrentTime);
//if (gCurrentWindowId == PAL::globalDetectWinID)
// XUngrabKeyboard(display, CurrentTime);
// 关闭 X11 连接
XCloseDisplay(display);
display = nullptr;
Expand Down
7 changes: 6 additions & 1 deletion platform/win_platform_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam); // k

void PAL::platformInit() {
PAL::gamepadConnected = false;
PAL::globalDetectWinID = 'K' + 'H' + 'i' + 's' + 't' + 'o' + 'r' + 'y';
gTargetWindowID = 0;
gKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, NULL, 0);
DSTRUCT_ASSERT(gKeyboardHook != NULL);
Expand Down Expand Up @@ -185,7 +186,11 @@ LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
printf("%d %d, %s\n", reinterpret_cast<unsigned int>(hWnd), gTargetWindowID, buf);
#endif
// verify window id & test, is it other programe injected?
if (reinterpret_cast<unsigned int>(hWnd) == gTargetWindowID /* && (pKbdStruct->flags & LLKHF_INJECTED) == 0 */) {
if (
gTargetWindowID == PAL::globalDetectWinID ||
reinterpret_cast<unsigned int>(hWnd) == gTargetWindowID
/* && (pKbdStruct->flags & LLKHF_INJECTED) == 0 */
) {
PAL::KeyData kd;
kd.key = pKbdStruct->scanCode;
if (wParam == WM_KEYDOWN) {
Expand Down
6 changes: 5 additions & 1 deletion src/KeyHistory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,11 @@ void KeyHistory::_drawControlImpl() {
ImGui::SameLine();

if (ImGui::BeginCombo(" <- window", windowName.c_str(), 0)) {
auto currentWindowList = TargetWindowKeyDetect::getInstance().getWindowInfoList();
dstruct::Vector<PAL::WindowInfo> currentWindowList = TargetWindowKeyDetect::getInstance().getWindowInfoList();
currentWindowList.push_back(PAL::WindowInfo{
.id = PAL::globalDetectWinID,
.name = "Global Detect(Note: don't use when input passwd)"
});
TargetWindowKeyDetect::getInstance().setTargetWindow({0, ""});
isListening = false;
for (int n = 0; n < currentWindowList.size(); n++) {
Expand Down
1 change: 1 addition & 0 deletions src/PAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

dstruct::Vector<std::string> khistory::PAL::KeyMapTable(KEY_NUMBERS, "");
bool khistory::PAL::gamepadConnected = false;
unsigned int khistory::PAL::globalDetectWinID = 0;

namespace khistory {

Expand Down

0 comments on commit 5a3d3f5

Please sign in to comment.