diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3fbf8355..ca9ecdf6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,19 @@ Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
+### Added
+
+- Added the ability to directly focus the plugin's editor instead of allowing
+ the host to also process keyboard events by holding down the Shift
+ key while entering the plugin's GUI with your mouse. Certain hosts like
+ **Bitwig Studio** normally still respond to the common key presses like Space
+ for play/pause while interacting with a plugin. This does mean that it becomes
+ impossible to type a space character in those hosts, which can become a
+ problem when naming presets. With this feature you can temporarily override
+ this behaviour, and allow all keyboard input to go directly to Wine. This can
+ also be useful for _Voxengo_ plugins, which don't grab keyboard focus in their
+ settings and license dialogs.
+
### Changed
- Added more tracing for input focus handling when using the `+editor`
diff --git a/README.md b/README.md
index 6508d430..d024eb64 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,7 @@ while also staying easy to debug and maintain.
- [Bitbridge](#bitbridge)
- [Wine prefixes](#wine-prefixes)
- [Drag-and-drop](#drag-and-drop)
+ - [Input focus grabbing](#input-focus-grabbing)
- [Downgrading Wine](#downgrading-wine)
- [Installing a development build](#installing-a-development-build)
- [Configuration](#configuration)
@@ -200,6 +201,24 @@ X11 applications like your DAW. If you're using yabridge in _REAPER_ or _Carla_,
then you may need to enable a [compatibility option](#compatibility-options) to
prevent those hosts from stealing the drop.
+### Input focus grabbing
+
+Yabridge tries to be clever about the way grabbing input focus for a plugin and
+subsequently giving it back to the host works. One important detail here is that
+when grabbing input focus, yabridge will always focus the _parent window_ passed
+by the host for the plugin to embed itself into. This means that hosts like
+Bitwig Studio can still process common keys like Space for play/pause even while
+interacting with a plugin's GUI. The downside of this approach is that this also
+means that in those hosts you simply cannot type a space character, as the key
+will always go to the host.
+
+For the very specific situations where you may want to focus the plugin's editor
+directly so that all keyboard input goes to Wine, you can hold down the
+Shift key while entering the plugin's GUI with your mouse. This will
+let you type spaces in text fields in **Bitwig Studio**, type text into the
+settings and license dialogs in **Voxengo** plugins, and it will also allow you
+to navigate dropdowns with the keyboard.
+
### Downgrading Wine
There have been a couple of small regressions in Wine after Wine 6.4. If you run
diff --git a/src/wine-host/editor.cpp b/src/wine-host/editor.cpp
index 72ede613..557cc569 100644
--- a/src/wine-host/editor.cpp
+++ b/src/wine-host/editor.cpp
@@ -785,7 +785,17 @@ void Editor::fix_local_coordinates() const {
}
void Editor::set_input_focus(bool grab) const {
- const xcb_window_t focus_target = grab ? parent_window : host_window;
+ // NOTE: When grabbing focus, you can hold down the shift key to focus the
+ // Wine window directly. This allows you to use the space key in
+ // plugin GUIs in Bitwig when necessary (e.g. for naming presets) but
+ // still allow space to pause/resume the transport when it's not
+ // needed. It's also needed for dialogs in Voxengo plugins to function
+ // properly, as they don't grab input focus themselves.
+ const xcb_window_t focus_target =
+ grab ? (get_active_modifiers().value_or(0) & XCB_MOD_MASK_SHIFT
+ ? wine_window
+ : parent_window)
+ : host_window;
xcb_generic_error_t* error = nullptr;
const xcb_get_input_focus_cookie_t focus_cookie =
@@ -865,6 +875,11 @@ std::optional Editor::get_active_modifiers() const noexcept {
return std::nullopt;
}
+ logger.log_editor_trace([&]() {
+ return "DEBUG: Active keyboard modifiers: " +
+ std::to_string(query_pointer_reply->mask);
+ });
+
return query_pointer_reply->mask;
}
diff --git a/src/wine-host/editor.h b/src/wine-host/editor.h
index 001c98dd..a5c4e751 100644
--- a/src/wine-host/editor.h
+++ b/src/wine-host/editor.h
@@ -242,6 +242,16 @@ class Editor {
* is calling `SetFocus()`. See the comment inside of this function for more
* details on when this is used.
*
+ * NOTE: There's a little bit of special behaviour in here. When the shift
+ * key is held while grabbing input focus, then we'll focus
+ * `wine_window` directly instead of focussing `wrapper_window`. This
+ * allows you to temporarily override the default focus grabbing
+ * behaviour, allowing you to use the space key in plugins GUIs in
+ * Bitwig and to enter text in Voxengo settings and license dialogs.
+ * This can also help with plugins that use popups but still rely on
+ * the parent window's keyboard events to come up to control those
+ * popups.
+ *
* @param grab Whether to grab input focus (if `true`) or to give back input
* focus to `host_window` (if `false`).
*/