在Qt的keyPressEvent()和keyReleaseEvent()中,我试图获得key + modifier的小键盘输入。
使用void MyWidget::keyPressEvent(QKeyEvent *evt)
,evt->key()
给出键码(Qt :: Key),evt->modifiers()
给出键盘修饰符(QFlags)。
我发现了shift key overrides NumLock。
下表显示了关键事件的所有可用Qt值的读数 重现击键:关闭NumLock,按下并释放num_5,然后按下并释放shift,然后按shift - >按num_5 - >发布num_5 - >释放班次,然后将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
你可以看到这种转变似乎是在小键盘事件发生之前发布的 问题是这个“虚拟”转移发布事件看起来完全与常规转移发布相同。
我理想的解决方案是在keyPressEvent()中获得真正的班次状态 作为一种解决方法,我很乐意测试是否在keyPressEvent()中启用了NumLock - 如果用户按下shift并要求禁用NumLock,我可以发出警告。
我正在使用Win7,但解决方案应该是可移植的,例如使用Qt。有什么想法吗?
我也满足于回答“这是不可能的,因为......”。
答案 0 :(得分:3)
此类任务由Windows API在Windows中执行,而在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文档:
<强>函数GetKeyState 强>
返回值类型简短
返回值指定指定虚拟键的状态,如下所示:
如果高位为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;
}
请注意,如果您没有运行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
}
我从 superuser.com 的answer获取了这段代码(linux one)。
答案 1 :(得分:1)
跟进Raydel Miranda's answer我发现了一个简单而有效的解决方案。
作为参考,我将发布Raydel Miranda的解决方案以获取当前的NumLock状态:
#ifdef _WIN32
#include <Windows.h>
#endif
#ifdef _UNIX
#include <X11/Xlib.h>
#endif
bool IsNumLockOn()
{
#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
}
小键盘按键会根据不同的状态产生不同的按键代码 (对于此示例,使用中间键(标记为“5”)):
NumLock | Shift | Key | Modifiers
off | off | Qt::Key_Clear | Qt::KeypadModifier
off | on | Qt::Key_Clear | Qt::KeypadModifier + Qt::ShiftModifier
on | off | Qt::Key_5 *1 | Qt::KeypadModifier
on | on | Qt::Key_Clear | Qt::KeypadModifier *2
* 1注意密钥代码如何根据NumLock和移位状态而变化 * 2你可以看到这里缺少Qt :: ShiftModifier。
警告:奇怪的是,当isAutoRepeat()为真时,中间小数键(并且只有这一个)没有设置Qt :: KeypadModifier标志!
为了比较,这里是数字键“5”(字母键上方)的相同结果表:
NumLock | Shift | Key | Modifiers
off | off | Qt::Key_5 | Qt::NoModifier
off | on | Qt::Key_5 | Qt::ShiftModifier
on | off | Qt::Key_5 | Qt::NoModifier
on | on | Qt::Key_5 | Qt::ShiftModifier
我们知道NumLock状态,我们知道密钥是否是一个小键盘密钥。现在我们可以按如下方式确定Shift键的真实状态(再次使用标记为“5”的中间键):
因此,我们可以使用此代码段确定正确的班次状态:
// using QKeyEvent *evt (e.g. in keyPressEvent())
Qt::Key key = Qt::Key(evt->key());
Qt::KeyboardModifiers mods = evt->modifiers();
bool NumLockOn = IsNumLockOn(); // see Raydel Miranda's answer
// set shift pressed if Qt::ShiftModifier is found
bool ShiftPressed = mods.testFlag(Qt::ShiftModifier);
// this list contains all the keycodes 'changed' on shift
QList<Qt::Key> lNumPadKeys = QList<Qt::Key>() << Qt::Key_Insert
<< Qt::Key_End << Qt::Key_Down << Qt::Key_PageDown
<< Qt::Key_Left << Qt::Key_Clear << Qt::Key_Right
<< Qt::Key_Home << Qt::Key_Up << Qt::Key_PageUp
<< Qt::Key_Delete;
// if shift wasn't pressed, the keycodes would be Qt::Key_0, Qt::Key_1, ..., Qt::Key_Comma instead
// correct the ShiftPressed value on NumLock + keypad input
if(mods.testFlag(Qt::KeypadModifier) && NumLockOn && !ShiftPressed)
{
// keycode appears in the list -> shift must have been pressed
// these keycodes can only result from keypad keys with NumLock on if shift was pressed
ShiftPressed = lNumPadKeys.contains(key);
}
瞧:
ShiftPressed现在设置为真正的移位状态(请注意关于Qt :: Key_Clear的警告)。