Skip to content

fix: uppercase characters when Option modifier is pressed#329

Merged
akitchen merged 3 commits intokeycastr:mainfrom
Hephaest:main
Aug 3, 2025
Merged

fix: uppercase characters when Option modifier is pressed#329
akitchen merged 3 commits intokeycastr:mainfrom
Hephaest:main

Conversation

@Hephaest
Copy link
Contributor

@Hephaest Hephaest commented Jun 27, 2025

Description

When pressing Option+character (e.g., Option+L), the displayed keystroke was showing lowercase characters (⌥l) while Command+character correctly showed uppercase (⌘L).

Screen.Recording.2025-06-27.at.13.30.05.mov

Changlog

The fix updates the condition to include the Option modifier flag, ensuring consistent behavior across all modifier keys.

Root Cause

This bug seems to be caused by the isCommand flag only checking for Control and Command modifiers, but not Option.

// KCEventTransformer.m
BOOL isCommand = (_modifiers & (NSEventModifierFlagControl | NSEventModifierFlagCommand)) != 0; // ← here!

// Commands and shifted keystrokes should be uppercased
if (isCommand || hasShiftModifier)
{
    // Unless it is a special case - do not shift keycode 27
    if (keystroke.keyCode != 27) {
        mutableResponse = [[mutableResponse uppercaseString] mutableCopy];
    }
}

Demo

Screen.Recording.2025-06-29.at.12.03.27.mov

When pressing Option+character (e.g., Option+L), the displayed keystroke
was showing lowercase characters (⌥l) while Command+character correctly
showed uppercase (⌘L). This was caused by the isCommand flag only checking
for Control and Command modifiers, but not Option.

The fix updates the condition to include the Option modifier flag, ensuring
consistent behavior across all modifier keys.
@Hephaest
Copy link
Contributor Author

Hi @akitchen Could you help review this PR?

I think this will be important for users like me—today, many rely on Option + letter shortcuts, and I'm sure this fix will benefit countless KeyCastr lovers. 😊

@akitchen
Copy link
Member

akitchen commented Jun 27, 2025

Hey, thanks for opening a PR about this. There's a bit of context here.

Originally this choice was intentional - command keystrokes (with Command or Control modifier) would always be capitalized, but non-command keystrokes would not. For a long while modified keys would be translated by a different mechanism which gave unexpected results for some option-modified keys which seemed like bugs.

Fast forward to today and there's a pretty decent translation solution in place with an option to display modified keys or not, with a translation solution which works well for all locales I'm able to test. There are some open issues with complaints about modifier translation in other scripts or custom layouts but it's not clear that it's anything KeyCastr can solve for. Regardless, keys with the shift modifier are always translated (i.e. shifted), which could be considered a bug, while option-modified keys are not. I can understand that it looks strange.

So I wonder (and wonder if @sdeken has thoughts here too) whether we should take this change and simply always capitalize modified keys, or go the other way and not display e.g. Shift-S with a capital S anymore unless the option to apply modifiers is enabled. Either way I think you should also update the unit tests for the event transformer, which aren't currently run by GitHub.

This is also still a very legacy area of code I've been thinking about refactoring further, but haven't had much time for keycastr lately. I'm planning on trying to put out a release soon, so hopefully Stephen can chime in and we can consider what we want to do here.

@Hephaest
Copy link
Contributor Author

Hey @akitchen ,

Thanks for sharing the detailed context! I did feel there might be some reasons for the current strange behaviors, especially considering the wider audience.

Per your suggestion, I’ve added unit tests to the PR (surprisingly, none existed before). I’m not yet fluent with the iOS testing framework, so I leaned on AI for guidance, but I also ran the tests locally and everything passes: ⬇️
image

I’m happy with whichever direction you and @sdeken decide to take—my local build already solves the issue on my end—and I’m excited to see where the project goes next. Thanks again! 😊

@akitchen
Copy link
Member

Thanks for generating some tests for this; what I had in mind was to update (or add) a couple cases to https://github.com/keycastr/keycastr/blob/main/keycastr/KCVisualizerTests/KCKeystrokeConversionTests.m

@Hephaest
Copy link
Contributor Author

Hephaest commented Jun 29, 2025

Thanks for generating some tests for this; what I had in mind was to update (or add) a couple cases to https://github.com/keycastr/keycastr/blob/main/keycastr/KCVisualizerTests/KCKeystrokeConversionTests.m

Hey @akitchen Thanks for the hint!

After reading the test case of KCKeystrokeConversionTests.m, I think I also need to update my handling logic so it won't make unnecessary breaks.

image

All test cases have been passed ✅ and the demo has been update in the PR description ⬆️, feel free to check out 😃

@akitchen akitchen merged commit 5d8b99d into keycastr:main Aug 3, 2025
@akitchen akitchen added this to the 0.10.4 milestone Aug 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants