Qt是一个跨平台开发的框架,可以实现一套代码多平台编译运行。但是有时候我们想实现的功能却和平台深度挂钩,比如本文想要描述的键盘钩子,也就是KeyBoard Hook。

在Windows平台开发时,如果我们需要监听键盘的操作或者屏蔽一些键盘操作时,比较容易的办法就是使用Windows 自带的API,包含SetWindowsHookEx、CallNextHookEx、UnhookWindowsHookEx。

例如:QT Windows平台屏蔽按键事件 自定义拦截按键输入

但是linux系统下是没有这些API供我们使用的,那么在使用Qt进行扩平台开发时,我们该如何做呢?

背景

Qt应用运行时,键盘按下导致程序异常操作,需要在程序整个运行期间拦截某些原生的按键响应。

焦点

Qt键盘事件属于Qt事件系统,所以事件系统中所有规则对按键事件都有效。一开始我就因为焦点不在窗口,导致对错误排查方向错误。

下面关注点在按键特有的部分:

focus

一个拥有焦点(focus)的QWidget才可以接受键盘事件。有输入焦点的窗口是活动窗口或活动窗口子窗口或子子窗口等。

焦点移动的方式有以下几种:

按下Tab或Shift+Tab
注意:文本编译器(一般需要插入Tab),或者WebView(需要Tab来移动超链接焦点) 等

Qt中,需要输入Tab的地方可以用 Ctrl+Tab 或 Ctrl+Shift+Tab 替代。
点击一个QWidget
建议:只对接受文本输入的Widget启用该功能
按下键盘的快捷键
QLabel::setBuddy(), QGroupBox,以及 QTabBar 支持
使用鼠标滚轮
用户移动焦点
程序将决定被设置focus的Widget的哪一个子Widget获得焦点
注意:如果一个 Widget 已经 grabKeyboard,所有键盘事件将发送到该Widget而不是获得焦点的Widget

focusPolicy

一个QWidget获得焦点的方式受 focusPolicy 控制

Qt::TabFocus
通过Tab键获得焦点
Qt::ClickFocus
通过被单击获得焦点
Qt::StrongFocus
可通过上面两种方式获得焦点
Qt::NoFocus
不能通过上两种方式获得焦点(默认值),setFocus仍可使其获得焦点

keypress和keyrelease

首先,我们要是Widget获得焦点,一般设置focusPolicy。

然后要对按键进行响应,我们只需要直接重载:

keyPressEvent
keyReleaseEvent
注意:

  • 对我们不处理的事件,要调用父类的相应事件处理函数。
  • 如果widget当前没有焦点,考虑到事件转发:如果其子widget有焦点,那么该widget未处理的键盘事件将被转发过来。
  • 有时输入焦点不在任何窗口中。这种情况发生在所有程序都是最小化的时候。这时,Windows将继续向活动窗口发送键盘消息,但是这些消息与发送给非最小化的活动窗口的键盘消息有不同的形式。

installEventFilter

Qt整个运行机制是事件循环,在运行期间如果需要拦截特定的任务,Qt提供一个便捷的处理机制,就是事件过滤器。因为过滤器的定义在QObject类中,所以只要继承了这个类,就可以使用installEventFilter()这个方法来使能过滤器。当然默认的过滤器不会过滤任何行为,如果想过滤特定行为,则需要对过滤器进行重写。

在QT的帮助文件中,我们可以看到installEventFilter()
在这里插入图片描述
QObject类中定义的eventfilter():

virtual bool QObject::eventFilter ( QObject * watched, QEvent * event );

此方法返回bool,过滤就返回true,否则flase。

重写事件过滤器

在这里插入图片描述
在这里插入图片描述

过滤组件的按键事件

在这里插入图片描述

最终效果

Qt应用启动期间,不会响应按压的原生上下左右键,按照原有TCP进程通信中的按键值响应,完成了最初目的,类似操作可以拦截更多事件。

Logo

更多推荐