Skip to content

Commit 0375012

Browse files
committed
Selectively prevent key propagation
1 parent 3829510 commit 0375012

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

src/macos/keyboard.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub(crate) struct KeyboardState {
5656
///
5757
/// It should also match up with CODE_MAP_MAC bindings in
5858
/// NativeKeyToDOMCodeName.h.
59-
fn key_code_to_code(key_code: u16) -> Code {
59+
pub(crate) fn key_code_to_code(key_code: u16) -> Code {
6060
match key_code {
6161
0x00 => Code::KeyA,
6262
0x01 => Code::KeyS,

src/macos/view.rs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
WindowEvent, WindowInfo, WindowOpenOptions,
2020
};
2121

22-
use super::keyboard::{from_nsstring, make_modifiers};
22+
use super::keyboard::{from_nsstring, key_code_to_code, make_modifiers};
2323
use super::window::WindowState;
2424
use super::{
2525
NSDragOperationCopy, NSDragOperationGeneric, NSDragOperationLink, NSDragOperationMove,
@@ -220,7 +220,8 @@ unsafe fn create_view_class() -> &'static Class {
220220
add_simple_mouse_class_method!(class, mouseEntered, MouseEvent::CursorEntered);
221221
add_simple_mouse_class_method!(class, mouseExited, MouseEvent::CursorLeft);
222222

223-
add_simple_keyboard_class_method!(class, keyDown);
223+
class.add_method(sel!(keyDown:), keyDown as extern "C" fn(&Object, Sel, id));
224+
224225
add_simple_keyboard_class_method!(class, keyUp);
225226
add_simple_keyboard_class_method!(class, flagsChanged);
226227

@@ -554,3 +555,51 @@ extern "C" fn handle_notification(this: &Object, _cmd: Sel, notification: id) {
554555
}
555556
}
556557
}
558+
559+
/// Checks if a certain key event should be intercepted.
560+
/// This is useful in DAW hosts such as Logic Pro which propagate
561+
/// all keys globally.
562+
fn should_intercept_key(event: id) -> bool {
563+
use keyboard_types::Code;
564+
let key_code = unsafe { NSEvent::keyCode(event) };
565+
let code = key_code_to_code(key_code);
566+
567+
matches!(
568+
code,
569+
// Regular number keys
570+
Code::Digit0 | Code::Digit1 | Code::Digit2 | Code::Digit3 | Code::Digit4 |
571+
Code::Digit5 | Code::Digit6 | Code::Digit7 | Code::Digit8 | Code::Digit9 |
572+
// Numpad keys
573+
Code::Numpad0 | Code::Numpad1 | Code::Numpad2 | Code::Numpad3 | Code::Numpad4 |
574+
Code::Numpad5 | Code::Numpad6 | Code::Numpad7 | Code::Numpad8 | Code::Numpad9 |
575+
// Period
576+
Code::Period | Code::NumpadDecimal |
577+
// Enter, Backspace and ESC
578+
Code::Enter | Code::Backspace | Code::Escape
579+
)
580+
}
581+
582+
#[allow(non_snake_case)]
583+
extern "C" fn keyDown(this: &Object, _: Sel, event: id) {
584+
let state = unsafe { WindowState::from_view(this) };
585+
586+
if should_intercept_key(event) {
587+
// Process the key event but don't let it propagate to the parent
588+
if let Some(key_event) = state.process_native_key_event(event) {
589+
let _status = state.trigger_event(Event::Keyboard(key_event));
590+
// We don't call super implementation - this prevents the key from reaching the host
591+
}
592+
} else {
593+
// Normal handling for other keys
594+
if let Some(key_event) = state.process_native_key_event(event) {
595+
let status = state.trigger_event(Event::Keyboard(key_event));
596+
597+
if let EventStatus::Ignored = status {
598+
unsafe {
599+
let superclass = msg_send![this, superclass];
600+
let () = msg_send![super(this, superclass), keyDown:event];
601+
}
602+
}
603+
}
604+
}
605+
}

0 commit comments

Comments
 (0)