Summary
Adds an Editor::on_vst3_virtual_key_down trait hook the VST3 wrapper calls from IPlugView::onKeyDown, so plugin editors can route virtual-key events (Space, Backspace, arrows, F-keys, etc.) that the host would otherwise intercept as accelerators before they reach the plugin's native view.
API
implEditorforMyEditor{fn on_virtual_key_from_host(&self,key_code: KeyCode,is_down: bool,modifiers: Modifiers)-> bool {// return true if the editor consumed the key
}}
KeyCode mirrors the VST3 SDK VirtualKeyCodes enum (pluginterfaces/base/keycodes.h), with named variants for Backspace, Tab, Return, arrows, Numpad, F1–F24, etc. Modifiers wraps the VST3 KeyModifier bitfield with .shift(), .alt(), .command(), .control(), .any(), .none() accessors.
VST3 wrapper behaviour
The wrapper forwards events only when the raw key_code lies in [VKEY_FIRST_CODE, VKEY_LAST_CODE] (1..=77 in the SDK enum). Values at VKEY_FIRST_ASCII = 128 and above encode printable ASCII characters and are not routed here; those flow through the plugin window's native keyboard path (on macOS, AppKit keyDown: + NSTextInputContext), which is the correct place for text input.
Motivation
REAPER (and some other hosts) capture certain keys (Space, Cmd-shortcuts, Backspace with some key-maps) as transport / accelerator commands before they reach the plugin's NSView. Before this hook, those keys were silently eaten even when a textbox in the plugin's editor had focus. Plugins can now consult the hook and claim the key only while editing text.
Usage
Wrapper-side, the GUI framework (or plugin) implements the hook and claims the key only when it has something focused that should consume it. A minimal pattern:
fn on_vst3_virtual_key_down(&self,key_code: KeyCode,modifiers: Modifiers)-> bool {if!self.has_text_focus()||modifiers.any(){returnfalse;}matchkey_code{KeyCode::Backspace=>{self.delete_back();true}KeyCode::Return=>{self.submit();true}KeyCode::Space=>{self.insert(' ');true}_=>false,}}
Returning true translates to kResultTrue so the host skips its own accelerator handling; returning false yields kResultFalse and the host proceeds as normal.
Tested
- macOS / REAPER — Space, Backspace, Enter, arrows, Numpad in a focused textbox; Space outside textbox reaches REAPER transport (when Send-all-keyboard-input is off).
- macOS / Ableton Live — basic type-in-textbox flow.
CLAP
Left unimplemented for now; CLAP plugins manage keyboard focus differently (clap_plugin_gui::set_keyboard_focus) and don't need an equivalent trait hook.
## Summary
Adds an `Editor::on_vst3_virtual_key_down` trait hook the VST3 wrapper calls from `IPlugView::onKeyDown`, so plugin editors can route virtual-key events (Space, Backspace, arrows, F-keys, etc.) that the host would otherwise intercept as accelerators before they reach the plugin's native view.
## API
```rust
impl Editor for MyEditor {
fn on_virtual_key_from_host(&self, key_code: KeyCode, is_down: bool, modifiers: Modifiers) -> bool {
// return true if the editor consumed the key
}
}
```
`KeyCode` mirrors the VST3 SDK `VirtualKeyCodes` enum (`pluginterfaces/base/keycodes.h`), with named variants for Backspace, Tab, Return, arrows, Numpad, F1–F24, etc. `Modifiers` wraps the VST3 `KeyModifier` bitfield with `.shift()`, `.alt()`, `.command()`, `.control()`, `.any()`, `.none()` accessors.
## VST3 wrapper behaviour
The wrapper forwards events only when the raw `key_code` lies in `[VKEY_FIRST_CODE, VKEY_LAST_CODE]` (1..=77 in the SDK enum). Values at `VKEY_FIRST_ASCII = 128` and above encode printable ASCII characters and are not routed here; those flow through the plugin window's native keyboard path (on macOS, AppKit `keyDown:` + NSTextInputContext), which is the correct place for text input.
## Motivation
REAPER (and some other hosts) capture certain keys (Space, Cmd-shortcuts, Backspace with some key-maps) as transport / accelerator commands before they reach the plugin's NSView. Before this hook, those keys were silently eaten even when a textbox in the plugin's editor had focus. Plugins can now consult the hook and claim the key only while editing text.
## Usage
Wrapper-side, the GUI framework (or plugin) implements the hook and claims the key only when it has something focused that should consume it. A minimal pattern:
```rust
fn on_vst3_virtual_key_down(&self, key_code: KeyCode, modifiers: Modifiers) -> bool {
if !self.has_text_focus() || modifiers.any() {
return false;
}
match key_code {
KeyCode::Backspace => { self.delete_back(); true }
KeyCode::Return => { self.submit(); true }
KeyCode::Space => { self.insert(' '); true }
_ => false,
}
}
```
Returning `true` translates to `kResultTrue` so the host skips its own accelerator handling; returning `false` yields `kResultFalse` and the host proceeds as normal.
## Tested
- macOS / REAPER — Space, Backspace, Enter, arrows, Numpad in a focused textbox; Space outside textbox reaches REAPER transport (when Send-all-keyboard-input is off).
- macOS / Ableton Live — basic type-in-textbox flow.
## CLAP
Left unimplemented for now; CLAP plugins manage keyboard focus differently (`clap_plugin_gui::set_keyboard_focus`) and don't need an equivalent trait hook.