From 8ae9c4d263dca76447569ca47febeb00f17b95c9 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Wed, 30 Sep 2020 17:30:38 +0200 Subject: [PATCH] Made input focus grabbing more aggressive #38 This fixes keyboard input in REAPER, and I haven't found any downsides to this approach yet. --- CHANGELOG.md | 5 +++++ src/wine-host/editor.cpp | 46 +++++++++++++++++++++++++--------------- src/wine-host/editor.h | 9 +++++++- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e91bc75..6e26688d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ Versioning](https://semver.org/spec/v2.0.0.html). the suggestion to enable the `hack_reaper_update_display` workaround for REAPER when it is not already enabled. +### Fixed + +- Changed the way keyboard input focus works to also allow keyboard input in + _REAPER_. Please let me know if this causes any issues elsewhere! + ## [1.6.1] - 2020-09-28 ### Fixed diff --git a/src/wine-host/editor.cpp b/src/wine-host/editor.cpp index ad03bdea..0f61e703 100644 --- a/src/wine-host/editor.cpp +++ b/src/wine-host/editor.cpp @@ -110,14 +110,12 @@ Editor::Editor(const Configuration& config, // within. For robustness's sake this should be done both when the actual // window the Wine window is embedded in (which may not be the parent // window) is moved or resized, and when the user moves his mouse over the - // window. We also want to set keyboard focus when the user clicks on the - // Windows since Bitwig 3.2 now explicitely requires this. + // window because this is sometimes needed for plugin groups. const uint32_t topmost_event_mask = XCB_EVENT_MASK_STRUCTURE_NOTIFY; xcb_change_window_attributes(x11_connection.get(), topmost_window, XCB_CW_EVENT_MASK, &topmost_event_mask); xcb_flush(x11_connection.get()); - const uint32_t parent_event_mask = - XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_ENTER_WINDOW; + const uint32_t parent_event_mask = XCB_EVENT_MASK_ENTER_WINDOW; xcb_change_window_attributes(x11_connection.get(), parent_window, XCB_CW_EVENT_MASK, &parent_event_mask); xcb_flush(x11_connection.get()); @@ -216,19 +214,6 @@ void Editor::handle_x11_events() const { case XCB_ENTER_NOTIFY: fix_local_coordinates(); break; - case XCB_FOCUS_IN: - fix_local_coordinates(); - - // Explicitely request input focus when the user clicks on the - // window. This is needed for Bitwig Studio 3.2, as the parent - // window now captures all keyboard events and forwards them to - // the main Bitwig Studio window instead of allowing the child - // window to handle those events. - xcb_set_input_focus(x11_connection.get(), - XCB_INPUT_FOCUS_PARENT, wine_window, - XCB_CURRENT_TIME); - xcb_flush(x11_connection.get()); - break; } free(generic_event); @@ -280,6 +265,19 @@ void Editor::fix_local_coordinates() const { xcb_flush(x11_connection.get()); } +void Editor::grab_input_focus() const { + // Explicitely request input focus when the user clicks on the window. This + // is needed for Bitwig Studio 3.2, as the parent window now captures all + // keyboard events and forwards them to the main Bitwig Studio window + // instead of allowing the child window to handle those events. We used to + // do this on the X11 FocusIn event, but that's not getting fired for REAPER + // so we now do this on `WM_PARENTNOTIFY` which included every time the user + // clicks on the Wine window. + xcb_set_input_focus(x11_connection.get(), XCB_INPUT_FOCUS_PARENT, + wine_window, XCB_CURRENT_TIME); + xcb_flush(x11_connection.get()); +} + LRESULT CALLBACK window_proc(HWND handle, UINT message, WPARAM wParam, @@ -315,6 +313,20 @@ LRESULT CALLBACK window_proc(HWND handle, editor->send_idle_event(); return 0; } break; + case WM_PARENTNOTIFY: { + auto editor = reinterpret_cast( + GetWindowLongPtr(handle, GWLP_USERDATA)); + if (!editor) { + break; + } + + // Grab input focus when the user interacts with the Wine window. + // Ideally this would only be done when the window does not yet have + // keyboard focus but I wasn't able to find a reliable way to do + // that that also works in REAPER. + editor->fix_local_coordinates(); + editor->grab_input_focus(); + } break; } return DefWindowProc(handle, message, wParam, lParam); diff --git a/src/wine-host/editor.h b/src/wine-host/editor.h index fd81c788..a63d22b8 100644 --- a/src/wine-host/editor.h +++ b/src/wine-host/editor.h @@ -136,7 +136,6 @@ class Editor { */ void handle_x11_events() const; - private: /** * Lie to the Wine window about its coordinates on the screen for * reparenting without using XEmbed. See the comment at the top of the @@ -144,6 +143,14 @@ class Editor { */ void fix_local_coordinates() const; + /** + * Steal keyboard focus. This is done whenever the user clicks on the window + * since we don't have a way to detect whether the client window is calling + * `SetFocus()`. + */ + void grab_input_focus() const; + + private: /** * A pointer to the currently active window. Will be a null pointer if no * window is active.