【问题标题】:Mouse events callback鼠标事件回调
【发布时间】:2015-08-28 03:11:46
【问题描述】:

我使用的是 WinAPI SetWindowsHookEx 和 OS X Objective-c [NSEvent addLocalMonitorForEventsMatchingMask:handler:],它们都设置了回调,然后我无休止地运行事件循环,并在需要时触发回调。

我只将这个钩子插入到我的进程/应用程序中(但如果我也可以在系统范围内进行操作会很酷)。当用户进行鼠标组合时,我会跟踪他们,如果组合匹配特定模式,它会阻止最后一个鼠标事件并执行特定功能。

我想知道 x11 等价物是什么?

我找到了这个话题:X11 Mouse Movement Event

但这似乎可以监视所有事件,而他只是过滤掉了鼠标事件。这也是一种锁定非回调方法,这没关系,因为我正在从专用线程运行此代码。但理想情况下,我更喜欢回调方法,因为我的主线程必须向该线程发送消息,例如关于活动窗口更改的消息,并且如果它卡在一个循环中,它将永远不会放弃获取活动窗口更改消息。

【问题讨论】:

  • This tutorial 将来可能会有用。 Writing callback functions in XLib 在这种情况下可能对您有用。基本上,您处理事件的方式与在 Windows 中的处理方式相同。但是,您手动过滤事件并最终调用特定的回调函数,就像您在 Windows 中的窗口过程中所做的那样。
  • xAttributes.event_mask = ...你应该建立自己的面具,而不是盲目复制示例。
  • @Noitidart 还有 XCB's mouse movement events 而不是 Xlib,但你是对的。您使用常规消息/事件循环来过滤事件并处理输入,而不是添加挂钩,这类似于在 Windows 中的窗口过程中处理 WM_MOUSEMOVE 消息。您只需根据需要设置事件掩码,将逻辑移至消息循环。如果您认为这似乎比它应该做的更困难,那么 X 与 Windows 根本不同:X 向服务器发送和接收消息; Windows 没有。
  • 使用 pthreads 条件变量。
  • @Noitidart Try it yourself :-) 即使窗口没有输入焦点,也接收到事件,包括点击/点击和移动,尽管它只接收窗口客户区暴露部分的事件,不是隐藏在另一个窗口后面的模糊部分(我的窗口管理器允许我按住 Shift 来单击一个窗口而不给它焦点)。但是,即使离开窗口的客户区,指针拖动仍然存在。因此,您可能会收到额外的XCB_LEAVE_NOTIFY 事件,并且必须对指针拖动进行特殊处理。

标签: x11


【解决方案1】:

如果您希望它在全局范围内工作,您可能必须为此修补内核。一些背景。

我不确定 OS X,但 Windows 是一个非常不安全的操作系统。例如,每个进程都可以通过SetWindowsHookEx 安装一个钩子并监控鼠标和键盘——它基本上是一个按键记录器。几年前,没有防病毒工具会报告这一点。不知道今天怎么样了。

但从本质上讲,Windows 是一个协作操作系统。这意味着 GUI 运行计算机。具有控制权的应用程序(= 活动的应用程序)获取所有事件。如果应用程序锁定,Windows 将锁定(鼠标和键盘已失效)。如果您在另一个窗口中单击并且活动应用程序显示“否”,则新窗口不会变为活动状态。我记得曾经做过一些事情来让事情变得更好,但这也是过去 Windows 如此不稳定的原因之一——某个应用程序中出现了一个错误,整个系统就会出现错误。

在 Unix 上,内核并不关心用户界面(它有自己的问题)。相反,有一个称为 X 服务器的程序(一个正常进程)。从内核的角度来看,这个程序与其他程序没有任何不同。内核处理鼠标和键盘。如果 X 锁定,键盘仍然可以工作(例如,您可以切换到文本控制台)。

这意味着 X 会读取像 /dev/input/mice 这样的设备(它会合并来自当前连接到您计算机的所有鼠标的所有鼠标事件)。您的键盘位于/dev/input/by-id/ 下方。这些设备由 X 内核维护并使用。X 只是这里的一个客户。内核作为控件。

如果一个程序使用 X 库,这意味着它会创建一个到 X 服务器的套接字连接。服务器处理内核设备发送的鼠标和键盘事件。这些被转换成XEvent 结构并发送给客户端。渲染发生在服务端,客户端向服务端发送绘图命令。

这使得从 X 客户端控制鼠标和键盘变得很困难——它离源头很远。如果您创建人为事件,它们会被标记为“合成”并且大多数程序会忽略这些 - 它们是安全威胁。

上面列出的设备只能被root读取,所以听用户做的每件事也不容易。

总而言之,如果您想为 X 显示器上的所有程序执行此操作,您将需要以 root 运行的程序,并且可能需要一个内核模块,它允许您注入事件并将它们作为新的事件设备公开在/dev/input/ 下。你需要配置 X 来收听你的新设备。即便如此,我认为您不能从其他设备取消事件,只需添加您自己的。

如果您只需要一个应用程序,那么事情就容易多了。首先,您需要为您创建的所有窗口添加一个事件侦听器。在处理程序中,您可以分析鼠标移动。使用必要的Button*Mask*MotionMask 位来获取您需要的事件。

如果您不关心安全性,则可以让您的应用程序接受合成事件并注入您的新事件。问题是 X 没有“取消事件”的概念。您也许可以使用事件传播规则来实现您想要的;请参阅此页面上的“设备事件传播”:http://menehune.opt.wfu.edu/Kokua/Irix_6.5.21_doc_cd/usr/share/Insight/library/SGI_bookshelves/SGI_Developer/books/XLib_PG/sgi_html/ch08.html

您可能还应该阅读第 2 章,其中概述了 X。

还有一件事:X 不是线程安全的。您不得从主线程外部调用 X 函数。如果你这样做了,你会得到错误或者你的程序会崩溃。

相关:

【讨论】:

  • 哇,非常感谢我现在正在阅读。顺便说一句,你是否使用 Firefox 我正在尝试使用 c 和 x11 而不是 javascript 来制作这个插件:addons.mozilla.org/en-US/firefox/addon/mousecontrol 因为 javascript 无法从顶层阻止鼠标事件,所以像 flash 和其他插件这样的东西会窃取焦点。但是,如果您在那里试用 mousecontrol 版本,它会让您完全了解我想要做什么。 :) 我不太善于交流想法:(
  • 我正在阅读这篇文章,非常感谢。我正在通过 Firefox 的 ctypes 运行此代码。所以理想情况下只需要在当前 Firefox 进程中挂钩/监视和阻止鼠标事件(用户可能打开了多个 Firefox)。仍在阅读,但只是想在阅读时更新此内容 :) 感谢您对我也了解 Windows 的非常深入的回复 :)
  • 啊,好吧,我想我明白了。所以我要从froget 系统方面,专注于应用程序。然后我要创建一个窗口,然后使用 XGrabPointer 将鼠标事件转移(我不能阻止我只能转移)到这个窗口,这将有效地阻止它在用户所在的窗口中。我通过添加事件监听器XSelectInput 在我的应用程序中打开的每个窗口上? :) 正如我在这里所做的那样:github.com/Noitidart/MouseControl/blob/master/modules/workers/… ?
  • 嘿@Aron 带有 null 参数的 gdk_window_add_filter 如何工作?它使用 x no?有没有地方可以查看 gdk 函数在做什么? developer.gnome.org/gdk3/stable/…
  • 我对 GTK+ 了解不多。但是,如果您可以在 Firefox 中运行 C 代码,更好的解决方案可能是本地事件循环:marc.info/?l=gtk-app-devel&m=97373050608317&w=2 您还应该查看模式窗口:developer.gnome.org/gtk3/stable/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-25
  • 2016-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多