c++ - 在 X11 中监听键盘事件而不消耗它们 - 键盘 Hook

标签 c++ linux x11 xlib keyboard-hook

我尝试编写一个程序,它可以 Hook 键盘消息,以便在 Ubuntu (KDE) 中按下时读出每个键的名称;不干扰程序中键盘的正常操作(仅报出键名)。

这是我的程序:

#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

using namespace std;

void SendPressKeyEvent(Display *display, XKeyEvent xkey)
{
    Window current_focus_window;
    int current_focus_revert;
    XGetInputFocus(display, &current_focus_window, &current_focus_revert);
    xkey.type =  KeyPress;
    xkey.display = display;
    xkey.window = current_focus_window;
    xkey.root = DefaultRootWindow(display);
    xkey.subwindow = None;
    xkey.time = 1000 * time(0);
    xkey.x = 0;
    xkey.y = 0;
    xkey.x_root = 0;
    xkey.y_root = 0;
    xkey.same_screen = True;
    XSendEvent(display, InputFocus,  True, KeyPressMask, (XEvent *)(&xkey));
}

void SendReleaseKeyEvent(Display *display, XKeyEvent xkey)
{
    Window current_focus_window;
    int current_focus_revert;
    XGetInputFocus(display, &current_focus_window, &current_focus_revert);
    xkey.type =  KeyRelease;
    xkey.display = display;
    xkey.window = current_focus_window;
    xkey.root = DefaultRootWindow(display);
    xkey.subwindow = None;
    xkey.time = 1000 * time(0);
    xkey.x = 0;
    xkey.y = 0;
    xkey.x_root = 0;
    xkey.y_root = 0;
    xkey.same_screen = True;
    XSendEvent(display, InputFocus, True, KeyReleaseMask, (XEvent *)(&xkey));
}

void *TaskCode(void* arg)
{
    switch(*(int*)arg)
    {
    case 38:
        system("espeak -v en "  "\"a\"");
    }
    return 0;
}

int main()
{
    Display *display = XOpenDisplay(0);
    if(display == 0)
        exit(1);
    XGrabKeyboard(display, DefaultRootWindow(display), True, GrabModeAsync, GrabModeAsync, CurrentTime);
    XEvent event;
    while(true)
    {
        XNextEvent(display, &event);
        if(event.type == Expose)
        {

        }
        if(event.type == KeyPress)
        {
            SendPressKeyEvent(display,event.xkey);
            if(event.xkey.keycode == 38)
            {
                pthread_t thread;
                int thread_arg = event.xkey.keycode;
                pthread_create(&thread,0, TaskCode, (void*) &thread_arg);
            }
        }
        if(event.type == KeyRelease)
            SendReleaseKeyEvent(display,event.xkey);
    }
    XCloseDisplay(display);
}

此程序仅针对键a,可以扩展到其他键。

但是当这个程序运行时,一些程序(例如 Chromium)不会在它们的编辑框中显示 blinker(光标)。所有 KDE 热键也将被禁用。

如何解决这个问题?

最佳答案

这是我的简单粗暴的例子

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <ctype.h>


int main ()
{
    Display* d = XOpenDisplay(NULL);
    Window root = DefaultRootWindow(d);
    Window curFocus;
    char buf[17];
    KeySym ks;
    XComposeStatus comp;
    int len;
    int revert;

    XGetInputFocus (d, &curFocus, &revert);
    XSelectInput(d, curFocus, KeyPressMask|KeyReleaseMask|FocusChangeMask);

    while (1)
    {
        XEvent ev;
        XNextEvent(d, &ev);
        switch (ev.type)
        {
            case FocusOut:
                printf ("Focus changed!\n");
                printf ("Old focus is %d\n", (int)curFocus);
                if (curFocus != root)
                    XSelectInput(d, curFocus, 0);
                XGetInputFocus (d, &curFocus, &revert);
                printf ("New focus is %d\n", (int)curFocus);
                if (curFocus == PointerRoot)
                    curFocus = root;
                XSelectInput(d, curFocus, KeyPressMask|KeyReleaseMask|FocusChangeMask);
                break;

            case KeyPress:
                printf ("Got key!\n");
                len = XLookupString(&ev.xkey, buf, 16, &ks, &comp);
                if (len > 0 && isprint(buf[0]))
                {
                    buf[len]=0;
                    printf("String is: %s\n", buf);
                }
                else
                {
                    printf ("Key is: %d\n", (int)ks);
                }
        }

    }
}

它不可靠,但大部分时间都有效。 (它显示了我现在正在在此框中键入的键)。您可以调查为什么它有时会失败;)原则上它也不能显示热键。热键是抓取的 key ,只有一个客户端可以获得抓取的 key 。除了加载为此目的设计的特殊 X11 扩展(例如 XEvIE)之外,这里什么也做不了。

关于c++ - 在 X11 中监听键盘事件而不消耗它们 - 键盘 Hook ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22749444/

相关文章:

linux - 当我在 Linux 上编译时在 bash 中设置 tenv

C-X11 API : Custom Control Redraw Issue

c++ - Linux 上 X11 图形库的声明问题

fonts - Xresources 中的粗体 xft 字体

c++ - AVL 树 C++ 的 Ostream 运算符

c++ - stdin 和 stdout 是否共享任何资源?

c++ - constexpr 函数在编译时获取值,即使我的变量不是 constexpr

c++ - 如何在 x86 程序集中递增数组?

c++ - 在 Ubuntu(Netbeans) 和 Windows(Visual Studio 2012) 中编译相同的 C++ 代码

linux - 复制所有 ".classpath"文件的linux命令是什么?