Итак, у меня есть приложение, в котором, если удерживать нажатой определенную кнопку, оно воспроизводит аудиоустройство, а при отпускании кнопки останавливает аудиоустройство. я использую 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. Он подключен к X11 через xcb, и по умолчанию, в случае повторяющихся клавиш, X11 отправляет для каждого повторяющегося ключа событие освобождения, за которым сразу следует событие нажатия клавиши. Таким образом, удержание клавиши приводит к последовательности XCB_BUTTON_RELEASE / XCB_BUTTON_PRESS-событий, отправляемых клиенту (попробуйте это с xev или источником в конце эта страница).
Тогда qt (qtbase / SRC / плагины / платформы / XCB / qxcbkeyboard.cpp) из этих событий пытается выяснить, является ли это случаем автоматического повторения: когда получен релиз, он использует функцию упреждения, чтобы выяснить, следует ли за ним нажатие (с достаточно близкими временными метками), и если это так, он предполагает автоматическое повторение.
Это не всегда работает, по крайней мере, не на всех платформах. Для моего случая (старый и изношенный медленный ноутбук (Intel® Celeron® CPU N2830 @ 2,16 ГГц × 2) с Ubuntu 16.04), он помог просто поставить usleep (500) перед этой проверкой, позволяя событию press после выпуска прибытие события … оно находится вокруг строки 1525 файла qxcbkeyboard.cpp:
// 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.
Nb: поведение X может быть изменено с помощью
Display *dpy=...;
Bool result;
XkbSetDetectableAutoRepeat (dpy, true, &result);
Затем он не будет отправлять эти последовательности отпускания-нажатия в случае удерживающей клавиши, но для его использования потребуется больше изменений в логике автоматического повторения-обнаружения.
Все равно решил это.
Проблема заключалась в том, что у меня есть виджет, который является подклассом QGLWidget, который я использую для отображения некоторых изображений дополненной реальности из Kinect. Этот виджет принимает фокус клавиатуры при каждом нажатии кнопки клавиатуры.
Чтобы решить эту проблему, мне нужно было позвонить grabKeyboard
функция от MainWindow
учебный класс (MainWindow
это подкласс QMainWindow
), так this->grabKeyboard()
это строка, которую мне нужно было добавить, когда key_0
кнопка нажата так, чтобы MainWindow
не теряет фокус клавиатуры, а затем, когда клавиша отпущена, мне нужно было добавить строку this->releaseKeyboard()
чтобы возобновить нормальное поведение, то есть другие виджеты могут иметь фокус клавиатуры.