linux应用程序抢占键盘,Linux全局事件监听技术

// 因为 XRecord 的事件循环会堵塞当前线程,避免监听事件的时候应用程序卡主

// 我们建立一个继承于 QThread 的EventMonitor类,通过子线程进行事件监听操作

EventMonitor::EventMonitor(QObject *parent) : QThread(parent)

{

// 鼠标按下标志位,用于识别鼠标的拖拽操作

isPress = false;

}

void EventMonitor::run()

{

// 创建记录 XRecord 协议的 X 专用连接

Display* display = XOpenDisplay(0);

// 连接打开检查

if (display == 0) {

fprintf(stderr, "unable to open display\n");

return;

}

// 初始化 XRecordCreateContext 所需的 XRecordClientSpec 参数

// XRecordAllClients 的意思是 "记录所有 X Client" 的事件

XRecordClientSpec clients = XRecordAllClients;

// 创建 XRecordRange 变量,XRecordRange 用于控制记录事件的范围

XRecordRange* range = XRecordAllocRange();

// 记录事件范围检查

if (range == 0) {

fprintf(stderr, "unable to allocate XRecordRange\n");

return;

}

// 初始化记录事件范围,范围开头设置成 KeyPress, 范围结尾设置成 MotionNotify 后

// 事件的类型就包括 KeyPress、KeyRelase、ButtonPress、ButtonRelease、MotionNotify五种事件

memset(range, 0, sizeof(XRecordRange));

range->device_events.first = KeyPress;

range->device_events.last  = MotionNotify;

// 根据上面的记录客户端类型和记录事件范围来创建 “记录上下文”

// 然后把 XRecordContext 传递给 XRecordEnableContext 函数来开启事件记录循环

XRecordContext context = XRecordCreateContext (display, 0, &clients, 1, &range, 1);

if (context == 0) {

fprintf(stderr, "XRecordCreateContext failed\n");

return;

}

// 释放 range 指针

XFree(range);

// XSync 的作用就是把上面的 X 代码立即发给 X Server

// 这样 X Server 接受到事件以后会立即发送给 XRecord 的 Client 连接

XSync(display, True);

// 建立一个专门读取 XRecord 协议数据的 X 链接

Display* display_datalink = XOpenDisplay(0);

// 连接打开检查

if (display_datalink == 0) {

fprintf(stderr, "unable to open second display\n");

return;

}

// 调用 XRecordEnableContext 函数建立 XRecord 上下文

// XRecordEnableContext 函数一旦调用就开始进入堵塞时的事件循环,直到线程或所属进程结束

// X Server 事件一旦发生就传递给事件处理回调函数

if (!XRecordEnableContext(display_datalink, context,  callback, (XPointer) this)) {

fprintf(stderr, "XRecordEnableContext() failed\n");

return;

}

}

// handleRecordEvent 函数的wrapper,避免 XRecord 代码编译不过的问题

void EventMonitor::callback(XPointer ptr, XRecordInterceptData* data)

{

((EventMonitor *) ptr)->handleRecordEvent(data);

}

// 真实处理 X 事件监听的回调函数

void EventMonitor::handleRecordEvent(XRecordInterceptData* data)

{

if (data->category == XRecordFromServer) {

// 得到 xEvent 对象

xEvent * event = (xEvent *)data->data;

switch (event->u.u.type) {

case ButtonPress:

// 过滤掉滚轮事件后,发送 buttonPress 信号

if (filterWheelEvent(event->u.u.detail)) {

isPress = true;

emit buttonPress(

event->u.keyButtonPointer.rootX,

event->u.keyButtonPointer.rootY);

}

break;

case MotionNotify:

// 只有在按下鼠标的时候移动,才发送 buttonDrag 信号

if (isPress) {

emit buttonDrag(

event->u.keyButtonPointer.rootX,

event->u.keyButtonPointer.rootY);

}

break;

case ButtonRelease:

// 过滤掉滚轮事件后,发送 buttonRelase 信号

if (filterWheelEvent(event->u.u.detail)) {

isPress = false;

emit buttonRelease(

event->u.keyButtonPointer.rootX,

event->u.keyButtonPointer.rootY);

}

break;

case KeyPress:

// 发送 keyPress 信号,附带按键的 code

emit keyPress(((unsigned char*) data->data)[1]);

break;

case KeyRelease:

// 发送 keyRelease 信号,附带按键的 code

emit keyRelease(((unsigned char*) data->data)[1]);

break;

default:

break;

}

}

// 资源释放

fflush(stdout);

XRecordFreeData(data);

}

// 过滤滚轮事件

bool EventMonitor::filterWheelEvent(int detail)

{

return detail != WheelUp && detail != WheelDown && detail != WheelLeft && detail != WheelRight;

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值