Keyboard focus and child windows are inconsistant across platforms; Windows: Can programmatically focus the child window, NVidia overlay can defocus it. X11: Can programmatically focus the child window. Wayland: Child window cannot be focused at all on most(?) DE. Mac: Can programmatically focus the child window. Thus for KB inputs we need to sometimes use the event filter. Mouse events are always
| 223 | // Thus for KB inputs we need to sometimes use the event filter. |
| 224 | // Mouse events are always delivered to the child window, so that seems consistant. |
| 225 | void DisplaySurface::handleKeyInputEvent(QEvent* event) |
| 226 | { |
| 227 | switch (event->type()) |
| 228 | { |
| 229 | case QEvent::KeyPress: |
| 230 | case QEvent::KeyRelease: |
| 231 | { |
| 232 | const QKeyEvent* key_event = static_cast<QKeyEvent*>(event); |
| 233 | |
| 234 | // Forward text input to imgui. |
| 235 | if (ImGuiManager::WantsTextInput() && key_event->type() == QEvent::KeyPress) |
| 236 | { |
| 237 | // Don't forward backspace characters. We send the backspace as a normal key event, |
| 238 | // so if we send the character too, it double-deletes. |
| 239 | QString text(key_event->text()); |
| 240 | text.remove(QChar('\b')); |
| 241 | if (!text.isEmpty()) |
| 242 | ImGuiManager::AddTextInput(text.toStdString()); |
| 243 | } |
| 244 | |
| 245 | if (key_event->isAutoRepeat()) |
| 246 | return; |
| 247 | |
| 248 | // For some reason, Windows sends "fake" key events. |
| 249 | // Scenario: Press shift, press F1, release shift, release F1. |
| 250 | // Events: Shift=Pressed, F1=Pressed, Shift=Released, **F1=Pressed**, F1=Released. |
| 251 | // To work around this, we keep track of keys pressed with modifiers in a list, and |
| 252 | // discard the press event when it's been previously activated. It's pretty gross, |
| 253 | // but I can't think of a better way of handling it, and there doesn't appear to be |
| 254 | // any window flag which changes this behavior that I can see. |
| 255 | |
| 256 | const u32 key = QtUtils::KeyEventToCode(key_event); |
| 257 | const Qt::KeyboardModifiers modifiers = key_event->modifiers(); |
| 258 | const bool pressed = (key_event->type() == QEvent::KeyPress); |
| 259 | const auto it = std::find(m_keys_pressed_with_modifiers.begin(), m_keys_pressed_with_modifiers.end(), key); |
| 260 | if (it != m_keys_pressed_with_modifiers.end()) |
| 261 | { |
| 262 | if (pressed) |
| 263 | return; |
| 264 | else |
| 265 | m_keys_pressed_with_modifiers.erase(it); |
| 266 | } |
| 267 | else if (modifiers != Qt::NoModifier && modifiers != Qt::KeypadModifier && pressed) |
| 268 | { |
| 269 | m_keys_pressed_with_modifiers.push_back(key); |
| 270 | } |
| 271 | |
| 272 | Host::RunOnCPUThread([key, pressed]() { |
| 273 | InputManager::InvokeEvents(InputManager::MakeHostKeyboardKey(key), static_cast<float>(pressed)); |
| 274 | }); |
| 275 | |
| 276 | return; |
| 277 | } |
| 278 | |
| 279 | default: |
| 280 | pxAssert(false); |
| 281 | return; |
| 282 | } |