From 9e760bf123e974332fcbd74cadc51daf6d659953 Mon Sep 17 00:00:00 2001 From: Nick Borovets Date: Thu, 19 Feb 2026 16:20:10 +0300 Subject: [PATCH 1/4] Add Windows keystroke transformation support Enhance KCEventTransformer to include a method for transforming keystrokes to their Windows equivalents. Update KCDefaultVisualizer to display both macOS and Windows keystroke representations when applicable. --- keycastr/KCDefaultVisualizer.m | 13 ++++++++- keycastr/KCEventTransformer.h | 2 ++ keycastr/KCEventTransformer.m | 49 ++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/keycastr/KCDefaultVisualizer.m b/keycastr/KCDefaultVisualizer.m index 32614cc..0fb6d9c 100644 --- a/keycastr/KCDefaultVisualizer.m +++ b/keycastr/KCDefaultVisualizer.m @@ -33,6 +33,7 @@ #import "KCDefaultVisualizer.h" #import "KCKeystroke.h" #import "KCMouseEvent.h" +#import "KCEventTransformer.h" #import "NSBezierPath+RoundedRect.h" #import "NSUserDefaults+Utility.h" @@ -316,7 +317,17 @@ - (void)addKeystroke:(KCKeystroke *)keystroke [self abandonCurrentBezelView]; } - [self appendString:[keystroke convertToString]]; + NSString *macString = [keystroke convertToString]; + NSString *winString = [[KCEventTransformer currentTransformer] transformedValueForWindows:keystroke]; + + NSString *displayString; + if (winString.length > 0) { + displayString = [NSString stringWithFormat:@"%@ | %@", macString, winString]; + } else { + displayString = macString; + } + + [self appendString:displayString]; } - (void)appendString:(NSString *)string diff --git a/keycastr/KCEventTransformer.h b/keycastr/KCEventTransformer.h index 5211c3b..e0ff76b 100644 --- a/keycastr/KCEventTransformer.h +++ b/keycastr/KCEventTransformer.h @@ -41,4 +41,6 @@ - (id)transformedValue:(KCKeycastrEvent *)event; +- (NSString *)transformedValueForWindows:(KCKeycastrEvent *)event; + @end diff --git a/keycastr/KCEventTransformer.m b/keycastr/KCEventTransformer.m index 31f4534..e0de3a1 100644 --- a/keycastr/KCEventTransformer.m +++ b/keycastr/KCEventTransformer.m @@ -322,6 +322,55 @@ - (id)transformedValue:(KCKeycastrEvent *)event return mutableResponse; } +- (NSString *)transformedValueForWindows:(KCKeycastrEvent *)event { + if (![event isKindOfClass:[KCKeystroke class]]) { + return nil; + } + + KCKeystroke *keystroke = (KCKeystroke *)event; + NSEventModifierFlags modifiers = event.modifierFlags; + + BOOL isCommand = (modifiers & NSEventModifierFlagCommand) != 0; + BOOL isControl = (modifiers & NSEventModifierFlagControl) != 0; + BOOL isOption = (modifiers & NSEventModifierFlagOption) != 0; + BOOL isShift = (modifiers & NSEventModifierFlagShift) != 0; + + // Only show Windows equivalent if there are modifiers (Command, Control, or Option) + // We treat Shift-only as a "simple letter" case usually, unless it's a special key? + // User said: "don't duplicate simple letters like 'a | a'". + // Shift+A -> "A". Windows: "Shift+A"? Or just "A"? + // Usually Windows shortcuts are Ctrl+C. + // Let's require Command, Control, or Option for now. + if (!isCommand && !isControl && !isOption) { + return nil; + } + + NSMutableArray *parts = [NSMutableArray array]; + + if (isControl) [parts addObject:@"Win"]; + if (isCommand) [parts addObject:@"Ctrl"]; + if (isOption) [parts addObject:@"Alt"]; + if (isShift) [parts addObject:@"Shift"]; + + // Get the character key + NSString *charString = nil; + NSString *specialKeyString = [[self _specialKeys] objectForKey:@(keystroke.keyCode)]; + if (specialKeyString) { + // We might want to map some symbols to text if possible, but keeping them as is for now is safer + // unless we have a map for Windows names. + // For example, arrow keys are symbols in _specialKeys. + charString = specialKeyString; + } else { + charString = [self translatedCharacterForKeystroke:keystroke]; + } + + if (charString.length > 0) { + [parts addObject:[charString uppercaseString]]; + } + + return [parts componentsJoinedByString:@"+"]; +} + - (NSString *)translatedCharacterForKeystroke:(KCKeystroke *)keystroke { if ([self shouldReturnOriginalCharactersForKeyCode:keystroke.keyCode characters:keystroke.characters] && keystroke.isCommand) { From b9ef9587755eaae9c4f48cede5a6a5c9ecb0d3cc Mon Sep 17 00:00:00 2001 From: Nick Borovets Date: Thu, 19 Feb 2026 20:04:58 +0300 Subject: [PATCH 2/4] Add option to show Windows equivalent keystrokes in visualizers Implemented a user preference to display Windows equivalent keystrokes alongside macOS keystrokes in both KCDefaultVisualizer and SvelteVisualizer. Updated relevant UI components and user defaults to support this feature. Co-authored-by: Cursor --- keycastr/KCDefaultVisualizer.m | 14 ++--- .../KCDefaultVisualizer.nib/designable.nib | 51 +++++++++++------- .../KCDefaultVisualizer.nib/keyedobjects.nib | Bin 24086 -> 24769 bytes keycastr/Svelte.nib/designable.nib | 25 ++++++--- keycastr/Svelte.nib/keyedobjects.nib | Bin 3083 -> 3671 bytes keycastr/SvelteVisualizer.h | 2 + keycastr/SvelteVisualizer.m | 42 +++++++++++---- 7 files changed, 92 insertions(+), 42 deletions(-) diff --git a/keycastr/KCDefaultVisualizer.m b/keycastr/KCDefaultVisualizer.m index 0fb6d9c..9e8c0c0 100644 --- a/keycastr/KCDefaultVisualizer.m +++ b/keycastr/KCDefaultVisualizer.m @@ -194,6 +194,7 @@ - (void)noteFlagsChanged:(NSEventModifierFlags)flags requiringSecureCoding:NO error:NULL], @"default_displayModifiedCharacters": @NO, + @"default.showWindowsEquivalent": @YES, }; } @@ -318,13 +319,14 @@ - (void)addKeystroke:(KCKeystroke *)keystroke } NSString *macString = [keystroke convertToString]; - NSString *winString = [[KCEventTransformer currentTransformer] transformedValueForWindows:keystroke]; + BOOL showWindowsEquivalent = [[NSUserDefaults standardUserDefaults] boolForKey:@"default.showWindowsEquivalent"]; - NSString *displayString; - if (winString.length > 0) { - displayString = [NSString stringWithFormat:@"%@ | %@", macString, winString]; - } else { - displayString = macString; + NSString *displayString = macString; + if (showWindowsEquivalent) { + NSString *winString = [[KCEventTransformer currentTransformer] transformedValueForWindows:keystroke]; + if (winString.length > 0) { + displayString = [NSString stringWithFormat:@"%@ | %@", macString, winString]; + } } [self appendString:displayString]; diff --git a/keycastr/KCDefaultVisualizer.nib/designable.nib b/keycastr/KCDefaultVisualizer.nib/designable.nib index 7e1a3ad..ed37d03 100644 --- a/keycastr/KCDefaultVisualizer.nib/designable.nib +++ b/keycastr/KCDefaultVisualizer.nib/designable.nib @@ -1,7 +1,8 @@ - + - + + @@ -13,7 +14,7 @@ - + @@ -40,7 +41,7 @@ - + @@ -85,7 +86,7 @@ - + @@ -130,7 +131,7 @@ - + @@ -175,7 +176,7 @@ - + @@ -209,7 +210,7 @@ - + @@ -235,7 +236,7 @@ - + @@ -246,7 +247,7 @@ - + - - - - + + + + + @@ -349,6 +360,8 @@ + + @@ -379,7 +392,7 @@ - + diff --git a/keycastr/KCDefaultVisualizer.nib/keyedobjects.nib b/keycastr/KCDefaultVisualizer.nib/keyedobjects.nib index 9bbdf5308f17acac633f4d4cb662409ca699bcd8..081640484ac3016817c344c008c0314cf0f24c8d 100644 GIT binary patch literal 24769 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 NBqM$PP;V_}{||US1d0Fv literal 24086 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 LKZ9qq7qkBZ#oGOn diff --git a/keycastr/Svelte.nib/designable.nib b/keycastr/Svelte.nib/designable.nib index 8c6c7bc..20dd0e3 100644 --- a/keycastr/Svelte.nib/designable.nib +++ b/keycastr/Svelte.nib/designable.nib @@ -1,7 +1,8 @@ - + - + + @@ -13,11 +14,11 @@ - + - + + + - + diff --git a/keycastr/Svelte.nib/keyedobjects.nib b/keycastr/Svelte.nib/keyedobjects.nib index 079ff93a0307f25e745b74b0b754d8ddf132380a..aefc36200d3bd17e7d8a25fc7e9bbbf0856ef4d7 100644 GIT binary patch delta 1904 zcmb7^e^69a6vxl*z9;WpKtTmT5mv-dTWNRssUq=14Yf99XKI>esvUg;I|ECx3#1IQ z+~u*bz%D1*>EE|MZ+UIX;|Hhc5ojCxRXXh z_t8-A{j^to06QPVzK3Wu+Cs;pK{`H`9-?E*Q7cd@Q5mRA)GAaKDjT&LwFZ@gT8qj> z<)N&obs-wg57FrQ5Y=4nn&yDg=JN!Ux>jFcRy6%!)*M3K-NP<-t#U+Zb_WhODEq^R~8m1BZuP?maD@M#bf6Q3hRZ z4C)Vfd;x90P&gYFel!KYAZ$0D0@F!i#>PiPM2-^N1^A5EkdwrLJWkj~Jx+>|Pmo>6 zDA|p?#5qkY*gi@GluS&BR4i7 zDbHY>NZ1aOeB_(*Dfuz^HB*YIpU7yxOx7SH;zg2!@Au>pd5}%J4hB=gBhUCp@pqW;jq$ ze+=lbPm;P~S5FOp2OPm?U8*u49o1*VH?+B=f-QYyHToDu zVcT@sY(22?#-gyAXcEa^n>Gomq)2$UER=0Pw5Wi1AR zEbV70*UD-r-Jzc^8zkKwTSnkcs>qNvi0W|uR9 zemq1AXK2^oM@W@U;8|){{6&6#GmCEO#kO+`MvL=eCT>)mpOC~h8#j&Jn>e}orewtV zLZ?X)Ivpi;T^HCq{21i?A5!f214aQ~dJ~CDOg_ z-*nBdiA_|(zboY|<1FW_;M~f&jdMF^CFc&#D$d(E8>;!MhO?Hlj&mnc2a^tF9V|Ks zI*2+f(IH6(Ne5X6qC>I{DLSO;uvCX-I;824j{j8cCvr?Xo?N8$BV zciL;=w%fXLi3G)$_<}mcw;@+iDj=e6`1-{}6Y(v6)K4bLC;#VcmH5TPCjZ|#=gD)P z=Q-y*x8JO&w1*SD+qP!=c4mfCJ|bf1MkoSV&>zq&lv+S^ImTbO7G9dS_a3zOJy9tg zDL5}3vQLZhnL_1k$(|8ovsL?BG5%fA{$5O65cUtk{!!RJiSp0I%CAo4cgOxy*nf%Y z#nL1RVf!FI6cD1SiBg$`Q&=Jj#Wqp2+hOkzqP$!<<+WnG92VoXn}w)t5n@yA7EI#M zR%jcv9l8~|4cYP3J%#B|j6o8OIVD7NQu`9t@Q(gudZ?VR zwhs;r<&p!rTEgntola*4(sySwgV{{(VRyCG=~lI_)(Pd6%MSKinMYEQ>Eqf3U;Yc0 zm-ZC-USvNeAF&QjGA@f|c@21wyTGS;J$Q((0UzfWIL@2F&lL}I0P_Q^f#(zp=7eb* zlh$ymKbN{UGqgL|kDS>P`U$f-!B3R)m;T^A>wBIg|EuJGftSEO%5C7w+~(eAb}jyz zWov#qA8bSXV>e;6=U-!#N49}?wjRpl`gYpJsBJiVqMO5^U@WW(YKKRiJHSR+`V{GB z)XAqwpCP?bVoa7epCJ}+cn78^(C`k-P@v%*jUVHG+@tQDyeim=B>QNv>54DPE_zQE`)ESg~7C{u$Ld zs(8KP4WLIpkNh45JkmVUJzC(=LXQlOOpn;3CXbrs7vqd3th*j~Fx8i%DyF?|yk*S2 P*wX2qZ`tT}EZXunmg+l_ diff --git a/keycastr/SvelteVisualizer.h b/keycastr/SvelteVisualizer.h index 7c224c4..55f9714 100644 --- a/keycastr/SvelteVisualizer.h +++ b/keycastr/SvelteVisualizer.h @@ -34,6 +34,8 @@ @interface SvelteVisualizerView : NSView +@property (nonatomic, assign) BOOL showWindowsEquivalent; + @end @interface SvelteVisualizer : KCVisualizer diff --git a/keycastr/SvelteVisualizer.m b/keycastr/SvelteVisualizer.m index b1a02b9..4e02c3a 100644 --- a/keycastr/SvelteVisualizer.m +++ b/keycastr/SvelteVisualizer.m @@ -32,6 +32,7 @@ #import "KCKeycastrEvent.h" #import "KCKeystroke.h" #import "KCMouseEvent.h" +#import "KCEventTransformer.h" @implementation SvelteVisualizerFactory @@ -57,6 +58,8 @@ @implementation SvelteVisualizerView { NSString *_displayedString; } +@synthesize showWindowsEquivalent = _showWindowsEquivalent; + -(void) drawRect:(NSRect)rect { NSRect frame = [self frame]; @@ -141,19 +144,27 @@ -(void) drawRect:(NSRect)rect - (void)noteKeyEvent:(KCKeycastrEvent *)event { - if (_displayedString) { - [_displayedString autorelease]; - _displayedString = [[_displayedString stringByAppendingString:[event convertToString]] retain]; + NSString *macString = [event convertToString]; + NSString *winString = self.showWindowsEquivalent ? [[KCEventTransformer currentTransformer] transformedValueForWindows:event] : nil; - - if (_displayedString.length > 6) { - NSRange range = NSMakeRange(_displayedString.length - 6, 6); + if (winString.length > 0) { + // For modifier-based shortcuts, replace the display entirely (don't accumulate) + [_displayedString autorelease]; + _displayedString = [[NSString stringWithFormat:@"%@ | %@", macString, winString] retain]; + } else { + // Regular keypresses: accumulate, keep last 6 chars + if (_displayedString) { [_displayedString autorelease]; - _displayedString = [[_displayedString substringWithRange:range] retain]; + _displayedString = [[_displayedString stringByAppendingString:macString] retain]; + + if (_displayedString.length > 6) { + NSRange range = NSMakeRange(_displayedString.length - 6, 6); + [_displayedString autorelease]; + _displayedString = [[_displayedString substringWithRange:range] retain]; + } + } else { + _displayedString = [macString retain]; } - } - else { - _displayedString = [[event convertToString] retain]; } [self setNeedsDisplay:YES]; } @@ -172,6 +183,7 @@ -(void) noteFlagsChanged:(NSEventModifierFlags)flags @interface SvelteVisualizer () @property (nonatomic, assign) BOOL displayAll; +@property (nonatomic, assign) BOOL showWindowsEquivalent; @end @@ -208,6 +220,7 @@ -(id) init [_visualizerWindow setContentView:_visualizerView]; _displayAll = [[[NSUserDefaults standardUserDefaults] valueForKey:@"svelte.displayAll"] boolValue]; + self.showWindowsEquivalent = [[[NSUserDefaults standardUserDefaults] valueForKey:@"svelte.showWindowsEquivalent"] boolValue]; // TODO: migrate away from using NSNotificationCenter for this, as it is far too chatty __weak typeof(self) weakSelf = self; @@ -216,6 +229,7 @@ -(id) init queue:nil usingBlock:^(NSNotification * _Nonnull notification) { weakSelf.displayAll = [notification.object boolForKey:@"svelte.displayAll"]; + weakSelf.showWindowsEquivalent = [notification.object boolForKey:@"svelte.showWindowsEquivalent"]; }]; return self; @@ -268,8 +282,14 @@ - (void)noteFlagsChanged:(NSEventModifierFlags)flags [_visualizerView noteFlagsChanged:flags]; } +-(void) setShowWindowsEquivalent:(BOOL)showWindowsEquivalent { + _showWindowsEquivalent = showWindowsEquivalent; + _visualizerView.showWindowsEquivalent = showWindowsEquivalent; +} + + (NSDictionary *)visualizerDefaults { - return @{ @"svelte.displayAll": @YES }; + return @{ @"svelte.displayAll": @YES, + @"svelte.showWindowsEquivalent": @YES }; } @end From d6e27550d25cc4add7bec6dd9e9dbb6aab12a17e Mon Sep 17 00:00:00 2001 From: Nick Borovets Date: Thu, 19 Feb 2026 20:17:57 +0300 Subject: [PATCH 3/4] Disable Windows equivalent keystrokes display in KCDefaultVisualizer and SvelteVisualizer Updated user defaults to turn off the option for displaying Windows equivalent keystrokes in both visualizers, aligning with user preferences. --- keycastr/KCDefaultVisualizer.m | 2 +- keycastr/SvelteVisualizer.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/keycastr/KCDefaultVisualizer.m b/keycastr/KCDefaultVisualizer.m index 9e8c0c0..1ad4e47 100644 --- a/keycastr/KCDefaultVisualizer.m +++ b/keycastr/KCDefaultVisualizer.m @@ -194,7 +194,7 @@ - (void)noteFlagsChanged:(NSEventModifierFlags)flags requiringSecureCoding:NO error:NULL], @"default_displayModifiedCharacters": @NO, - @"default.showWindowsEquivalent": @YES, + @"default.showWindowsEquivalent": @NO, }; } diff --git a/keycastr/SvelteVisualizer.m b/keycastr/SvelteVisualizer.m index 4e02c3a..7d5ae01 100644 --- a/keycastr/SvelteVisualizer.m +++ b/keycastr/SvelteVisualizer.m @@ -289,7 +289,7 @@ -(void) setShowWindowsEquivalent:(BOOL)showWindowsEquivalent { + (NSDictionary *)visualizerDefaults { return @{ @"svelte.displayAll": @YES, - @"svelte.showWindowsEquivalent": @YES }; + @"svelte.showWindowsEquivalent": @NO }; } @end From cce31c22cfbe7d821b364732539651f14e45b214 Mon Sep 17 00:00:00 2001 From: Nick Borovets Date: Thu, 19 Feb 2026 20:25:31 +0300 Subject: [PATCH 4/4] Refine Windows keystroke display logic in KCEventTransformer Updated the condition for displaying Windows equivalent keystrokes to require Command, Control, or Option modifiers, while excluding Shift. This change aligns with user feedback to avoid duplicating simple letter inputs. --- keycastr/KCEventTransformer.m | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/keycastr/KCEventTransformer.m b/keycastr/KCEventTransformer.m index e0de3a1..3d39959 100644 --- a/keycastr/KCEventTransformer.m +++ b/keycastr/KCEventTransformer.m @@ -335,13 +335,7 @@ - (NSString *)transformedValueForWindows:(KCKeycastrEvent *)event { BOOL isOption = (modifiers & NSEventModifierFlagOption) != 0; BOOL isShift = (modifiers & NSEventModifierFlagShift) != 0; - // Only show Windows equivalent if there are modifiers (Command, Control, or Option) - // We treat Shift-only as a "simple letter" case usually, unless it's a special key? - // User said: "don't duplicate simple letters like 'a | a'". - // Shift+A -> "A". Windows: "Shift+A"? Or just "A"? - // Usually Windows shortcuts are Ctrl+C. - // Let's require Command, Control, or Option for now. - if (!isCommand && !isControl && !isOption) { + if (!isCommand && !isControl && !isOption && !isShift) { return nil; }