Feature add hint to remap option as alt key (#12021)

This commit is contained in:
William Hou 2025-01-19 23:34:04 -05:00 committed by GitHub
parent 53a5350292
commit 7133969e3a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 105 additions and 0 deletions

View file

@ -2348,6 +2348,31 @@ extern "C" {
*/ */
#define SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH "SDL_MAC_OPENGL_ASYNC_DISPATCH" #define SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH "SDL_MAC_OPENGL_ASYNC_DISPATCH"
/**
* A variable controlling whether the Option () key on macOS should be remapped
* to act as the Alt key.
*
* The variable can be set to the following values:
*
* - "none": The Option key is not remapped to Alt. (default)
* - "only_left": Only the left Option key is remapped to Alt.
* - "only_right": Only the right Option key is remapped to Alt.
* - "both": Both Option keys are remapped to Alt.
*
* This will prevent the triggering of key compositions that rely on the Option
* key, but will still send the Alt modifier for keyboard events. In the case
* that both Alt and Option are pressed, the Option key will be ignored. This is
* particularly useful for applications like terminal emulators and graphical
* user interfaces (GUIs) that rely on Alt key functionality for shortcuts or
* navigation. This does not apply to SDL_GetKeyFromScancode and only has an
* effect if IME is enabled.
*
* This hint can be set anytime.
*
* \since This hint is available since 3.2.0
*/
#define SDL_HINT_MAC_OPTION_AS_ALT "SDL_MAC_OPTION_AS_ALT"
/** /**
* A variable controlling whether SDL_EVENT_MOUSE_WHEEL event values will have * A variable controlling whether SDL_EVENT_MOUSE_WHEEL event values will have
* momentum on macOS. * momentum on macOS.

View file

@ -369,6 +369,26 @@ static void UpdateKeymap(SDL_CocoaVideoData *data, bool send_event)
SDL_SetKeymap(keymap, send_event); SDL_SetKeymap(keymap, send_event);
} }
static void SDLCALL SDL_MacOptionAsAltChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata;
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
if (hint && *hint) {
if (SDL_strcmp(hint, "none") == 0) {
data.option_as_alt = OptionAsAltNone;
} else if (SDL_strcmp(hint, "only_left") == 0) {
data.option_as_alt = OptionAsAltOnlyLeft;
} else if (SDL_strcmp(hint, "only_right") == 0) {
data.option_as_alt = OptionAsAltOnlyRight;
} else if (SDL_strcmp(hint, "both") == 0) {
data.option_as_alt = OptionAsAltBoth;
}
} else {
data.option_as_alt = OptionAsAltNone;
}
}
void Cocoa_InitKeyboard(SDL_VideoDevice *_this) void Cocoa_InitKeyboard(SDL_VideoDevice *_this)
{ {
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
@ -385,6 +405,8 @@ void Cocoa_InitKeyboard(SDL_VideoDevice *_this)
data.modifierFlags = (unsigned int)[NSEvent modifierFlags]; data.modifierFlags = (unsigned int)[NSEvent modifierFlags];
SDL_ToggleModState(SDL_KMOD_CAPS, (data.modifierFlags & NSEventModifierFlagCapsLock) ? true : false); SDL_ToggleModState(SDL_KMOD_CAPS, (data.modifierFlags & NSEventModifierFlagCapsLock) ? true : false);
SDL_AddHintCallback(SDL_HINT_MAC_OPTION_AS_ALT, SDL_MacOptionAsAltChanged, _this);
} }
bool Cocoa_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props) bool Cocoa_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
@ -437,6 +459,51 @@ bool Cocoa_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
return true; return true;
} }
static NSEvent *ReplaceEvent(NSEvent *event, OptionAsAlt option_as_alt)
{
if (option_as_alt == OptionAsAltNone) {
return event;
}
const unsigned int modflags = (unsigned int)[event modifierFlags];
bool ignore_alt_characters = false;
bool lalt_pressed = IsModifierKeyPressed(modflags, NX_DEVICELALTKEYMASK,
NX_DEVICERALTKEYMASK, NX_ALTERNATEMASK);
bool ralt_pressed = IsModifierKeyPressed(modflags, NX_DEVICERALTKEYMASK,
NX_DEVICELALTKEYMASK, NX_ALTERNATEMASK);
if (option_as_alt == OptionAsAltOnlyLeft && lalt_pressed) {
ignore_alt_characters = true;
} else if (option_as_alt == OptionAsAltOnlyRight && ralt_pressed) {
ignore_alt_characters = true;
} else if (option_as_alt == OptionAsAltBoth && (lalt_pressed || ralt_pressed)) {
ignore_alt_characters = true;
}
bool cmd_pressed = modflags & NX_COMMANDMASK;
bool ctrl_pressed = modflags & NX_CONTROLMASK;
ignore_alt_characters = ignore_alt_characters && !cmd_pressed && !ctrl_pressed;
if (ignore_alt_characters) {
NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers];
return [NSEvent keyEventWithType:[event type]
location:[event locationInWindow]
modifierFlags:modflags
timestamp:[event timestamp]
windowNumber:[event windowNumber]
context:nil
characters:charactersIgnoringModifiers
charactersIgnoringModifiers:charactersIgnoringModifiers
isARepeat:[event isARepeat]
keyCode:[event keyCode]];
}
return event;
}
void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event) void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event)
{ {
unsigned short scancode; unsigned short scancode;
@ -446,6 +513,10 @@ void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event)
return; // can happen when returning from fullscreen Space on shutdown return; // can happen when returning from fullscreen Space on shutdown
} }
if ([event type] == NSEventTypeKeyDown || [event type] == NSEventTypeKeyUp) {
event = ReplaceEvent(event, data.option_as_alt);
}
scancode = [event keyCode]; scancode = [event keyCode];
if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) { if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {

View file

@ -44,6 +44,14 @@
@class SDL3TranslatorResponder; @class SDL3TranslatorResponder;
typedef enum
{
OptionAsAltNone,
OptionAsAltOnlyLeft,
OptionAsAltOnlyRight,
OptionAsAltBoth,
} OptionAsAlt;
@interface SDL_CocoaVideoData : NSObject @interface SDL_CocoaVideoData : NSObject
@property(nonatomic) int allow_spaces; @property(nonatomic) int allow_spaces;
@property(nonatomic) int trackpad_is_touch_only; @property(nonatomic) int trackpad_is_touch_only;
@ -53,6 +61,7 @@
@property(nonatomic) NSInteger clipboard_count; @property(nonatomic) NSInteger clipboard_count;
@property(nonatomic) IOPMAssertionID screensaver_assertion; @property(nonatomic) IOPMAssertionID screensaver_assertion;
@property(nonatomic) SDL_Mutex *swaplock; @property(nonatomic) SDL_Mutex *swaplock;
@property(nonatomic) OptionAsAlt option_as_alt;
@end @end
// Utility functions // Utility functions