所以,我有一个应用程序,如果一个特定的按钮保持按下它播放音频设备,当按钮被释放它停止音频设备。我使用keyPressEvent
和KeyReleaseEvent
来实现这一点,类似于下面的代码:
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if(event->isAutoRepeat())
{
event->ignore();
}
else
{
if(event->key() == Qt::Key_0)
{
qDebug()<<"key_0 pressed"<<endl;
}
else
{
QWidget::keyPressEvent(event);
}
}
}
void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
if(event->isAutoRepeat())
{
event->ignore();
}
else
{
if(event->key() == Qt::Key_0)
{
qDebug()<<"key_0 released"<<endl;
}
else
{
QWidget::keyReleaseEvent(event);
}
}
}
但显然isAutoRepeat
功能不起作用,因为我可以看到连续打印出key_0 pressed
和key_0 released
,尽管我没有在按下0键后释放它。是我的代码错了还是别的什么东西错了?
谢谢。
编辑
我认为这是因为MainWindow
失去了键盘焦点。我怎样才能知道哪个小部件有焦点?当Qt::Key_0
按下时,我实际上使用了一些小部件,但我认为我将所有这些可能的小部件设置为Qt::NoFocus
,我想它不起作用。
我想知道哪个小部件有焦点做以下操作:
QWidget * wigdet = QApplication::activeWindow();
qDebug()<<wigdet->accessibleName()<<endl;
,但它总是打印一个空字符串。我如何使它打印具有键盘焦点的小部件的名称?
因此,当我也被这个问题绊倒时(并且grabKeyboard没有真正帮助),我开始在qtbase中挖掘。它通过xcb连接到X11,默认情况下,在重复键的情况下,X11为每个重复的键发送一个释放事件,紧接着是一个按键事件。因此,按住一个键会导致XCB_BUTTON_RELEASE/xcb_button_press事件序列被发送到客户机(使用xev或本页末尾的源代码进行试验)。
然后,qt (qtbase/src/plugins/platforms/xcb/qxcbkeyboard.cpp)试图从这些事件中找出它是否是自动重复的情况:当收到一个发布时,它使用一个向前看的功能来确定它后面是否有一个按(时间戳足够接近),如果是这样,它假设自动重复。
这并不总是有效,至少不是在所有平台上。对于我的情况(旧的和过时的慢笔记本电脑(英特尔®赛扬(R) CPU N2830 @ 2.16GHz × 2)运行ubuntu 16.04),它有助于在检查之前设置ussleep(500),允许发布事件之后的新闻发布会到达…在qxcbkeyboard.cpp:
的第1525行左右 // look ahead for auto-repeat
KeyChecker checker(source->xcb_window(), code, time, state);
usleep(500); // Added, 100 is to small, 200 is ok (for me)
xcb_generic_event_t *event = connection()->checkEvent(checker);
if (event) {
...
将此文件归档为QTBUG-57335。
注意:X的行为可以通过使用 来改变Display *dpy=...;
Bool result;
XkbSetDetectableAutoRepeat (dpy, true, &result);
那么它不会在按住键的情况下发送这个release-press-sequences,但是使用它将需要对autorepeat-detection-logic进行更多的更改。
反正解决了。
问题是我有一个小部件,它是QGLWidget的子类,我用它来显示一些来自Kinect的增强现实图像。只要按下键盘按钮,这个小部件就会接管键盘焦点。
为了解决这个问题,我需要从MainWindow
类调用grabKeyboard
函数(MainWindow
是QMainWindow
的子类),因此this->grabKeyboard()
是我需要在key_0
按钮按下时添加的行,以便MainWindow
不会失去键盘焦点,然后当键被释放时,我需要添加行this->releaseKeyboard()
以恢复正常行为,也就是说,其他小部件可以具有键盘焦点。