[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
This commit is contained in:
dev 2024-01-12 12:08:37 +01:00 committed by Martin Fleisz
parent db73c562a2
commit feceb1c0f3

View File

@ -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