Linux X11 - 全局键盘挂钩

2023-12-24

是否有可能(或如何)创建一个像 Windows 中的全局钩子(SetWindowsHookEx())一样工作的机制(在 Linux X11、C++ 中)?

我希望能够赶上关键事件,但进一步传播的可能性。我正在尝试使用XGrabKey https://stackoverflow.com/questions/144901/system-wide-keyboard-hook-on-x-under-linux解决方案(如xbindkeys http://www.nongnu.org/xbindkeys/xbindkeys.html)但是当我设置捕获关键事件时,该事件被“消耗”。

该机制的要求如下:

  1. 全局/系统范围 - 无论具有焦点的窗口如何捕获事件
  2. “接住”和“接过”的可能性
  3. 一定是相当快的

示例代码如下所示:

bool myFlagIsSet = false;
XEvent event;
while (true) {
    while (XPending(display) > 0) {
        usleep(SLEEP_TIME);
    }

    XNextEvent(display, &event);
    switch (e.type) {
        case KeyPress:
            if (myFlagIsSet) {
                //do not propagate
            }
            // propagate
            break;
        case KeyRelease:
            if (myFlagIsSet) {
                //do not propagate
            }
            // propagate
            break;
    }
}

在 Windows 上我简单地写道:

if(event.isConsumed()) {
    return LRESULT(1);
}
//...
return CallNextHookEx(hookHandle, nCode, wParam, lParam);

我还尝试过使用 XUngrabKey 和 XSendEvent:

switch (event.type) {
    case KeyPress:
        if (myFlagIsSet) {
            //do not propagate
        }
        // propagate
        XUngrabKey(...);
        XSendEvent(..., &event);
        XGrabKey(...);
        break;
    case KeyRelease:
        ...
    }

不幸的是,由于我未知的原因,XSendEvent - 即使 XGrabKey 行被注释,也不要发送此事件。

这种方法有可能成功完成吗?

如果我注定失败,请建议其他方法

EDIT

我想使用 Compiz 窗口管理器在 Ubuntu Gnome 上实现此功能


尝试从此页面编译简单的代码:

http://webhamster.ru/site/page/index/articles/comp/367 http://webhamster.ru/site/page/index/articles/comp/367

这是获取全局键盘事件的示例。这个小应用程序的工作原理是xinput.

备注1:将设备ID写入mian.cpp(通过运行不带参数的xinput获取ID):

sprintf(deviceId, "9");

备注2:编译命令:

gcc ./main.cpp -lstdc++ -lX11 -lXext -lXi

备注 3:编译之前,安装libxi-dev包:

apt-get install libxi-dev

File main.h

#include <X11/Xlib.h>
#include <X11/extensions/XInput.h>

#ifdef HAVE_XI2
#include <X11/extensions/XInput2.h>
#endif

#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>

extern int xi_opcode; /* xinput extension op code */

XDeviceInfo* find_device_info( Display *display, char *name, Bool only_extended);

#if HAVE_XI2
XIDeviceInfo* xi2_find_device_info(Display *display, char *name);
int xinput_version(Display* display);
#endif

File main.cpp

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include "main.h"
#include <ctype.h>
#include <string.h>

using namespace std;

int xi_opcode;

#define INVALID_EVENT_TYPE -1

static int motion_type = INVALID_EVENT_TYPE;
static int button_press_type = INVALID_EVENT_TYPE;
static int button_release_type = INVALID_EVENT_TYPE;
static int key_press_type = INVALID_EVENT_TYPE;
static int key_release_type = INVALID_EVENT_TYPE;
static int proximity_in_type = INVALID_EVENT_TYPE;
static int proximity_out_type = INVALID_EVENT_TYPE;

static int register_events(Display *dpy,
                           XDeviceInfo *info,
                           char *dev_name,
                           Bool handle_proximity)
{
    int            number = 0;    /* number of events registered */
    XEventClass        event_list[7];
    int            i;
    XDevice        *device;
    Window        root_win;
    unsigned long    screen;
    XInputClassInfo    *ip;

    screen = DefaultScreen(dpy);
    root_win = RootWindow(dpy, screen);

    device = XOpenDevice(dpy, info->id);

    if (!device) {
    printf("unable to open device '%s'\n", dev_name);
    return 0;
    }

    if (device->num_classes > 0) {
    for (ip = device->classes, i=0; i<info->num_classes; ip++, i++) {
        switch (ip->input_class) {
        case KeyClass:
        DeviceKeyPress(device, key_press_type, event_list[number]); number++;
        DeviceKeyRelease(device, key_release_type, event_list[number]); number++;
        break;

        case ButtonClass:
        DeviceButtonPress(device, button_press_type, event_list[number]); number++;
        DeviceButtonRelease(device, button_release_type, event_list[number]); number++;
        break;

        case ValuatorClass:
        DeviceMotionNotify(device, motion_type, event_list[number]); number++;
        if (handle_proximity) {
            ProximityIn(device, proximity_in_type, event_list[number]); number++;
            ProximityOut(device, proximity_out_type, event_list[number]); number++;
        }
        break;

        default:
        printf("unknown class\n");
        break;
        }
    }

    if (XSelectExtensionEvent(dpy, root_win, event_list, number)) {
        printf("error selecting extended events\n");
        return 0;
    }
    }
    return number;
}


static void print_events(Display *dpy)
{
    XEvent        Event;

    setvbuf(stdout, NULL, _IOLBF, 0);

    while(1) {
    XNextEvent(dpy, &Event);

    if (Event.type == motion_type) {
        int    loop;
        XDeviceMotionEvent *motion = (XDeviceMotionEvent *) &Event;

        printf("motion ");

        for(loop=0; loop<motion->axes_count; loop++) {
        printf("a[%d]=%d ", motion->first_axis + loop, motion->axis_data[loop]);
        }
        printf("\n");
    } else if ((Event.type == button_press_type) ||
           (Event.type == button_release_type)) {
        int    loop;
        XDeviceButtonEvent *button = (XDeviceButtonEvent *) &Event;

        printf("button %s %d ", (Event.type == button_release_type) ? "release" : "press  ",
           button->button);

        for(loop=0; loop<button->axes_count; loop++) {
        printf("a[%d]=%d ", button->first_axis + loop, button->axis_data[loop]);
        }
        printf("\n");
    } else if ((Event.type == key_press_type) ||
           (Event.type == key_release_type)) {
        int    loop;
        XDeviceKeyEvent *key = (XDeviceKeyEvent *) &Event;

        printf("key %s %d ", (Event.type == key_release_type) ? "release" : "press  ",
           key->keycode);

        for(loop=0; loop<key->axes_count; loop++) {
        printf("a[%d]=%d ", key->first_axis + loop, key->axis_data[loop]);
        }
        printf("\n");
    } else if ((Event.type == proximity_out_type) ||
           (Event.type == proximity_in_type)) {
        int    loop;
        XProximityNotifyEvent *prox = (XProximityNotifyEvent *) &Event;

        printf("proximity %s ", (Event.type == proximity_in_type) ? "in " : "out");

        for(loop=0; loop<prox->axes_count; loop++) {
        printf("a[%d]=%d ", prox->first_axis + loop, prox->axis_data[loop]);
        }
        printf("\n");
    }
    else {
        printf("what's that %d\n", Event.type);
    }
    }
}


// Определение версии библиотеки расширений, установленной для X11
int xinput_version(Display    *display)
{
    XExtensionVersion    *version;
    static int vers = -1;

    if (vers != -1)
        return vers;

    version = XGetExtensionVersion(display, INAME);

    if (version && (version != (XExtensionVersion*) NoSuchExtension)) {
    vers = version->major_version;
    XFree(version);
    }

#if HAVE_XI2
    /* Announce our supported version so the server treats us correctly. */
    if (vers >= XI_2_Major)
    {
        const char *forced_version;
        int maj = 2,
            min = 0;

#if HAVE_XI22
        min = 2;
#elif HAVE_XI21
        min = 1;
#endif

        forced_version = getenv("XINPUT_XI2_VERSION");
        if (forced_version) {
            if (sscanf(forced_version, "%d.%d", &maj, &min) != 2) {
                fprintf(stderr, "Invalid format of XINPUT_XI2_VERSION "
                                "environment variable. Need major.minor\n");
                exit(1);
            }
            printf("Overriding XI2 version to: %d.%d\n", maj, min);
        }

        XIQueryVersion(display, &maj, &min);
    }
#endif

    return vers;
}


// Поиск информации об устройстве
XDeviceInfo* find_device_info(Display *display,
                              char *name,
                              Bool only_extended)
{
    XDeviceInfo *devices;
    XDeviceInfo *found = NULL;
    int        loop;
    int        num_devices;
    int        len = strlen(name);
    Bool    is_id = True;
    XID        id = (XID)-1;

    for(loop=0; loop<len; loop++) {
    if (!isdigit(name[loop])) {
        is_id = False;
        break;
    }
    }

    if (is_id) {
    id = atoi(name);
    }

    devices = XListInputDevices(display, &num_devices);

    for(loop=0; loop<num_devices; loop++) {
    if ((!only_extended || (devices[loop].use >= IsXExtensionDevice)) &&
        ((!is_id && strcmp(devices[loop].name, name) == 0) ||
         (is_id && devices[loop].id == id))) {
        if (found) {
            fprintf(stderr,
                    "Warning: There are multiple devices named '%s'.\n"
                    "To ensure the correct one is selected, please use "
                    "the device ID instead.\n\n", name);
        return NULL;
        } else {
        found = &devices[loop];
        }
    }
    }
    return found;
}


int test(Display *display, char *deviceId)
{
    XDeviceInfo *info;

    Bool handle_proximity = True;

    info = find_device_info(display, deviceId, True);

    if(!info)
    {
      printf("unable to find device '%s'\n", deviceId);
      exit(1);
    }
    else
    {
      if(register_events(display, info, deviceId, handle_proximity))
         print_events(display);
      else
      {
        fprintf(stderr, "no event registered...\n");
        exit(1);
      }
    }

    return 0;
}


int main()
{
  Display *display;
  int event, error;

  // Инициируется указатель на текущий дисплей
  display = XOpenDisplay(NULL);
  if (display == NULL)
  {
    printf("Unable to connect to X server\n");
    exit(1);
  }

  // Проверяется наличие расширений
  if(!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error))
  {
    printf("X Input extension not available.\n");
    exit(1);
  }

  // Проверяется версия расширения, она не должна быть нулевой
  if(!xinput_version(display))
  {
    printf("%s extension not available\n", INAME);
    exit(1);
  }

  char deviceId[10];
  sprintf(deviceId, "9");

  test(display, deviceId);

  XSync(display, False);
  XCloseDisplay(display);

  return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux X11 - 全局键盘挂钩 的相关文章

  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • SSH,运行进程然后忽略输出

    我有一个命令可以使用 SSH 并在 SSH 后运行脚本 该脚本运行一个二进制文件 脚本完成后 我可以输入任意键 本地终端将恢复到正常状态 但是 由于该进程仍在我通过 SSH 连接的计算机中运行 因此任何时候它都会登录到stdout我在本地终
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • C 编程:带有数组的函数

    我正在尝试编写一个函数 该函数查找行为 4 列为 4 的二维数组中的最大值 其中二维数组填充有用户输入 我知道我的主要错误是函数中的数组 但我不确定它是什么 如果有人能够找到我出错的地方而不是编写新代码 我将不胜感激 除非我刚去南方 我的尝
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • C++ 中的参考文献

    我偶尔会在 StackOverflow 上看到代码 询问一些涉及函数的重载歧义 例如 void foo int param 我的问题是 为什么会出现这种情况 或者更确切地说 你什么时候会有 对参考的参考 这与普通的旧参考有何不同 我从未在现
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat

随机推荐

  • gke nginx lb 运行状况检查/无法使所有实例处于“健康”状态

    使用nginxnginx ingress controller 0 9 0 下面是谷歌云负载均衡器的永久状态 基本上 单个健康节点是运行 nginx ingress controller pod 的节点 除了在这个屏幕上看起来不太好之外 一
  • Java XML 解析 - 合并 xi:include 的输出

    我有一个 XML 文件 其中包含以下内容
  • Java 线程基础知识

    下面两个线程调用有什么区别 这两个调用的行为会类似吗 注意 我没有同时使用 1 和 2 这是最好的选择 private void startConnections ServerThread server new ServerThread s
  • 从packages.config安装私有源Nuget包

    我在我们的一台内部服务器上有一个私人 nuget feed 我可以像这样从命令行安装此提要中的包 nuget install PackageName source DevServer NugetFeed 但是 如果我尝试从我们的packag
  • 将 Express Router 与 Next.js 结合使用

    我正在尝试将 Express Router 与 Next js 结合使用定制快递服务器示例 https github com zeit next js blob master examples custom server express s
  • 如何修复“找不到默认 Python”错误

    我在 Windows 服务器 64 位 中使用 python 它由另一个用户安装在他自己的目录中C user userx AppData Local Programs Python Python36 所有其他用户 不包括我 都可以在此服务器
  • codeigniter 指定限制为 NULL 在最新 CI 版本 2.1.2 中不起作用

    我有以下获取作者列表在我的 Codeigniter 模型之一中运行 function get authors list limit offset data array this gt db gt select gt from authors
  • 如何从 shell 脚本编辑 kubernetes 资源

    我浏览了文档来使用以下命令编辑 kubernetes 资源kubectl edit https kubernetes v1 4 github io docs user guide kubectl kubectl edit 命令 执行命令后
  • 重定向路线并显示消息

    我想知道是否有办法重定向路线或返回Response与数据并在另一个页面上获取它loader功能 基本上 我试图使用表单创建一个新对象 并重定向到另一个我想要显示创建成功消息的页面 这是一个表单页面示例 我正在尝试发送消息Response b
  • 如何知道topojson是否安装并正常工作?

    如何知道topojson是否安装好并且工作正常 一个要转换的小文件示例将不胜感激 包含源和预期结果 如果您还没有偶然发现这一点 我发现它是整个过程的一个很好的演练 http bost ocks org mike map http bost
  • 如何在 Java 中使用 Selenium WebDriver 和/或 Sikuli 平滑滚动

    作为测量 Web 应用程序 FPS 的测试套件的一部分 我需要执行网页的平滑滚动 也就是说 与用户抓住滚动条并用鼠标移动它时的平滑度相同 到目前为止 我已经尝试使用 sikuli 模拟按键 即多次按向上 向下箭头键来滚动整个页面 我也尝试过
  • Prometheus基于Label的过滤

    如何在Prometheus查询中添加标签过滤器 kube pod 信息 kube pod info created by kind ReplicaSet created by name alertmanager 6d9f74d4c5 ins
  • 通过 facebook graph api 创建事件

    有没有办法通过代码创建 facebook 事件 截至今天 请参阅文档 for v2 0 https developers facebook com docs graph api reference v1 0 event for v1 0 h
  • Spring 5 功能性 Web 框架无法与 Eureka 客户端一起使用

    当我启用微服务环境 Config Server Service Registry Eureka Gateway Zuul 时 Spring 5 功能 Web 框架无法工作 我有一个 Maven Spring Boot v 2 0 0 M3
  • 没有提交消息的 Git 提交

    如何在不指定提交消息的情况下提交更改 为什么默认需要它 git 通常需要非空消息 因为提供有意义的提交消息是良好开发实践和良好存储库管理的一部分 提交消息的第一行在 git 中随处可见 欲了解更多信息 请阅读 关于 Git 提交消息的注释
  • posmax:类似于 argmax,但给出了 f[x] 最大的元素 x 的位置

    Mathematica 有一个内置函数ArgMax http reference wolfram com mathematica ref ArgMax html对于无限域上的函数 基于标准数学定义 http en wikipedia org
  • 添加预览到 html 链接标签

    当我们共享一些链接时 它会显示一个链接预览图像和一些文本 我们如何添加到我们的http链接 希望我的问题很清楚 OG 可能就是您正在寻找的东西 它是一组具有特定属性的元标记 它们处理链接共享后显示的标题 描述和图像 更多这里 about O
  • 如何在Django中存储图像文件?

    Django 中存储图像文件的典型场景是什么 更具体地说 图像是否直接存储在本地文件系统或 Amazon S3 上的数据库 blob 例如 MongoDB GridFS 中 对于这三种情况 是否有工具或 django 软件包可用于简化您存储
  • 为什么 VS Code 中的 Nodejs 断点会根据完整路径是否出现在选项卡标题中而被禁用?

    我的 Mocha 测试中的断点在一个 VS Code 选项卡中的完全相同的行上设置时有效 但在另一个选项卡中则无效 区别 如果选项卡中显示完整路径 则断点有效 屏幕截图中的第二项 但是 如果没有路径的文件名出现在选项卡标题中 则断点在执行期
  • Linux X11 - 全局键盘挂钩

    是否有可能 或如何 创建一个像 Windows 中的全局钩子 SetWindowsHookEx 一样工作的机制 在 Linux X11 C 中 我希望能够赶上关键事件 但进一步传播的可能性 我正在尝试使用XGrabKey https sta