diff --git a/osdep/mac/application.m b/osdep/mac/application.m index cd6d146a10..bd71b6042c 100644 --- a/osdep/mac/application.m +++ b/osdep/mac/application.m @@ -115,7 +115,7 @@ static void terminate_cocoa_application(void) - (void)sendEvent:(NSEvent *)event { - if ([self modalWindow] || ![_eventsResponder processKeyEvent:event]) + if ([self modalWindow] || ![_eventsResponder.inputHelper processKeyWithEvent:event]) [super sendEvent:event]; [_eventsResponder.inputHelper wakeup]; } diff --git a/osdep/mac/events.h b/osdep/mac/events.h index 574aae9b5a..5c3ac38b6b 100644 --- a/osdep/mac/events.h +++ b/osdep/mac/events.h @@ -19,7 +19,6 @@ #ifndef MAC_EVENTS #define MAC_EVENTS -#include "input/keycodes.h" struct input_ctx; struct mpv_handle; diff --git a/osdep/mac/events.m b/osdep/mac/events.m index 02b414428d..127a674339 100644 --- a/osdep/mac/events.m +++ b/osdep/mac/events.m @@ -17,21 +17,12 @@ * License along with mpv. If not, see . */ -// Carbon header is included but Carbon is NOT linked to mpv's binary. This -// file only needs this include to use the keycode definitions in keymap. -#import - -// Media keys definitions -#import #import #include "mpv_talloc.h" #include "input/event.h" #include "input/input.h" #include "player/client.h" -#include "input/keycodes.h" -// doesn't make much sense, but needed to access keymap functionality -#include "video/out/vo.h" #import "osdep/mac/events_objc.h" #import "osdep/mac/application_objc.h" @@ -48,77 +39,13 @@ BOOL _is_application; } -- (NSEvent *)handleKey:(NSEvent *)event; - (BOOL)setMpvHandle:(struct mpv_handle *)ctx; - (void)initCocoaCb; - (void)readEvents; - (void)startMediaKeys; - (void)stopMediaKeys; -- (int)mapKeyModifiers:(int)cocoaModifiers; -- (int)keyModifierMask:(NSEvent *)event; @end - -#define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption) -#define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption) - -static bool LeftAltPressed(int mask) -{ - return (mask & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask; -} - -static bool RightAltPressed(int mask) -{ - return (mask & NSRightAlternateKeyMask) == NSRightAlternateKeyMask; -} - -static const struct mp_keymap keymap[] = { - // special keys - {kVK_Return, MP_KEY_ENTER}, {kVK_Escape, MP_KEY_ESC}, - {kVK_Delete, MP_KEY_BACKSPACE}, {kVK_Option, MP_KEY_BACKSPACE}, - {kVK_Control, MP_KEY_BACKSPACE}, {kVK_Shift, MP_KEY_BACKSPACE}, - {kVK_Tab, MP_KEY_TAB}, - - // cursor keys - {kVK_UpArrow, MP_KEY_UP}, {kVK_DownArrow, MP_KEY_DOWN}, - {kVK_LeftArrow, MP_KEY_LEFT}, {kVK_RightArrow, MP_KEY_RIGHT}, - - // navigation block - {kVK_Help, MP_KEY_INSERT}, {kVK_ForwardDelete, MP_KEY_DELETE}, - {kVK_Home, MP_KEY_HOME}, {kVK_End, MP_KEY_END}, - {kVK_PageUp, MP_KEY_PAGE_UP}, {kVK_PageDown, MP_KEY_PAGE_DOWN}, - - // F-keys - {kVK_F1, MP_KEY_F + 1}, {kVK_F2, MP_KEY_F + 2}, {kVK_F3, MP_KEY_F + 3}, - {kVK_F4, MP_KEY_F + 4}, {kVK_F5, MP_KEY_F + 5}, {kVK_F6, MP_KEY_F + 6}, - {kVK_F7, MP_KEY_F + 7}, {kVK_F8, MP_KEY_F + 8}, {kVK_F9, MP_KEY_F + 9}, - {kVK_F10, MP_KEY_F + 10}, {kVK_F11, MP_KEY_F + 11}, {kVK_F12, MP_KEY_F + 12}, - {kVK_F13, MP_KEY_F + 13}, {kVK_F14, MP_KEY_F + 14}, {kVK_F15, MP_KEY_F + 15}, - {kVK_F16, MP_KEY_F + 16}, {kVK_F17, MP_KEY_F + 17}, {kVK_F18, MP_KEY_F + 18}, - {kVK_F19, MP_KEY_F + 19}, {kVK_F20, MP_KEY_F + 20}, - - // numpad - {kVK_ANSI_KeypadPlus, '+'}, {kVK_ANSI_KeypadMinus, '-'}, - {kVK_ANSI_KeypadMultiply, '*'}, {kVK_ANSI_KeypadDivide, '/'}, - {kVK_ANSI_KeypadEnter, MP_KEY_KPENTER}, - {kVK_ANSI_KeypadDecimal, MP_KEY_KPDEC}, - {kVK_ANSI_Keypad0, MP_KEY_KP0}, {kVK_ANSI_Keypad1, MP_KEY_KP1}, - {kVK_ANSI_Keypad2, MP_KEY_KP2}, {kVK_ANSI_Keypad3, MP_KEY_KP3}, - {kVK_ANSI_Keypad4, MP_KEY_KP4}, {kVK_ANSI_Keypad5, MP_KEY_KP5}, - {kVK_ANSI_Keypad6, MP_KEY_KP6}, {kVK_ANSI_Keypad7, MP_KEY_KP7}, - {kVK_ANSI_Keypad8, MP_KEY_KP8}, {kVK_ANSI_Keypad9, MP_KEY_KP9}, - - {0, 0} -}; - -static int convert_key(unsigned key, unsigned charcode) -{ - int mpkey = lookup_keymap_table(keymap, key); - if (mpkey) - return mpkey; - return charcode; -} - void cocoa_init_media_keys(void) { [[EventsResponder sharedInstance] startMediaKeys]; @@ -255,77 +182,4 @@ void cocoa_init_cocoa_cb(void) [_remoteCommandCenter stop]; } -- (int)mapKeyModifiers:(int)cocoaModifiers -{ - int mask = 0; - if (cocoaModifiers & NSEventModifierFlagShift) - mask |= MP_KEY_MODIFIER_SHIFT; - if (cocoaModifiers & NSEventModifierFlagControl) - mask |= MP_KEY_MODIFIER_CTRL; - if (LeftAltPressed(cocoaModifiers) || - (RightAltPressed(cocoaModifiers) && ![_inputHelper useAltGr])) - mask |= MP_KEY_MODIFIER_ALT; - if (cocoaModifiers & NSEventModifierFlagCommand) - mask |= MP_KEY_MODIFIER_META; - return mask; -} - -- (int)mapTypeModifiers:(NSEventType)type -{ - NSDictionary *map = @{ - @(NSEventTypeKeyDown) : @(MP_KEY_STATE_DOWN), - @(NSEventTypeKeyUp) : @(MP_KEY_STATE_UP), - }; - return [map[@(type)] intValue]; -} - -- (int)keyModifierMask:(NSEvent *)event -{ - return [self mapKeyModifiers:[event modifierFlags]] | - [self mapTypeModifiers:[event type]]; -} - --(BOOL)handleMPKey:(int)key withMask:(int)mask -{ - if (key > 0) { - [_inputHelper putKey:key | mask modifiers:0]; - if (mask & MP_KEY_STATE_UP) - [_inputHelper putKey:MP_INPUT_RELEASE_ALL modifiers:0]; - return YES; - } else { - return NO; - } -} - -- (NSEvent*)handleKey:(NSEvent *)event -{ - if ([event isARepeat]) return nil; - - NSString *chars; - - if ([_inputHelper useAltGr] && RightAltPressed([event modifierFlags])) { - chars = [event characters]; - } else { - chars = [event charactersIgnoringModifiers]; - } - - struct bstr t = bstr0([chars UTF8String]); - int key = convert_key([event keyCode], bstr_decode_utf8(t, &t)); - - if (key > -1) - [self handleMPKey:key withMask:[self keyModifierMask:event]]; - - return nil; -} - -- (bool)processKeyEvent:(NSEvent *)event -{ - if (event.type == NSEventTypeKeyDown || event.type == NSEventTypeKeyUp){ - if (![[NSApp mainMenu] performKeyEquivalent:event]) - [self handleKey:event]; - return true; - } - return false; -} - @end diff --git a/osdep/mac/events_objc.h b/osdep/mac/events_objc.h index 01c0957991..ece2254702 100644 --- a/osdep/mac/events_objc.h +++ b/osdep/mac/events_objc.h @@ -29,10 +29,6 @@ struct input_ctx; + (EventsResponder *)sharedInstance; - (void)setIsApplication:(BOOL)isApplication; -- (bool)processKeyEvent:(NSEvent *)event; - -- (BOOL)handleMPKey:(int)key withMask:(int)mask; - @property(nonatomic, retain) RemoteCommandCenter *remoteCommandCenter; @property(nonatomic, retain) InputHelper *inputHelper; diff --git a/osdep/mac/input_helper.swift b/osdep/mac/input_helper.swift index 48e289f409..fb067e4fd0 100644 --- a/osdep/mac/input_helper.swift +++ b/osdep/mac/input_helper.swift @@ -15,21 +15,130 @@ * License along with mpv. If not, see . */ +import Carbon.HIToolbox + class InputHelper: NSObject { var mpv: MPVHelper? var lock = NSCondition() private var input: OpaquePointer? + let keymap: [mp_keymap] = [ + // special keys + mp_keymap(from: Int32(kVK_Return), to: MP_KEY_ENTER), + mp_keymap(from: Int32(kVK_Escape), to: MP_KEY_ESC), + mp_keymap(from: Int32(kVK_Delete), to: MP_KEY_BACKSPACE), + mp_keymap(from: Int32(kVK_Option), to: MP_KEY_BACKSPACE), + mp_keymap(from: Int32(kVK_Control), to: MP_KEY_BACKSPACE), + mp_keymap(from: Int32(kVK_Shift), to: MP_KEY_BACKSPACE), + mp_keymap(from: Int32(kVK_Tab), to: MP_KEY_TAB), + + // cursor keys + mp_keymap(from: Int32(kVK_UpArrow), to: MP_KEY_UP), + mp_keymap(from: Int32(kVK_DownArrow), to: MP_KEY_DOWN), + mp_keymap(from: Int32(kVK_LeftArrow), to: MP_KEY_LEFT), + mp_keymap(from: Int32(kVK_RightArrow), to: MP_KEY_RIGHT), + + // navigation block + mp_keymap(from: Int32(kVK_Help), to: MP_KEY_INSERT), + mp_keymap(from: Int32(kVK_ForwardDelete), to: MP_KEY_DELETE), + mp_keymap(from: Int32(kVK_Home), to: MP_KEY_HOME), + mp_keymap(from: Int32(kVK_End), to: MP_KEY_END), + mp_keymap(from: Int32(kVK_PageUp), to: MP_KEY_PAGE_UP), + mp_keymap(from: Int32(kVK_PageDown), to: MP_KEY_PAGE_DOWN), + + // F-keys + mp_keymap(from: Int32(kVK_F1), to: MP_KEY_F + 1), + mp_keymap(from: Int32(kVK_F2), to: MP_KEY_F + 2), + mp_keymap(from: Int32(kVK_F3), to: MP_KEY_F + 3), + mp_keymap(from: Int32(kVK_F4), to: MP_KEY_F + 4), + mp_keymap(from: Int32(kVK_F5), to: MP_KEY_F + 5), + mp_keymap(from: Int32(kVK_F6), to: MP_KEY_F + 6), + mp_keymap(from: Int32(kVK_F7), to: MP_KEY_F + 7), + mp_keymap(from: Int32(kVK_F8), to: MP_KEY_F + 8), + mp_keymap(from: Int32(kVK_F9), to: MP_KEY_F + 9), + mp_keymap(from: Int32(kVK_F10), to: MP_KEY_F + 10), + mp_keymap(from: Int32(kVK_F11), to: MP_KEY_F + 11), + mp_keymap(from: Int32(kVK_F12), to: MP_KEY_F + 12), + mp_keymap(from: Int32(kVK_F13), to: MP_KEY_F + 13), + mp_keymap(from: Int32(kVK_F14), to: MP_KEY_F + 14), + mp_keymap(from: Int32(kVK_F15), to: MP_KEY_F + 15), + mp_keymap(from: Int32(kVK_F16), to: MP_KEY_F + 16), + mp_keymap(from: Int32(kVK_F17), to: MP_KEY_F + 17), + mp_keymap(from: Int32(kVK_F18), to: MP_KEY_F + 18), + mp_keymap(from: Int32(kVK_F19), to: MP_KEY_F + 19), + mp_keymap(from: Int32(kVK_F20), to: MP_KEY_F + 20), + + // numpad + mp_keymap(from: Int32(kVK_ANSI_KeypadPlus), to: Int32(Character("+").asciiValue ?? 0)), + mp_keymap(from: Int32(kVK_ANSI_KeypadMinus), to: Int32(Character("-").asciiValue ?? 0)), + mp_keymap(from: Int32(kVK_ANSI_KeypadMultiply), to: Int32(Character("*").asciiValue ?? 0)), + mp_keymap(from: Int32(kVK_ANSI_KeypadDivide), to: Int32(Character("/").asciiValue ?? 0)), + mp_keymap(from: Int32(kVK_ANSI_KeypadEnter), to: MP_KEY_KPENTER), + mp_keymap(from: Int32(kVK_ANSI_KeypadDecimal), to: MP_KEY_KPDEC), + mp_keymap(from: Int32(kVK_ANSI_Keypad0), to: MP_KEY_KP0), + mp_keymap(from: Int32(kVK_ANSI_Keypad1), to: MP_KEY_KP1), + mp_keymap(from: Int32(kVK_ANSI_Keypad2), to: MP_KEY_KP2), + mp_keymap(from: Int32(kVK_ANSI_Keypad3), to: MP_KEY_KP3), + mp_keymap(from: Int32(kVK_ANSI_Keypad4), to: MP_KEY_KP4), + mp_keymap(from: Int32(kVK_ANSI_Keypad5), to: MP_KEY_KP5), + mp_keymap(from: Int32(kVK_ANSI_Keypad6), to: MP_KEY_KP6), + mp_keymap(from: Int32(kVK_ANSI_Keypad7), to: MP_KEY_KP7), + mp_keymap(from: Int32(kVK_ANSI_Keypad8), to: MP_KEY_KP8), + mp_keymap(from: Int32(kVK_ANSI_Keypad9), to: MP_KEY_KP9), + + mp_keymap(from: 0, to: 0) + ] + @objc init(_ input: OpaquePointer? = nil, _ mpv: MPVHelper? = nil) { super.init() self.input = input self.mpv = mpv } - @objc func putKey(_ key: Int32, modifiers: NSEvent.ModifierFlags = .init(rawValue: 0)) { + @objc func put( + key: Int32, + modifiers: NSEvent.ModifierFlags = .init(rawValue: 0), + type: NSEvent.EventType = .applicationDefined + ) { lock.withLock { - guard let input = input else { return } - mp_input_put_key(input, key | mapModifier(modifiers)) + putKey(key, modifiers: modifiers, type: type) + } + } + + private func putKey( + _ key: Int32, + modifiers: NSEvent.ModifierFlags = .init(rawValue: 0), + type: NSEvent.EventType = .applicationDefined + ) { + if key < 1 { return } + + guard let input = input else { return } + let code = key | mapModifier(modifiers) | mapType(type) + mp_input_put_key(input, code) + + if type == .keyUp { + mp_input_put_key(input, MP_INPUT_RELEASE_ALL) + } + } + + @objc func processKey(event: NSEvent) -> Bool { + if event.type != .keyDown && event.type != .keyUp { return false } + if NSApp.mainMenu?.performKeyEquivalent(with: event) ?? false || event.isARepeat { return true } + + return lock.withLock { + let mpkey = lookup_keymap_table(keymap, Int32(event.keyCode)) + if mpkey > 0 { + putKey(mpkey, modifiers: event.modifierFlags, type: event.type) + return true + } + + guard let chars = event.characters, let charsNoMod = event.charactersIgnoringModifiers else { return false } + let key = (useAltGr() && event.modifierFlags.contains(.optionRight)) ? chars : charsNoMod + key.withCString { + var bstr = bstr0($0) + putKey(bstr_decode_utf8(bstr, &bstr), modifiers: event.modifierFlags, type: event.type) + } + return true } } @@ -72,9 +181,17 @@ class InputHelper: NSObject { } } + private func mapType(_ type: NSEvent.EventType) -> Int32 { + let typeMapping: [NSEvent.EventType:UInt32] = [ + .keyDown: MP_KEY_STATE_DOWN, + .keyUp: MP_KEY_STATE_UP, + ] + + return Int32(typeMapping[type] ?? 0); + } + private func mapModifier(_ modifiers: NSEvent.ModifierFlags) -> Int32 { var mask: UInt32 = 0; - guard let input = input else { return Int32(mask) } if modifiers.contains(.shift) { mask |= MP_KEY_MODIFIER_SHIFT @@ -85,9 +202,7 @@ class InputHelper: NSObject { if modifiers.contains(.command) { mask |= MP_KEY_MODIFIER_META } - if modifiers.contains(.optionLeft) || - modifiers.contains(.optionRight) && !mp_input_use_alt_gr(input) - { + if modifiers.contains(.optionLeft) || modifiers.contains(.optionRight) && !useAltGr() { mask |= MP_KEY_MODIFIER_ALT } @@ -111,11 +226,9 @@ class InputHelper: NSObject { } } - @objc func useAltGr() -> Bool { - lock.withLock { - guard let input = input else { return false } - return mp_input_use_alt_gr(input) - } + private func useAltGr() -> Bool { + guard let input = input else { return false } + return mp_input_use_alt_gr(input) } @objc func wakeup() { diff --git a/osdep/mac/remote_command_center.swift b/osdep/mac/remote_command_center.swift index 0bfced2422..6dd02e0ada 100644 --- a/osdep/mac/remote_command_center.swift +++ b/osdep/mac/remote_command_center.swift @@ -155,7 +155,7 @@ class RemoteCommandCenter: NSObject { self.configs[event.command]?.state = state } - EventsResponder.sharedInstance().handleMPKey(config.key, withMask: Int32(state)) + EventsResponder.sharedInstance().inputHelper.put(key: config.key | Int32(state)) return .success } diff --git a/osdep/mac/swift_bridge.h b/osdep/mac/swift_bridge.h index 2c0c9a9225..b47fbbaf05 100644 --- a/osdep/mac/swift_bridge.h +++ b/osdep/mac/swift_bridge.h @@ -28,6 +28,7 @@ #include "player/core.h" #include "input/input.h" #include "input/event.h" +#include "input/keycodes.h" #include "video/out/win_state.h" #include "osdep/mac/application_objc.h" diff --git a/video/out/mac/view.swift b/video/out/mac/view.swift index ea4a715a28..8085ec8f20 100644 --- a/video/out/mac/view.swift +++ b/video/out/mac/view.swift @@ -53,7 +53,7 @@ class View: NSView, CALayerDelegate { addTrackingArea(tracker!) if containsMouseLocation() { - input?.putKey(SWIFT_KEY_MOUSE_LEAVE) + input?.put(key: SWIFT_KEY_MOUSE_LEAVE) } } @@ -118,14 +118,14 @@ class View: NSView, CALayerDelegate { override func mouseEntered(with event: NSEvent) { if input?.mouseEnabled() ?? true { - input?.putKey(SWIFT_KEY_MOUSE_ENTER) + input?.put(key: SWIFT_KEY_MOUSE_ENTER) } common.updateCursorVisibility() } override func mouseExited(with event: NSEvent) { if input?.mouseEnabled() ?? true { - input?.putKey(SWIFT_KEY_MOUSE_LEAVE) + input?.put(key: SWIFT_KEY_MOUSE_LEAVE) } common.titleBar?.hide() common.setCursorVisibility(true) @@ -202,7 +202,7 @@ class View: NSView, CALayerDelegate { func signalMouseEvent(_ event: NSEvent, _ state: UInt32) { hasMouseDown = state == MP_KEY_STATE_DOWN let mpkey = getMpvButton(event) - input?.putKey((mpkey | Int32(state)), modifiers: event.modifierFlags) + input?.put(key: (mpkey | Int32(state)), modifiers: event.modifierFlags) } func signalMouseMovement(_ event: NSEvent) { @@ -250,7 +250,7 @@ class View: NSView, CALayerDelegate { mpkey = deltaX > 0 ? SWIFT_WHEEL_LEFT : SWIFT_WHEEL_RIGHT } - input?.putKey(mpkey, modifiers: modifiers) + input?.put(key: mpkey, modifiers: modifiers) } } diff --git a/video/out/mac/window.swift b/video/out/mac/window.swift index 59b9098af0..31953abe9d 100644 --- a/video/out/mac/window.swift +++ b/video/out/mac/window.swift @@ -556,7 +556,7 @@ class Window: NSWindow, NSWindowDelegate { } func windowShouldClose(_ sender: NSWindow) -> Bool { - input?.putKey(MP_KEY_CLOSE_WIN) + input?.put(key: MP_KEY_CLOSE_WIN) return false }