在 Qt 的 keyPressEvent() 和 keyReleaseEvent() 中,我试图获得键 + 修饰符的数字键盘输入。
使用void MyWidget::keyPressEvent(QKeyEvent *evt),evt->key()给出键码 (Qt::Key) 并evt->modifiers()给出键盘修饰符 (QFlags)。
下表显示了有关关键事件的所有可用 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
Run Code Online (Sandbox Code Playgroud)
您可以看到 shift 似乎在 numpad 键事件之前被释放。
问题在于,这个“虚拟”轮班发布事件看起来与常规轮班发布完全相同。
我的理想解决方案是在 keyPressEvent() 中获得真正的换档状态。
作为一种解决方法,我很乐意测试是否在 keyPressEvent() 中启用了 NumLock - 如果用户按下 shift 并要求禁用 NumLock,我可以发出警告。
我使用的是 Win7,但解决方案应该是可移植的,例如使用 Qt。有任何想法吗?
我也会满足于回答“这是不可能的,因为......”。
这样的任务在 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
Run Code Online (Sandbox Code Playgroud)
对于 Windows,我推荐:GetKeyState函数
摘自 Visual Studio 文档:
获取键状态
返回值类型SHORT
返回值指定指定虚拟按键的状态,如下:
如果高位为1,则按键按下;否则,就结束了。
如果低位为 1,则按键被切换。诸如 CAPS LOCK 键之类的键在打开时会被切换。如果低位为 0,则该键关闭且未切换。切换键在键盘上的指示灯(如果有)在该键被切换时会亮起,在该键未切换时会熄灭。
对于 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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您没有运行 X Server,此代码将无法在 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
}
Run Code Online (Sandbox Code Playgroud)
这段代码(linux 的)是我从superuser.com的答案中获取的。
根据Raydel Miranda 的回答,我找到了一个简单且有效的解决方案。
\n\n作为参考,我将发布 Raydel Miranda 的解决方案来获取当前的 NumLock 状态:
\n\n#ifdef _WIN32\n#include <Windows.h>\n#endif\n\n#ifdef _UNIX\n#include <X11/Xlib.h>\n#endif\n\nbool IsNumLockOn()\n{\n#ifdef _WIN32\n short status = GetKeyState(VK_NUMLOCK);\n return status == 1;\n#endif\n\n#ifdef _UNIX\n Display *dpy = XOpenDisplay(":0");\n XKeyboardState x;\n XGetKeyboardControl(dpy, &x);\n XCloseDisplay(dpy);\n return x.led_mask & 2;\n#endif\n}\nRun Code Online (Sandbox Code Playgroud)\n\n根据不同的状态,小键盘按键会产生不同的键代码\n(在本例中使用中键(标记为“5”)):
\n\nNumLock | Shift | Key | Modifiers\n off | off | Qt::Key_Clear | Qt::KeypadModifier\n off | on | Qt::Key_Clear | Qt::KeypadModifier + Qt::ShiftModifier\n on | off | Qt::Key_5 *1 | Qt::KeypadModifier\n on | on | Qt::Key_Clear | Qt::KeypadModifier *2\nRun Code Online (Sandbox Code Playgroud)\n\n*1 注意按键代码如何根据 NumLock 和 Shift 状态而变化。
\n*2 您可以看到这里缺少 Qt::ShiftModifier。
警告:奇怪的是,当 isAutoRepeat() 为 true 时,中间的小键盘键(只有这个)没有设置 Qt::KeypadModifier 标志!
\n\n为了进行比较,这里是数字键“5”(字母键上方)的相同结果表:
\n\nNumLock | Shift | Key | Modifiers\n off | off | Qt::Key_5 | Qt::NoModifier\n off | on | Qt::Key_5 | Qt::ShiftModifier\n on | off | Qt::Key_5 | Qt::NoModifier\n on | on | Qt::Key_5 | Qt::ShiftModifier\nRun Code Online (Sandbox Code Playgroud)\n\n我们知道 NumLock 状态,并且知道该键是否是数字键盘键。现在我们可以确定 Shift 键的真实状态如下(再次使用标记为“5”的中键):
\n\n因此我们可以使用以下代码片段确定正确的轮班状态:
\n\n// using QKeyEvent *evt (e.g. in keyPressEvent())\nQt::Key key = Qt::Key(evt->key());\nQt::KeyboardModifiers mods = evt->modifiers();\n\nbool NumLockOn = IsNumLockOn(); // see Raydel Miranda\'s answer\n\n// set shift pressed if Qt::ShiftModifier is found\nbool ShiftPressed = mods.testFlag(Qt::ShiftModifier);\n\n// this list contains all the keycodes \'changed\' on shift\nQList<Qt::Key> lNumPadKeys = QList<Qt::Key>() << Qt::Key_Insert \n << Qt::Key_End << Qt::Key_Down << Qt::Key_PageDown \n << Qt::Key_Left << Qt::Key_Clear << Qt::Key_Right \n << Qt::Key_Home << Qt::Key_Up << Qt::Key_PageUp \n << Qt::Key_Delete;\n// if shift wasn\'t pressed, the keycodes would be Qt::Key_0, Qt::Key_1, ..., Qt::Key_Comma instead\n\n// correct the ShiftPressed value on NumLock + keypad input\nif(mods.testFlag(Qt::KeypadModifier) && NumLockOn && !ShiftPressed)\n{\n // keycode appears in the list -> shift must have been pressed\n // these keycodes can only result from keypad keys with NumLock on if shift was pressed \n ShiftPressed = lNumPadKeys.contains(key);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n瞧\xc3\xa0:
\n\nShiftPressed 现在设置为真正的换档状态(不过请注意有关 Qt::Key_Clear 的警告)。
\n| 归档时间: |
|
| 查看次数: |
4175 次 |
| 最近记录: |