From feceb1c0f3f20045cf48a2b7679982d2ea84ffa1 Mon Sep 17 00:00:00 2001 From: dev Date: Fri, 12 Jan 2024 12:08:37 +0100 Subject: [PATCH] [client,mac] fix keyboard state sync * release all keyboard modifiers on pause * release/sync keyboard modifier states on resume * update modifier states on keyDown, keyUp and flagsChanged --- client/Mac/MRDPView.m | 221 +++++++++++++++++++++--------------------- 1 file changed, 109 insertions(+), 112 deletions(-) diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index 6c82753c3..b0dabec30 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -37,6 +37,7 @@ #import "freerdp/freerdp.h" #import "freerdp/types.h" +#import "freerdp/config.h" #import "freerdp/channels/channels.h" #import "freerdp/gdi/gdi.h" #import "freerdp/gdi/dc.h" @@ -417,7 +418,7 @@ DWORD WINAPI mac_client_thread(void *param) mf_scale_mouse_event(context, PTR_FLAGS_MOVE, x, y); } -DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) +static DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) { /** * In 99% of cases, the given key code is truly keyboard independent. @@ -473,6 +474,22 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) return keyCode; } +- (void)flagsChanged:(NSEvent *)event +{ + if (!is_connected) + return; + + DWORD modFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; + + WINPR_ASSERT(instance); + WINPR_ASSERT(instance->context); + + rdpInput *input = instance->context->input; + + updateFlagStates(input, modFlags, kbdModFlags); + kbdModFlags = modFlags; +} + - (void)keyDown:(NSEvent *)event { DWORD keyCode; @@ -485,6 +502,8 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) if (!is_connected) return; + [self flagsChanged:event]; + keyFlags = KBD_FLAGS_DOWN; keyCode = [event keyCode]; characters = [event charactersIgnoringModifiers]; @@ -500,12 +519,12 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0; scancode &= 0xFF; vkcode &= 0xFF; -#if 0 - WLog_ERR(TAG, - "keyDown: keyCode: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s", + +#if defined(WITH_DEBUG_KBD) + WLog_DBG(TAG, "keyDown: keyCode: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s", keyCode, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode)); #endif - sync_keyboard_state(instance); + WINPR_ASSERT(instance->context); freerdp_input_send_keyboard_event(instance->context->input, keyFlags, scancode); } @@ -522,6 +541,8 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) if (!is_connected) return; + [self flagsChanged:event]; + keyFlags = KBD_FLAGS_RELEASE; keyCode = [event keyCode]; characters = [event charactersIgnoringModifiers]; @@ -537,107 +558,100 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0; scancode &= 0xFF; vkcode &= 0xFF; -#if 0 - WLog_DBG(TAG, - "keyUp: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s", +#if defined(WITH_DEBUG_KBD) + WLog_DBG(TAG, "keyUp: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s", keyCode, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode)); #endif WINPR_ASSERT(instance->context); freerdp_input_send_keyboard_event(instance->context->input, keyFlags, scancode); } -- (void)flagsChanged:(NSEvent *)event +static BOOL updateFlagState(rdpInput *input, DWORD modFlags, DWORD kbdModFlags, DWORD flag) { - int key; - DWORD keyFlags; - DWORD vkcode; - DWORD scancode; - DWORD modFlags; - rdpInput *input; + const BOOL press = ((modFlags & flag) != 0) && ((kbdModFlags & flag) == 0); + const BOOL release = ((modFlags & flag) == 0) && ((kbdModFlags & flag) != 0); + DWORD keyFlags = press ? KBD_FLAGS_DOWN : (release ? KBD_FLAGS_RELEASE : 0); + const char *name = NULL; + DWORD scancode = 0; - if (!is_connected) - return; + switch (flag) + { + case NSEventModifierFlagCapsLock: + name = "NSEventModifierFlagCapsLock"; + scancode = RDP_SCANCODE_CAPSLOCK; + break; + case NSEventModifierFlagShift: + name = "NSEventModifierFlagShift"; + scancode = RDP_SCANCODE_LSHIFT; + break; - keyFlags = 0; - key = [event keyCode]; - modFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; - vkcode = GetVirtualKeyCodeFromKeycode(key, WINPR_KEYCODE_TYPE_APPLE); - scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4); - keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0; + case NSEventModifierFlagControl: + name = "NSEventModifierFlagControl"; + scancode = RDP_SCANCODE_LCONTROL; + break; + + case NSEventModifierFlagOption: + name = "NSEventModifierFlagOption"; + scancode = RDP_SCANCODE_LMENU; + break; + + case NSEventModifierFlagCommand: + name = "NSEventModifierFlagCommand"; + scancode = RDP_SCANCODE_LWIN; + break; + + case NSEventModifierFlagNumericPad: + name = "NSEventModifierFlagNumericPad"; + scancode = RDP_SCANCODE_NUMLOCK; + break; + + case NSEventModifierFlagHelp: + name = "NSEventModifierFlagHelp"; + scancode = RDP_SCANCODE_HELP; + break; + + case NSEventModifierFlagFunction: + name = "NSEventModifierFlagFunction"; + scancode = RDP_SCANCODE_HELP; + break; + + default: + WLog_ERR(TAG, "Invalid flag: 0x%08" PRIx32 ", not supported", flag); + return FALSE; + } + + keyFlags |= (scancode & KBDEXT); scancode &= 0xFF; - vkcode &= 0xFF; -#if 0 - WLog_DBG(TAG, - "flagsChanged: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X extended: %d name: %s modFlags: 0x%04X", - key - 8, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode), modFlags); - - if (modFlags & NSEventModifierFlagCapsLock) - WLog_DBG(TAG, "NSEventModifierFlagCapsLock"); - - if (modFlags & NSEventModifierFlagShift) - WLog_DBG(TAG, "NSEventModifierFlagShift"); - - if (modFlags & NSEventModifierFlagControl) - WLog_DBG(TAG, "NSEventModifierFlagControl"); - - if (modFlags & NSEventModifierFlagOption) - WLog_DBG(TAG, "NSEventModifierFlagOption"); - - if (modFlags & NSEventModifierFlagCommand) - WLog_DBG(TAG, "NSEventModifierFlagCommand"); - - if (modFlags & NSEventModifierFlagNumericPad) - WLog_DBG(TAG, "NSEventModifierFlagNumericPad"); - - if (modFlags & NSEventModifierFlagHelp) - WLog_DBG(TAG, "NSEventModifierFlagHelp"); +#if defined(WITH_DEBUG_KBD) + if (press || release) + WLog_DBG(TAG, "changing flag %s[0x%08" PRIx32 "] to %s", name, flag, + press ? "DOWN" : "RELEASE"); #endif - WINPR_ASSERT(instance); - WINPR_ASSERT(instance->context); + if (press) + return freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode); - input = instance->context->input; + if (release) + return freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode); - if ((modFlags & NSEventModifierFlagCapsLock) && !(kbdModFlags & NSEventModifierFlagCapsLock)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode); - else if (!(modFlags & NSEventModifierFlagCapsLock) && - (kbdModFlags & NSEventModifierFlagCapsLock)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode); + return TRUE; +} - if ((modFlags & NSEventModifierFlagShift) && !(kbdModFlags & NSEventModifierFlagShift)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode); - else if (!(modFlags & NSEventModifierFlagShift) && (kbdModFlags & NSEventModifierFlagShift)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode); +static BOOL updateFlagStates(rdpInput *input, UINT32 modFlags, UINT32 kbdModFlags) +{ + updateFlagState(input, modFlags, kbdModFlags, NSEventModifierFlagCapsLock); + updateFlagState(input, modFlags, kbdModFlags, NSEventModifierFlagShift); + updateFlagState(input, modFlags, kbdModFlags, NSEventModifierFlagControl); + updateFlagState(input, modFlags, kbdModFlags, NSEventModifierFlagOption); + updateFlagState(input, modFlags, kbdModFlags, NSEventModifierFlagCommand); + updateFlagState(input, modFlags, kbdModFlags, NSEventModifierFlagNumericPad); + return TRUE; +} - if ((modFlags & NSEventModifierFlagControl) && !(kbdModFlags & NSEventModifierFlagControl)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode); - else if (!(modFlags & NSEventModifierFlagControl) && (kbdModFlags & NSEventModifierFlagControl)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode); - - if ((modFlags & NSEventModifierFlagOption) && !(kbdModFlags & NSEventModifierFlagOption)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode); - else if (!(modFlags & NSEventModifierFlagOption) && (kbdModFlags & NSEventModifierFlagOption)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode); - - if ((modFlags & NSEventModifierFlagCommand) && !(kbdModFlags & NSEventModifierFlagCommand)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode); - else if (!(modFlags & NSEventModifierFlagCommand) && (kbdModFlags & NSEventModifierFlagCommand)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode); - - if ((modFlags & NSEventModifierFlagNumericPad) && - !(kbdModFlags & NSEventModifierFlagNumericPad)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode); - else if (!(modFlags & NSEventModifierFlagNumericPad) && - (kbdModFlags & NSEventModifierFlagNumericPad)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode); - - if ((modFlags & NSEventModifierFlagHelp) && !(kbdModFlags & NSEventModifierFlagHelp)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode); - else if (!(modFlags & NSEventModifierFlagHelp) && (kbdModFlags & NSEventModifierFlagHelp)) - freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode); - - kbdModFlags = modFlags; +static BOOL releaseFlagStates(rdpInput *input, UINT32 kbdModFlags) +{ + return updateFlagStates(input, 0, kbdModFlags); } - (void)releaseResources @@ -751,6 +765,8 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) { [self removeTrackingArea:ta]; } + releaseFlagStates(instance->context->input, kbdModFlags); + kbdModFlags = 0; } - (void)resume @@ -758,6 +774,10 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) if (!self.is_connected) return; + releaseFlagStates(instance->context->input, kbdModFlags); + kbdModFlags = 0; + freerdp_input_send_focus_in_event(instance->context->input, 0); + dispatch_async(dispatch_get_main_queue(), ^{ self->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 @@ -1496,27 +1516,4 @@ void windows_to_apple_cords(MRDPView *view, NSRect *r) }); } -void sync_keyboard_state(freerdp *instance) -{ - UINT32 flags = 0; - CGEventFlags currentFlags = CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState); - mfContext *context; - - WINPR_ASSERT(instance); - context = (mfContext *)instance->context; - WINPR_ASSERT(context); - - if (context->kbdFlags != currentFlags) - { - if (currentFlags & kCGEventFlagMaskAlphaShift) - flags |= KBD_SYNC_CAPS_LOCK; - - if (currentFlags & kCGEventFlagMaskNumericPad) - flags |= KBD_SYNC_NUM_LOCK; - - freerdp_input_send_synchronize_event(instance->context->input, flags); - context->kbdFlags = currentFlags; - } -} - @end