ref:33bdb011e233eedf337341d28c2608ce56a4eb94

fix(macos): provide left/right identity for modifiers (#5115)

SHA: 33bdb011e233eedf337341d28c2608ce56a4eb94
Author: martona <marton@anka.me>
Date: 2026-05-14 21:59
Parents: 91615e3
1 files changed +53 -27
Type
src/platform/macos/input.cpp +53 −27
@@ -11,6 +11,7 @@
#include <ApplicationServices/ApplicationServices.h>
#import <Carbon/Carbon.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hidsystem/IOLLEvent.h>
#include <mach/mach.h>
// local includes
@@ -36,6 +37,7 @@
CGEventSourceRef source {};
// keyboard related stuff
CGEventSourceRef keyboard_source {};
CGEventFlags kb_flags {};
// mouse related stuff
@@ -245,5 +247,42 @@
return temp_map->mac_keycode;
}
struct modifier_flags_t {
CGEventFlags generic {};
CGEventFlags device {};
CGEventFlags all_devices {};
};
bool modifier_flags_for_key(int key, modifier_flags_t &flags) {
switch (key) {
case kVK_Shift:
flags = {kCGEventFlagMaskShift, NX_DEVICELSHIFTKEYMASK, NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK};
return true;
case kVK_RightShift:
flags = {kCGEventFlagMaskShift, NX_DEVICERSHIFTKEYMASK, NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK};
return true;
case kVK_Command:
flags = {kCGEventFlagMaskCommand, NX_DEVICELCMDKEYMASK, NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK};
return true;
case kVK_RightCommand:
flags = {kCGEventFlagMaskCommand, NX_DEVICERCMDKEYMASK, NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK};
return true;
case kVK_Option:
flags = {kCGEventFlagMaskAlternate, NX_DEVICELALTKEYMASK, NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK};
return true;
case kVK_RightOption:
flags = {kCGEventFlagMaskAlternate, NX_DEVICERALTKEYMASK, NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK};
return true;
case kVK_Control:
flags = {kCGEventFlagMaskControl, NX_DEVICELCTLKEYMASK, NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK};
return true;
case kVK_RightControl:
flags = {kCGEventFlagMaskControl, NX_DEVICERCTLKEYMASK, NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK};
return true;
default:
return false;
}
}
void keyboard_update(input_t &input, uint16_t modcode, bool release, uint8_t flags) {
auto key = keysym(modcode);
@@ -256,43 +295,28 @@
auto macos_input = ((macos_input_t *) input.get());
CGEventRef event = nullptr;
modifier_flags_t modifier_flags;
if (key == kVK_Shift || key == kVK_RightShift ||
key == kVK_Command || key == kVK_RightCommand ||
key == kVK_Option || key == kVK_RightOption ||
key == kVK_Control || key == kVK_RightControl) {
event = CGEventCreate(macos_input->source);
if (modifier_flags_for_key(key, modifier_flags)) {
event = CGEventCreateKeyboardEvent(macos_input->keyboard_source, key, !release);
if (!event) {
return;
}
CGEventSetIntegerValueField(event, kCGKeyboardEventKeycode, key);
CGEventFlags mask;
switch (key) {
case kVK_Shift:
case kVK_RightShift:
mask = kCGEventFlagMaskShift;
break;
case kVK_Command:
case kVK_RightCommand:
mask = kCGEventFlagMaskCommand;
break;
case kVK_Option:
case kVK_RightOption:
mask = kCGEventFlagMaskAlternate;
break;
case kVK_Control:
case kVK_RightControl:
mask = kCGEventFlagMaskControl;
break;
if (release) {
macos_input->kb_flags &= ~modifier_flags.device;
if ((macos_input->kb_flags & modifier_flags.all_devices) == 0) {
macos_input->kb_flags &= ~modifier_flags.generic;
}
} else {
macos_input->kb_flags |= modifier_flags.generic | modifier_flags.device;
}
macos_input->kb_flags = release ? macos_input->kb_flags & ~mask : macos_input->kb_flags | mask;
CGEventSetType(event, kCGEventFlagsChanged);
} else {
event = CGEventCreateKeyboardEvent(macos_input->source, key, !release);
event = CGEventCreateKeyboardEvent(macos_input->keyboard_source, key, !release);
if (!event) {
return;
}
@@ -301,6 +325,6 @@
}
CGEventSetFlags(event, macos_input->kb_flags);
CGEventPost(kCGSessionEventTap, event);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
@@ -567,5 +591,6 @@
CFRelease(mode);
macos_input->source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
macos_input->keyboard_source = CGEventSourceCreate(kCGEventSourceStatePrivate);
macos_input->kb_flags = 0;
@@ -584,6 +609,7 @@
const auto *input = static_cast<macos_input_t *>(p);
CFRelease(input->source);
CFRelease(input->keyboard_source);
CFRelease(input->mouse_event);
delete input;