在 Qt 的 keyPressEvent() 和 keyReleaseEvent() 中,我试图获得键 + 修饰符的小键盘输入。
使用 void MyWidget::keyPressEvent(QKeyEvent *evt)
,evt->key()
给出键码 (Qt::Key) 和 evt->modifiers()
给出键盘修饰符(QFlags)。
- 对于所有“常规”键,我可以检测到所有需要的修饰符(shift、alt、ctrl)。
- 对于小键盘键,如果 numLock 关闭,我会得到正确的修饰符。
- 如果 NumLock 打开,我会收到 ctrl 和 alt,但不会收到 shift。
我发现 shift key overrides NumLock .
下表显示了关于关键事件的所有可用 Qt 值的读数。
重现击键:关闭 NumLock,按下并释放 num_5,然后按下并释放 shift,然后按下 shift -> 按 num_5 -> 释放 num_5 -> 释放 shift,然后打开 NumLock 并重复相同的按键。
table headers:
natSC = evt->nativeScanCode()
natMods = evt->nativeModifiers()
kbdMods = QGuiApplication::keyboardModifiers()
queryKbdMods = QGuiApplication::queryKeyboardModifiers()
NumLock | Action | Event | evt->key() | evt->modifiers() | natSC | natMods | kbdMods | queryKbdMods
--------+---------------+------------+-------------+------------------+-------+----------+--------------+-------------
off | Num_5 down | keyPress | Key_Clear | Keypad | 76 | 0 | Keypad | 0
off | Num_5 up | keyRelease | Key_Clear | Keypad | 76 | 0 | Keypad | 0
off | Shift down | keyPress | Key_Shift | Shift | 42 | 1 | 0 | Shift
off | Shift up | keyRelease | Key_Shift | 0 | 42 | 0 | Shift | 0
off | Shift down | keyPress | Key_Shift | Shift | 42 | 1 | 0 | Shift
off | Num_5 down | keyPress | Key_Clear | Shift+Keypad | 76 | 1 | Shift+Keypad | Shift
off | Num_5 up | keyRelease | Key_Clear | Shift+Keypad | 76 | 1 | Shift+Keypad | Shift
off | Shift up | keyRelease | Key_Shift | 0 | 42 | 0 | Shift | 0
--------+---------------+------------+-------------+------------------+-------+----------+--------------+-------------
on | NumLock dwn | keyPress | Key_NumLock | Keypad | 325 | 16777728 | Keypad | 0
on | NumLock up | keyRelease | Key_NumLock | Keypad | 325 | 16777728 | Keypad | 0
--------+---------------+------------+-------------+------------------+-------+----------+--------------+-------------
on | Num_5 down | keyPress | Key_5 | Keypad | 76 | 512 | Keypad | 0
on | Num_5 up | keyRelease | Key_5 | Keypad | 76 | 512 | Keypad | 0
on | Shift down | keyPress | Key_Shift | Shift | 42 | 513 | 0 | Shift
on | Shift up | keyRelease | Key_Shift | 0 | 42 | 512 | Shift | 0
on | Shift down | keyPress | Key_Shift | Shift | 42 | 513 | 0 | Shift
on | Num_5 down | keyRelease | Key_Shift | 0 | 42 | 512 | Shift | 0
on | ...Num_5 down | keyPress | Key_Clear | Keypad | 76 | 512 | Keypad | 0
on | Num_5 up | keyRelease | Key_Clear | Keypad | 76 | 512 | Keypad | Shift
on | ...Num_5 up | keyPress | Key_Shift | Shift | 42 | 513 | 0 | Shift
on | Shift up | keyRelease | Key_Shift | 0 | 42 | 512 | Shift | 0
您可以看到 shift 似乎在小键盘键事件之前被释放。
问题在于,这个“虚拟”轮类发布事件看起来完全与常规轮类发布相同。
我理想的解决方案是在 keyPressEvent() 中获取真正的转换状态。
作为解决方法,我很乐意测试是否在 keyPressEvent() 中启用了 NumLock - 如果用户按下 shift 并要求禁用 NumLock,我可以发出警告。
我使用的是 Win7,但解决方案应该是可移植的,例如使用 Qt。有什么想法吗?
我也会满足于回答“这是不可能的,因为......”。
最佳答案
获取 NumLock 状态
此类任务在 Windows 中由 Windows API 执行,而在 Unix 系统中是 X11谁负责。如果您希望您的代码在两者中运行,您可以使用条件编译。
#ifdef _WIN32
// Code for windows
#else
#ifdef __linux__ // Systems based on the Linux kernel define this macro.
// Code for linux.
#else
对于 Windows,我会推荐:GetKeyState 函数
摘自 Visual Studio 文档:
获取 key 状态
返回值类型SHORT
The return value specifies the status of the specified virtual key, as follows:
If the high-order bit is 1, the key is down; otherwise, it is up.
If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.
对于 Linux:使用 XLib。
这是一个多平台示例代码:
#ifdef _WIN32
#include <Windows.h>
#endif
#ifdef _UNIX
#include <X11/Xlib.h>
#endif
#include <iostream>
bool is_numlock_activated()
{
#ifdef _WIN32
short status = GetKeyState(VK_NUMLOCK);
return status == 1;
#endif
#ifdef _UNIX
Display *dpy = XOpenDisplay(":0");
XKeyboardState x;
XGetKeyboardControl(dpy, &x);
XCloseDisplay(dpy);
return x.led_mask & 2;
#endif
}
int main()
{
if (is_numlock_activated())
std::cout << "NumLock is activated.";
else
std::cout << "NumLock is deactivated.";
std::cout << std::endl;
return 0;
}
请注意,如果您没有运行 X 服务器,此代码将无法在 Linux 上运行。这无关紧要,因为您正在开发桌面应用程序,因此如果您可以运行您的应用程序,则可以运行此代码。
获取类次状态
为此(对于 linux),除了 Xlib.h 之外,您还需要包含 XKB 扩展。
#ifdef _UNIX
#include <X11/XKBlib.h>
#endif
bool is_shift_pressed()
{
bool result;
#ifdef _WIN32
short status = GetKeyState(VK_SHIFT);
return status == 0xF0; // Here we are checking the High order bit.
// See GetKeyState documentation above.
#endif
#ifdef _UNIX
Display *dpy = XOpenDisplay(":0");
XkbStateRec sate;
XkbGetSate(dpy, XkbUseCoreKbd, &sate);
XCloseDisplay(dpy);
return state.mods & 1; // 1 is the mask for modifier SHIFT.
#endif
}
这段代码(linux 代码)是我从 answer 中提取的来自 superuser.com。
关于c++ - 如何判断是否在启用 NumLock 的情况下在小键盘输入上按下了 shift?或者至少获得 NumLock 状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24822505/