From c56f2d3c8d115faccb974d32daa3007c9f2923d0 Mon Sep 17 00:00:00 2001 From: "Colin T.A. Gray" Date: Wed, 27 Feb 2019 10:58:43 -0500 Subject: [PATCH 1/6] adds 'Mods only' visualizer --- keycastr/KeyCastr.xcodeproj/project.pbxproj | 170 ++++++++++++++++ keycastr/Mods-Info.plist | 22 +++ keycastr/Mods.nib/designable.nib | 23 +++ keycastr/Mods.nib/keyedobjects.nib | Bin 0 -> 1396 bytes keycastr/ModsVisualizer.h | 61 ++++++ keycastr/ModsVisualizer.m | 207 ++++++++++++++++++++ 6 files changed, 483 insertions(+) create mode 100644 keycastr/Mods-Info.plist create mode 100644 keycastr/Mods.nib/designable.nib create mode 100644 keycastr/Mods.nib/keyedobjects.nib create mode 100644 keycastr/ModsVisualizer.h create mode 100644 keycastr/ModsVisualizer.m diff --git a/keycastr/KeyCastr.xcodeproj/project.pbxproj b/keycastr/KeyCastr.xcodeproj/project.pbxproj index 8b3e3bb..5c363ec 100644 --- a/keycastr/KeyCastr.xcodeproj/project.pbxproj +++ b/keycastr/KeyCastr.xcodeproj/project.pbxproj @@ -7,6 +7,13 @@ objects = { /* Begin PBXBuildFile section */ + 1DB8252B2226E86500E123AA /* ModsVisualizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1DB825272226E86500E123AA /* ModsVisualizer.h */; }; + 1DB8252C2226E86500E123AA /* Mods.nib in Resources */ = {isa = PBXBuildFile; fileRef = 1DB825282226E86500E123AA /* Mods.nib */; }; + 1DB8252D2226E86500E123AA /* Mods-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1DB825292226E86500E123AA /* Mods-Info.plist */; }; + 1DB8252E2226E86500E123AA /* ModsVisualizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DB8252A2226E86500E123AA /* ModsVisualizer.m */; }; + 1DB8253E2226E8D100E123AA /* ModsVisualizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DB8252A2226E86500E123AA /* ModsVisualizer.m */; }; + 1DB8253F2226E8DA00E123AA /* Mods.nib in Resources */ = {isa = PBXBuildFile; fileRef = 1DB825282226E86500E123AA /* Mods.nib */; }; + 1DB825402226EC2100E123AA /* Mods.kcplugin in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1DB8253C2226E8A000E123AA /* Mods.kcplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 324AD25E40F9EFA6F54FA36A /* KCKeycastrEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 324AD6721F5E3C6D50AE104A /* KCKeycastrEvent.h */; }; 324AD36C18A447EB8EDCE7B7 /* KCDefaultVisualizer.nib in Resources */ = {isa = PBXBuildFile; fileRef = 324AD93D2D9827CC6B6996A8 /* KCDefaultVisualizer.nib */; }; 324AD7AC994A031550F38591 /* KCKeycastrEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 324ADBA0D37774E36EA35A2E /* KCKeycastrEvent.m */; }; @@ -71,6 +78,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 1DB825412226EC3200E123AA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1DB8252F2226E8A000E123AA; + remoteInfo = Mods; + }; 3D1646D40F43DCB200CA65AD /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -297,6 +311,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( + 1DB825402226EC2100E123AA /* Mods.kcplugin in CopyFiles */, 3D1648C20F451EDB00CA65AD /* Svelte.kcplugin in CopyFiles */, 3D1646690F43D76D00CA65AD /* KCDefaultVisualizer.kcplugin in CopyFiles */, ); @@ -329,6 +344,11 @@ /* Begin PBXFileReference section */ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 1DB825272226E86500E123AA /* ModsVisualizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModsVisualizer.h; sourceTree = ""; }; + 1DB825282226E86500E123AA /* Mods.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = Mods.nib; sourceTree = ""; }; + 1DB825292226E86500E123AA /* Mods-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Mods-Info.plist"; sourceTree = ""; }; + 1DB8252A2226E86500E123AA /* ModsVisualizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModsVisualizer.m; sourceTree = ""; }; + 1DB8253C2226E8A000E123AA /* Mods.kcplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Mods.kcplugin; sourceTree = BUILT_PRODUCTS_DIR; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; @@ -471,10 +491,21 @@ 3D1646B60F43DBD700CA65AD /* KCVisualizer.framework */, 3D1648AC0F451D4500CA65AD /* Svelte.kcplugin */, AFC172192377CFF500292155 /* KCVisualizerTests.xctest */, + 1DB8253C2226E8A000E123AA /* Mods.kcplugin */, ); name = Products; sourceTree = ""; }; + 1DB825262226E85800E123AA /* Mods */ = { + isa = PBXGroup; + children = ( + 1DB825282226E86500E123AA /* Mods.nib */, + 1DB825272226E86500E123AA /* ModsVisualizer.h */, + 1DB8252A2226E86500E123AA /* ModsVisualizer.m */, + ); + name = Mods; + sourceTree = ""; + }; 29B97314FDCFA39411CA2CEA /* KeyCastr */ = { isa = PBXGroup; children = ( @@ -486,6 +517,7 @@ AF6DD3FB2586E00500EDC9D4 /* Externals */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, + 1DB825292226E86500E123AA /* Mods-Info.plist */, ); name = KeyCastr; sourceTree = ""; @@ -550,6 +582,7 @@ 3D1646530F43D6B800CA65AD /* Visualizers */ = { isa = PBXGroup; children = ( + 1DB825262226E85800E123AA /* Mods */, 3D1648A30F451CDA00CA65AD /* Svelte */, 324AD7A5D37DE702839F52C6 /* Mouse */, 324ADFFC6CB5410AEFDEF479 /* Default */, @@ -674,12 +707,31 @@ 324ADBC2EAD3FC5FD3C369FE /* KCMouseEventVisualizer.h in Headers */, 324ADBB15522719676E80D5F /* KCMouseEvent.h in Headers */, 324AD25E40F9EFA6F54FA36A /* KCKeycastrEvent.h in Headers */, + 1DB8252B2226E86500E123AA /* ModsVisualizer.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 1DB8252F2226E8A000E123AA /* Mods */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DB825382226E8A000E123AA /* Build configuration list for PBXNativeTarget "Mods" */; + buildPhases = ( + 1DB825322226E8A000E123AA /* Resources */, + 1DB825342226E8A000E123AA /* Sources */, + 3D1646580F43D6E700CA65AD /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 1DB825302226E8A000E123AA /* PBXTargetDependency */, + ); + name = Mods; + productName = Svelte; + productReference = 1DB8253C2226E8A000E123AA /* Mods.kcplugin */; + productType = "com.apple.product-type.bundle"; + }; 3D1646590F43D6E700CA65AD /* KCDefaultVisualizer */ = { isa = PBXNativeTarget; buildConfigurationList = 3D16465E0F43D6E800CA65AD /* Build configuration list for PBXNativeTarget "KCDefaultVisualizer" */; @@ -752,6 +804,7 @@ AF6DD4372586E0BA00EDC9D4 /* PBXTargetDependency */, AF6DD4342586E0A700EDC9D4 /* PBXTargetDependency */, 3D1646D50F43DCB200CA65AD /* PBXTargetDependency */, + 1DB825422226EC3200E123AA /* PBXTargetDependency */, ); name = KeyCastr; productInstallPath = "$(HOME)/Applications"; @@ -828,6 +881,7 @@ projectRoot = ""; targets = ( 3D1646B50F43DBD700CA65AD /* KCVisualizer */, + 1DB8252F2226E8A000E123AA /* Mods */, 3D1648AB0F451D4500CA65AD /* Svelte */, 3D1646590F43D6E700CA65AD /* KCDefaultVisualizer */, 8D1107260486CEB800E47090 /* KeyCastr */, @@ -987,6 +1041,14 @@ /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ + 1DB825322226E8A000E123AA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1DB8253F2226E8DA00E123AA /* Mods.nib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 3D1646560F43D6E700CA65AD /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -999,6 +1061,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1DB8252C2226E86500E123AA /* Mods.nib in Resources */, + 1DB8252D2226E86500E123AA /* Mods-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1041,6 +1105,14 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 1DB825342226E8A000E123AA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1DB8253E2226E8D100E123AA /* ModsVisualizer.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 3D1646570F43D6E700CA65AD /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1054,6 +1126,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1DB8252E2226E86500E123AA /* ModsVisualizer.m in Sources */, 3D1646C20F43DC4700CA65AD /* KCVisualizer.m in Sources */, AF5457292C0CDB2E00064C82 /* KCColorValueTransformer.m in Sources */, AF7B1CF32C22376100C8C145 /* NSUserDefaults+Utility.m in Sources */, @@ -1099,6 +1172,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 1DB825422226EC3200E123AA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1DB8252F2226E8A000E123AA /* Mods */; + targetProxy = 1DB825412226EC3200E123AA /* PBXContainerItemProxy */; + }; 3D1646D50F43DCB200CA65AD /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 3D1646B50F43DBD700CA65AD /* KCVisualizer */; @@ -1171,6 +1249,88 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 1DB825392226E8A000E123AA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + INFOPLIST_FILE = "Mods-Info.plist"; + INSTALL_PATH = "$(HOME)/Library/Bundles"; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + PREBINDING = NO; + PRODUCT_BUNDLE_IDENTIFIER = net.stephendeken.KeyCastr.Mods; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = kcplugin; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DB8253A2226E8A000E123AA /* Code Coverage */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_TEST_COVERAGE_FILES = YES; + GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + INFOPLIST_FILE = "Mods-Info.plist"; + INSTALL_PATH = "$(HOME)/Library/Bundles"; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + PREBINDING = NO; + PRODUCT_BUNDLE_IDENTIFIER = net.stephendeken.KeyCastr.Mods; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = kcplugin; + ZERO_LINK = NO; + }; + name = "Code Coverage"; + }; + 1DB8253B2226E8A000E123AA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + INFOPLIST_FILE = "Mods-Info.plist"; + INSTALL_PATH = "$(HOME)/Library/Bundles"; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + PREBINDING = NO; + PRODUCT_BUNDLE_IDENTIFIER = net.stephendeken.KeyCastr.Mods; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = kcplugin; + ZERO_LINK = NO; + }; + name = Release; + }; 3D16465C0F43D6E800CA65AD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1609,6 +1769,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 1DB825382226E8A000E123AA /* Build configuration list for PBXNativeTarget "Mods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DB825392226E8A000E123AA /* Debug */, + 1DB8253A2226E8A000E123AA /* Code Coverage */, + 1DB8253B2226E8A000E123AA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 3D16465E0F43D6E800CA65AD /* Build configuration list for PBXNativeTarget "KCDefaultVisualizer" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/keycastr/Mods-Info.plist b/keycastr/Mods-Info.plist new file mode 100644 index 0000000..5a6a411 --- /dev/null +++ b/keycastr/Mods-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + ModsVisualizerFactory + + diff --git a/keycastr/Mods.nib/designable.nib b/keycastr/Mods.nib/designable.nib new file mode 100644 index 0000000..98351db --- /dev/null +++ b/keycastr/Mods.nib/designable.nib @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/keycastr/Mods.nib/keyedobjects.nib b/keycastr/Mods.nib/keyedobjects.nib new file mode 100644 index 0000000000000000000000000000000000000000..c6700ccb681483b50913dabc24d7ea03f7415352 GIT binary patch literal 1396 zcmZuwTWl0n7@q(9TiVjwblK92KnrXOtEIG*+BOwo+fuBQt#rEE?RA~*p3=eTPMw)8 zRKy-qZi)&bf@ypxU5OGe#NZ`Le9@42ec2Gy5FSj7iHV6m852X|zZV-Hn90mJ=Rg1D z`@a92@o8PN?E3m!z|fJk;+6A3_Y5~J&4>ow#`r-Vwyi<8YKA8@GWWY}W7;Xf$;E5( z`s|#_jqV5Qwmtl4_v3q?*zX?M?GG3!VqpC|*#Fs*<)tgDtalm?dc z7EEM|GO=37qEckhw@y@v(nOVW{f1#8ll1nfQ(T~Mgk)Kn;kwNUNlewXXSkWDuGzGC zD4jG)Zo%}FTVoU(vutB3&2VXxC-@)R#6!;7Erg&h(~m{5g3@fQC$;v)Y?UY~+>UQ; z@c4ZS&B(p6>GF1wBZ_V{x3oH4ZIA4rT#6Ah!<;1Sx2BC~gqy^#%OubWF`-00ZM@%zg(urplk(4W>FNPX zNMfbPqkn!eEWvhfKSGcIeq!yCPe2U-V zW+$IeW4dh-0^2lnotyE=gPtVWWdj8S^`)SPYDdT7E|-gRPrfB&u*a^r2+ej{rUB)o z%+HQpIr`k3I3~(Pg?K=$5o<+>3^J2ZcF0*2_k7c$D5CMju|*1~t~q;-NO!lVPf@38 zt4n7+sZP?_b@A}3zGF#lReuIO&Bvt})uPjwMU|8zv9vzosBqqLPiZ)8*jNI6om zR3UAYwn*EgW@%VbrNh#k^pdn7y(@ht-Ijg>gi5G^255vPXogm3gB`FFywCx=VGr~` z5Qbm`46tDiPQxWwfH=Gj*Wp9>7;eB<@Es)J2lxr@z+Lzi{(yTdi)FK1md6TM1*>H( ztc&%s{Y+tgHoyki2%BJ2%w%)yI6K2Gv8(KTc9VV0eq?vq@9a +#import "KCVisualizer.h" + +@interface ModsVisualizerFactory : KCVisualizerFactory +{ +} + +-(NSString*) visualizerNibName; +-(Class) visualizerClass; +-(NSString*) visualizerName; + +@end + +@interface ModsVisualizerView : NSView +{ + uint32_t _flags; +} + +-(void) noteFlagsChanged:(uint32_t)flags; + +@end + +@interface ModsVisualizer : KCVisualizer +{ + NSWindow* _visualizerWindow; + ModsVisualizerView* _visualizerView; +} + +-(NSString*) visualizerName; +-(void) deactivateVisualizer:(id)sender; + +-(void) noteFlagsChanged:(uint32_t)flags; + +@end diff --git a/keycastr/ModsVisualizer.m b/keycastr/ModsVisualizer.m new file mode 100644 index 0000000..2877972 --- /dev/null +++ b/keycastr/ModsVisualizer.m @@ -0,0 +1,207 @@ +// Copyright (c) 2009 Stephen Deken +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name KeyCastr nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#import "ModsVisualizer.h" +#import "NSBezierPath+RoundedRect.h" + +@implementation ModsVisualizerFactory + +-(NSString*) visualizerNibName +{ + return @"Mods"; +} + +-(Class) visualizerClass +{ + return [ModsVisualizer class]; +} + +-(NSString*) visualizerName +{ + return @"Mods"; +} + +@end + +@implementation ModsVisualizerView + +-(void) drawRect:(NSRect)rect +{ + NSRect frame = [self frame]; + NSRect bgFrame = [self frame]; + float oneQuarter = floorf(frame.size.width / 4); + bgFrame.size.width = 0; + CGFloat x = frame.size.width, y; + NSSize size; + + bgFrame.origin.x = frame.size.width; + [[NSColor clearColor] setFill]; + NSRectFill(frame); + + if (_flags & NSShiftKeyMask) { + bgFrame.size.width += oneQuarter; + bgFrame.origin.x -= oneQuarter; + } + + if (_flags & NSControlKeyMask) { + bgFrame.size.width += oneQuarter; + bgFrame.origin.x -= oneQuarter; + } + + if (_flags & NSAlternateKeyMask) { + bgFrame.size.width += oneQuarter; + bgFrame.origin.x -= oneQuarter; + } + + if (_flags & NSCommandKeyMask) { + bgFrame.size.width += oneQuarter; + bgFrame.origin.x -= oneQuarter; + } + + if (bgFrame.size.width > 0) { + [[NSColor colorWithCalibratedWhite:0 alpha:0.75] setFill]; + NSBezierPath* bp = [NSBezierPath bezierPath]; + [bp appendRoundedRect:bgFrame radius:10]; + [bp fill]; + } + + NSMutableParagraphStyle* ps = [[NSMutableParagraphStyle alloc] init]; + [ps setAlignment:NSCenterTextAlignment]; + + NSString* shiftKeyString = [NSString stringWithUTF8String:"\xe2\x87\xa7\x01"]; + NSString* controlKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x83\x01"]; + NSString* altKeyString = [NSString stringWithUTF8String:"\xe2\x8c\xa5\x01"]; + NSString* commandKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x98\x01"]; + NSShadow* shadow = [[[NSShadow alloc] init] autorelease]; + [shadow setShadowColor:[NSColor blackColor]]; + [shadow setShadowBlurRadius:2]; + [shadow setShadowOffset:NSMakeSize(2,-2)]; + + NSMutableDictionary* attr = [@{ + NSFontAttributeName: [NSFont boldSystemFontOfSize:80], + NSForegroundColorAttributeName: [NSColor colorWithCalibratedWhite:1 alpha:0.8], + NSShadowAttributeName: shadow, + NSParagraphStyleAttributeName: [ps autorelease] + } mutableCopy]; + + if (_flags & NSShiftKeyMask) { + size = [shiftKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [shiftKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } + + if (_flags & NSControlKeyMask) { + size = [controlKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [controlKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } + + if (_flags & NSAlternateKeyMask) { + size = [altKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [altKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } + + if (_flags & NSCommandKeyMask) { + size = [commandKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [commandKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } +} + +-(void) noteFlagsChanged:(uint32_t)flags +{ + _flags = flags; + [self setNeedsDisplay:YES]; +} + +@end + + +@implementation ModsVisualizer + +-(NSString*) visualizerName +{ + return @"Mods"; +} + +-(id) init +{ + if (!(self = [super init])) + return nil; + + NSRect r = { 10, 10, 400, 100 }; + _visualizerWindow = [[NSWindow alloc] + initWithContentRect:r + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + [_visualizerWindow setLevel:NSScreenSaverWindowLevel]; + [_visualizerWindow setBackgroundColor:[NSColor clearColor]]; + [_visualizerWindow setMovableByWindowBackground:YES]; + [_visualizerWindow setFrame:r display:NO]; + [_visualizerWindow setFrameAutosaveName:@"mods visualizerFrame"]; + [_visualizerWindow setFrameUsingName:@"mods visualizerFrame"]; + [_visualizerWindow setOpaque:NO]; + + _visualizerView = [[ModsVisualizerView alloc] initWithFrame:r]; + [_visualizerWindow setContentView:_visualizerView]; + + return self; +} + +- (void)dealloc { + [_visualizerWindow release]; + [_visualizerView release]; + [super dealloc]; +} + +-(void) showVisualizer:(id)sender +{ + [_visualizerWindow orderFront:self]; +} + +-(void) hideVisualizer:(id)sender +{ + [_visualizerWindow orderOut:self]; +} + +-(void) deactivateVisualizer:(id)sender +{ + [_visualizerWindow orderOut:self]; +} + +-(void) noteFlagsChanged:(uint32_t)flags +{ + [_visualizerView noteFlagsChanged:flags]; +} + +@end From 43f8fa0c1f91b8228253e4d9c93376cac2df03cd Mon Sep 17 00:00:00 2001 From: "Colin T.A. Gray" Date: Tue, 17 Oct 2023 14:37:52 -0400 Subject: [PATCH 2/6] updates for Sonoma to ignore mouse events (resize frame on mods change) --- keycastr/ModsVisualizer.m | 113 ++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 47 deletions(-) diff --git a/keycastr/ModsVisualizer.m b/keycastr/ModsVisualizer.m index 2877972..538d594 100644 --- a/keycastr/ModsVisualizer.m +++ b/keycastr/ModsVisualizer.m @@ -24,9 +24,11 @@ // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#define MODS_WIDTH 400 #import "ModsVisualizer.h" #import "NSBezierPath+RoundedRect.h" +#import "KCKeystroke.h" @implementation ModsVisualizerFactory @@ -49,53 +51,50 @@ -(NSString*) visualizerName @implementation ModsVisualizerView +- (unsigned short) flagsCount { + unsigned short count = 0; + + if (_flags & NSEventModifierFlagShift) { + count += 1; + } + + if (_flags & NSEventModifierFlagControl) { + count += 1; + } + + if (_flags & NSEventModifierFlagOption) { + count += 1; + } + + if (_flags & NSEventModifierFlagCommand) { + count += 1; + } + + return count; +} + -(void) drawRect:(NSRect)rect { NSRect frame = [self frame]; NSRect bgFrame = [self frame]; - float oneQuarter = floorf(frame.size.width / 4); - bgFrame.size.width = 0; + float oneQuarter = floorf(MODS_WIDTH / 4); + CGFloat x = frame.size.width, y; NSSize size; - bgFrame.origin.x = frame.size.width; [[NSColor clearColor] setFill]; NSRectFill(frame); - if (_flags & NSShiftKeyMask) { - bgFrame.size.width += oneQuarter; - bgFrame.origin.x -= oneQuarter; - } - - if (_flags & NSControlKeyMask) { - bgFrame.size.width += oneQuarter; - bgFrame.origin.x -= oneQuarter; - } - - if (_flags & NSAlternateKeyMask) { - bgFrame.size.width += oneQuarter; - bgFrame.origin.x -= oneQuarter; - } - - if (_flags & NSCommandKeyMask) { - bgFrame.size.width += oneQuarter; - bgFrame.origin.x -= oneQuarter; - } - if (bgFrame.size.width > 0) { - [[NSColor colorWithCalibratedWhite:0 alpha:0.75] setFill]; - NSBezierPath* bp = [NSBezierPath bezierPath]; - [bp appendRoundedRect:bgFrame radius:10]; - [bp fill]; + [[NSColor colorWithCalibratedWhite:0 alpha:0.75] setFill]; + NSBezierPath* bp = [NSBezierPath bezierPath]; + [bp appendRoundedRect:bgFrame radius:10]; + [bp fill]; } NSMutableParagraphStyle* ps = [[NSMutableParagraphStyle alloc] init]; - [ps setAlignment:NSCenterTextAlignment]; + [ps setAlignment:NSTextAlignmentCenter]; - NSString* shiftKeyString = [NSString stringWithUTF8String:"\xe2\x87\xa7\x01"]; - NSString* controlKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x83\x01"]; - NSString* altKeyString = [NSString stringWithUTF8String:"\xe2\x8c\xa5\x01"]; - NSString* commandKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x98\x01"]; NSShadow* shadow = [[[NSShadow alloc] init] autorelease]; [shadow setShadowColor:[NSColor blackColor]]; [shadow setShadowBlurRadius:2]; @@ -108,28 +107,32 @@ -(void) drawRect:(NSRect)rect NSParagraphStyleAttributeName: [ps autorelease] } mutableCopy]; - if (_flags & NSShiftKeyMask) { + if (_flags & NSEventModifierFlagShift) { + NSString* shiftKeyString = [NSString stringWithUTF8String:"\xe2\x87\xa7\x01"]; size = [shiftKeyString sizeWithAttributes:attr]; y = (frame.size.height - size.height) / 2.0; x -= oneQuarter; [shiftKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; } - if (_flags & NSControlKeyMask) { + if (_flags & NSEventModifierFlagControl) { + NSString* controlKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x83\x01"]; size = [controlKeyString sizeWithAttributes:attr]; y = (frame.size.height - size.height) / 2.0; x -= oneQuarter; [controlKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; } - if (_flags & NSAlternateKeyMask) { + if (_flags & NSEventModifierFlagOption) { + NSString* altKeyString = [NSString stringWithUTF8String:"\xe2\x8c\xa5\x01"]; size = [altKeyString sizeWithAttributes:attr]; y = (frame.size.height - size.height) / 2.0; x -= oneQuarter; [altKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; } - if (_flags & NSCommandKeyMask) { + if (_flags & NSEventModifierFlagCommand) { + NSString* commandKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x98\x01"]; size = [commandKeyString sizeWithAttributes:attr]; y = (frame.size.height - size.height) / 2.0; x -= oneQuarter; @@ -139,8 +142,11 @@ -(void) drawRect:(NSRect)rect -(void) noteFlagsChanged:(uint32_t)flags { - _flags = flags; - [self setNeedsDisplay:YES]; + _flags = flags; + NSRect frame = self.frame; + frame.size.width = MODS_WIDTH / 4 * (CGFloat)[self flagsCount]; + self.frame = frame; + [self setNeedsDisplay:YES]; } @end @@ -158,30 +164,30 @@ -(id) init if (!(self = [super init])) return nil; - NSRect r = { 10, 10, 400, 100 }; + NSRect windowFrame = { MODS_WIDTH, 100, 0, 100 }; _visualizerWindow = [[NSWindow alloc] - initWithContentRect:r - styleMask:NSBorderlessWindowMask + initWithContentRect:windowFrame + styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered defer:NO]; [_visualizerWindow setLevel:NSScreenSaverWindowLevel]; [_visualizerWindow setBackgroundColor:[NSColor clearColor]]; [_visualizerWindow setMovableByWindowBackground:YES]; - [_visualizerWindow setFrame:r display:NO]; [_visualizerWindow setFrameAutosaveName:@"mods visualizerFrame"]; - [_visualizerWindow setFrameUsingName:@"mods visualizerFrame"]; + [_visualizerWindow setFrameUsingName:@"mods visualizerFrame" force:YES]; [_visualizerWindow setOpaque:NO]; - _visualizerView = [[ModsVisualizerView alloc] initWithFrame:r]; + _visualizerView = [[ModsVisualizerView alloc] init]; [_visualizerWindow setContentView:_visualizerView]; + [_visualizerView noteFlagsChanged:0]; return self; } - (void)dealloc { - [_visualizerWindow release]; - [_visualizerView release]; - [super dealloc]; + [_visualizerWindow release]; + [_visualizerView release]; + [super dealloc]; } -(void) showVisualizer:(id)sender @@ -202,6 +208,19 @@ -(void) deactivateVisualizer:(id)sender -(void) noteFlagsChanged:(uint32_t)flags { [_visualizerView noteFlagsChanged:flags]; + NSRect r = _visualizerWindow.frame; + CGFloat right = r.origin.x + r.size.width; + r.size.width = _visualizerView.frame.size.width; + r.origin.x = right - r.size.width; + [_visualizerWindow setFrame:r display:NO]; +} + +- (void)noteKeyEvent:(KCKeystroke *)keystroke {} + +- (void)noteMouseEvent:(KCMouseEvent *)mouseEvent {} + ++ (NSDictionary *)visualizerDefaults { + return @{}; } @end From 064f574dd30df309b49c524dea2141a50ee20c21 Mon Sep 17 00:00:00 2001 From: "Colin T.A. Gray" Date: Fri, 20 Oct 2023 11:51:09 -0400 Subject: [PATCH 3/6] =?UTF-8?q?code=20style=20changes,=20and=20ordered=20m?= =?UTF-8?q?odifiers=20'=E2=8C=83=E2=8C=A5=E2=87=A7=E2=8C=98'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- keycastr/ModsVisualizer.h | 64 ++++---- keycastr/ModsVisualizer.m | 332 ++++++++++++++++++-------------------- 2 files changed, 192 insertions(+), 204 deletions(-) diff --git a/keycastr/ModsVisualizer.h b/keycastr/ModsVisualizer.h index aa6a6fb..5a5db10 100644 --- a/keycastr/ModsVisualizer.h +++ b/keycastr/ModsVisualizer.h @@ -1,28 +1,28 @@ -// Copyright (c) 2009 Stephen Deken -// All rights reserved. +// Copyright (c) 2023 Colin Gray +// All rights reserved. // -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: // -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name KeyCastr nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific -// prior written permission. +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name KeyCastr nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. // -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #import @@ -32,30 +32,30 @@ { } --(NSString*) visualizerNibName; --(Class) visualizerClass; --(NSString*) visualizerName; +- (NSString*)visualizerNibName; +- (Class)visualizerClass; +- (NSString*)visualizerName; @end @interface ModsVisualizerView : NSView { - uint32_t _flags; + uint32_t _flags; } --(void) noteFlagsChanged:(uint32_t)flags; +- (void)noteFlagsChanged:(uint32_t)flags; @end @interface ModsVisualizer : KCVisualizer { - NSWindow* _visualizerWindow; - ModsVisualizerView* _visualizerView; + NSWindow* _visualizerWindow; + ModsVisualizerView* _visualizerView; } --(NSString*) visualizerName; --(void) deactivateVisualizer:(id)sender; +- (NSString*)visualizerName; +- (void)deactivateVisualizer:(id)sender; --(void) noteFlagsChanged:(uint32_t)flags; +- (void)noteFlagsChanged:(uint32_t)flags; @end diff --git a/keycastr/ModsVisualizer.m b/keycastr/ModsVisualizer.m index 538d594..ed2af79 100644 --- a/keycastr/ModsVisualizer.m +++ b/keycastr/ModsVisualizer.m @@ -1,28 +1,28 @@ -// Copyright (c) 2009 Stephen Deken -// All rights reserved. +// Copyright (c) 2023 Colin Gray +// All rights reserved. // -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: // -// * Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name KeyCastr nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific -// prior written permission. +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name KeyCastr nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. // -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define MODS_WIDTH 400 @@ -32,190 +32,178 @@ @implementation ModsVisualizerFactory --(NSString*) visualizerNibName -{ - return @"Mods"; +- (NSString *)visualizerNibName { + return @"Mods"; } --(Class) visualizerClass -{ - return [ModsVisualizer class]; +- (Class)visualizerClass { + return [ModsVisualizer class]; } --(NSString*) visualizerName -{ - return @"Mods"; +- (NSString *)visualizerName { + return @"Mods"; } @end @implementation ModsVisualizerView -- (unsigned short) flagsCount { - unsigned short count = 0; - - if (_flags & NSEventModifierFlagShift) { - count += 1; - } - - if (_flags & NSEventModifierFlagControl) { - count += 1; - } - - if (_flags & NSEventModifierFlagOption) { - count += 1; - } - - if (_flags & NSEventModifierFlagCommand) { - count += 1; - } - - return count; +- (unsigned short)flagsCount { + unsigned short count = 0; + + if (_flags & NSEventModifierFlagControl) { + count += 1; + } + + if (_flags & NSEventModifierFlagOption) { + count += 1; + } + + if (_flags & NSEventModifierFlagShift) { + count += 1; + } + + if (_flags & NSEventModifierFlagCommand) { + count += 1; + } + + return count; } --(void) drawRect:(NSRect)rect -{ - NSRect frame = [self frame]; - NSRect bgFrame = [self frame]; - float oneQuarter = floorf(MODS_WIDTH / 4); - - CGFloat x = frame.size.width, y; - NSSize size; - - [[NSColor clearColor] setFill]; - NSRectFill(frame); - - if (bgFrame.size.width > 0) { - [[NSColor colorWithCalibratedWhite:0 alpha:0.75] setFill]; - NSBezierPath* bp = [NSBezierPath bezierPath]; - [bp appendRoundedRect:bgFrame radius:10]; - [bp fill]; - } - - NSMutableParagraphStyle* ps = [[NSMutableParagraphStyle alloc] init]; - [ps setAlignment:NSTextAlignmentCenter]; - - NSShadow* shadow = [[[NSShadow alloc] init] autorelease]; - [shadow setShadowColor:[NSColor blackColor]]; - [shadow setShadowBlurRadius:2]; - [shadow setShadowOffset:NSMakeSize(2,-2)]; - - NSMutableDictionary* attr = [@{ - NSFontAttributeName: [NSFont boldSystemFontOfSize:80], - NSForegroundColorAttributeName: [NSColor colorWithCalibratedWhite:1 alpha:0.8], - NSShadowAttributeName: shadow, - NSParagraphStyleAttributeName: [ps autorelease] - } mutableCopy]; - - if (_flags & NSEventModifierFlagShift) { - NSString* shiftKeyString = [NSString stringWithUTF8String:"\xe2\x87\xa7\x01"]; - size = [shiftKeyString sizeWithAttributes:attr]; - y = (frame.size.height - size.height) / 2.0; - x -= oneQuarter; - [shiftKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; - } - - if (_flags & NSEventModifierFlagControl) { - NSString* controlKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x83\x01"]; - size = [controlKeyString sizeWithAttributes:attr]; - y = (frame.size.height - size.height) / 2.0; - x -= oneQuarter; - [controlKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; - } - - if (_flags & NSEventModifierFlagOption) { - NSString* altKeyString = [NSString stringWithUTF8String:"\xe2\x8c\xa5\x01"]; - size = [altKeyString sizeWithAttributes:attr]; - y = (frame.size.height - size.height) / 2.0; - x -= oneQuarter; - [altKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; - } - - if (_flags & NSEventModifierFlagCommand) { - NSString* commandKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x98\x01"]; - size = [commandKeyString sizeWithAttributes:attr]; - y = (frame.size.height - size.height) / 2.0; - x -= oneQuarter; - [commandKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; - } +- (void)drawRect:(NSRect)rect { + NSRect frame = [self frame]; + NSRect bgFrame = [self frame]; + float oneQuarter = floorf(MODS_WIDTH / 4); + + CGFloat x = frame.size.width, y; + NSSize size; + + [[NSColor clearColor] setFill]; + NSRectFill(frame); + + if (bgFrame.size.width > 0) { + [[NSColor colorWithCalibratedWhite:0 alpha:0.75] setFill]; + NSBezierPath* bp = [NSBezierPath bezierPath]; + [bp appendRoundedRect:bgFrame radius:10]; + [bp fill]; + } + + NSMutableParagraphStyle* ps = [[NSMutableParagraphStyle alloc] init]; + [ps setAlignment:NSTextAlignmentCenter]; + + NSShadow* shadow = [[[NSShadow alloc] init] autorelease]; + [shadow setShadowColor:[NSColor blackColor]]; + [shadow setShadowBlurRadius:2]; + [shadow setShadowOffset:NSMakeSize(2,-2)]; + + NSMutableDictionary* attr = [@{ + NSFontAttributeName: [NSFont boldSystemFontOfSize:80], + NSForegroundColorAttributeName: [NSColor colorWithCalibratedWhite:1 alpha:0.8], + NSShadowAttributeName: shadow, + NSParagraphStyleAttributeName: [ps autorelease] + } mutableCopy]; + + if (_flags & NSEventModifierFlagControl) { + NSString* controlKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x83\x01"]; + size = [controlKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [controlKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } + + if (_flags & NSEventModifierFlagOption) { + NSString* altKeyString = [NSString stringWithUTF8String:"\xe2\x8c\xa5\x01"]; + size = [altKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [altKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } + + if (_flags & NSEventModifierFlagShift) { + NSString* shiftKeyString = [NSString stringWithUTF8String:"\xe2\x87\xa7\x01"]; + size = [shiftKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [shiftKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } + + if (_flags & NSEventModifierFlagCommand) { + NSString* commandKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x98\x01"]; + size = [commandKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [commandKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } } --(void) noteFlagsChanged:(uint32_t)flags -{ - _flags = flags; - NSRect frame = self.frame; - frame.size.width = MODS_WIDTH / 4 * (CGFloat)[self flagsCount]; - self.frame = frame; - [self setNeedsDisplay:YES]; +- (void)noteFlagsChanged:(uint32_t)flags { + _flags = flags; + NSRect frame = self.frame; + frame.size.width = MODS_WIDTH / 4 * (CGFloat)[self flagsCount]; + self.frame = frame; + [self setNeedsDisplay:YES]; } @end - @implementation ModsVisualizer --(NSString*) visualizerName -{ - return @"Mods"; +- (NSString *)visualizerName { + return @"Mods"; } --(id) init -{ - if (!(self = [super init])) - return nil; - - NSRect windowFrame = { MODS_WIDTH, 100, 0, 100 }; - _visualizerWindow = [[NSWindow alloc] - initWithContentRect:windowFrame - styleMask:NSWindowStyleMaskBorderless - backing:NSBackingStoreBuffered - defer:NO]; - [_visualizerWindow setLevel:NSScreenSaverWindowLevel]; - [_visualizerWindow setBackgroundColor:[NSColor clearColor]]; - [_visualizerWindow setMovableByWindowBackground:YES]; - [_visualizerWindow setFrameAutosaveName:@"mods visualizerFrame"]; - [_visualizerWindow setFrameUsingName:@"mods visualizerFrame" force:YES]; - [_visualizerWindow setOpaque:NO]; - - _visualizerView = [[ModsVisualizerView alloc] init]; - [_visualizerWindow setContentView:_visualizerView]; - [_visualizerView noteFlagsChanged:0]; - - return self; +- (id)init { + if (!(self = [super init])) + return nil; + + NSRect windowFrame = { MODS_WIDTH, 100, 0, 100 }; + _visualizerWindow = [[NSWindow alloc] + initWithContentRect:windowFrame + styleMask:NSWindowStyleMaskBorderless + backing:NSBackingStoreBuffered + defer:NO]; + [_visualizerWindow setLevel:NSScreenSaverWindowLevel]; + [_visualizerWindow setBackgroundColor:[NSColor clearColor]]; + [_visualizerWindow setMovableByWindowBackground:YES]; + [_visualizerWindow setFrameAutosaveName:@"mods visualizerFrame"]; + [_visualizerWindow setFrameUsingName:@"mods visualizerFrame" force:YES]; + [_visualizerWindow setOpaque:NO]; + + _visualizerView = [[ModsVisualizerView alloc] init]; + [_visualizerWindow setContentView:_visualizerView]; + [_visualizerView noteFlagsChanged:0]; + + return self; } -- (void)dealloc { - [_visualizerWindow release]; - [_visualizerView release]; - [super dealloc]; +- (void)dealloc { + [_visualizerWindow release]; + [_visualizerView release]; + [super dealloc]; } --(void) showVisualizer:(id)sender -{ - [_visualizerWindow orderFront:self]; +- (void)showVisualizer:(id)sender { + [_visualizerWindow orderFront:self]; } --(void) hideVisualizer:(id)sender -{ - [_visualizerWindow orderOut:self]; +- (void)hideVisualizer:(id)sender { + [_visualizerWindow orderOut:self]; } --(void) deactivateVisualizer:(id)sender -{ - [_visualizerWindow orderOut:self]; +- (void)deactivateVisualizer:(id)sender { + [_visualizerWindow orderOut:self]; } --(void) noteFlagsChanged:(uint32_t)flags -{ - [_visualizerView noteFlagsChanged:flags]; - NSRect r = _visualizerWindow.frame; - CGFloat right = r.origin.x + r.size.width; - r.size.width = _visualizerView.frame.size.width; - r.origin.x = right - r.size.width; - [_visualizerWindow setFrame:r display:NO]; +- (void)noteFlagsChanged:(uint32_t)flags { + [_visualizerView noteFlagsChanged:flags]; + NSRect r = _visualizerWindow.frame; + CGFloat right = r.origin.x + r.size.width; + r.size.width = _visualizerView.frame.size.width; + r.origin.x = right - r.size.width; + [_visualizerWindow setFrame:r display:NO]; } -- (void)noteKeyEvent:(KCKeystroke *)keystroke {} +- (void)noteKeyEvent:(KCKeystroke *)keystroke {} - (void)noteMouseEvent:(KCMouseEvent *)mouseEvent {} From 66811447aa83b5228d60a33811a5f46aa5cc9dc4 Mon Sep 17 00:00:00 2001 From: "Colin T.A. Gray" Date: Thu, 2 Nov 2023 12:12:38 -0400 Subject: [PATCH 4/6] supports 'FN' key, and I had the order flipped on modifiers --- keycastr/KCEventTap.m | 3 ++ keycastr/ModsVisualizer.m | 64 +++++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/keycastr/KCEventTap.m b/keycastr/KCEventTap.m index c6ed8f1..873e12d 100644 --- a/keycastr/KCEventTap.m +++ b/keycastr/KCEventTap.m @@ -218,6 +218,9 @@ -(void) _noteFlagsChanged:(CGEventRef)event if (f & kCGEventFlagMaskAlternate) modifiers |= NSEventModifierFlagOption; + + if (f & kCGEventFlagMaskSecondaryFn) + modifiers |= NSEventModifierFlagFunction; [self noteFlagsChanged:modifiers]; } diff --git a/keycastr/ModsVisualizer.m b/keycastr/ModsVisualizer.m index ed2af79..5e96200 100644 --- a/keycastr/ModsVisualizer.m +++ b/keycastr/ModsVisualizer.m @@ -24,7 +24,7 @@ // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#define MODS_WIDTH 400 +#define MODS_WIDTH 100 #import "ModsVisualizer.h" #import "NSBezierPath+RoundedRect.h" @@ -51,6 +51,10 @@ @implementation ModsVisualizerView - (unsigned short)flagsCount { unsigned short count = 0; + if (_flags & NSEventModifierFlagFunction) { + count += 1; + } + if (_flags & NSEventModifierFlagControl) { count += 1; } @@ -73,7 +77,7 @@ - (unsigned short)flagsCount { - (void)drawRect:(NSRect)rect { NSRect frame = [self frame]; NSRect bgFrame = [self frame]; - float oneQuarter = floorf(MODS_WIDTH / 4); + float oneQuarter = floorf(MODS_WIDTH); CGFloat x = frame.size.width, y; NSSize size; @@ -103,13 +107,21 @@ - (void)drawRect:(NSRect)rect { NSParagraphStyleAttributeName: [ps autorelease] } mutableCopy]; - if (_flags & NSEventModifierFlagControl) { - NSString* controlKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x83\x01"]; - size = [controlKeyString sizeWithAttributes:attr]; - y = (frame.size.height - size.height) / 2.0; - x -= oneQuarter; - [controlKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; - } + if (_flags & NSEventModifierFlagCommand) { + NSString* commandKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x98\x01"]; + size = [commandKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [commandKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } + + if (_flags & NSEventModifierFlagShift) { + NSString* shiftKeyString = [NSString stringWithUTF8String:"\xe2\x87\xa7\x01"]; + size = [shiftKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [shiftKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } if (_flags & NSEventModifierFlagOption) { NSString* altKeyString = [NSString stringWithUTF8String:"\xe2\x8c\xa5\x01"]; @@ -119,27 +131,27 @@ - (void)drawRect:(NSRect)rect { [altKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; } - if (_flags & NSEventModifierFlagShift) { - NSString* shiftKeyString = [NSString stringWithUTF8String:"\xe2\x87\xa7\x01"]; - size = [shiftKeyString sizeWithAttributes:attr]; - y = (frame.size.height - size.height) / 2.0; - x -= oneQuarter; - [shiftKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; - } - - if (_flags & NSEventModifierFlagCommand) { - NSString* commandKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x98\x01"]; - size = [commandKeyString sizeWithAttributes:attr]; - y = (frame.size.height - size.height) / 2.0; - x -= oneQuarter; - [commandKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; - } + if (_flags & NSEventModifierFlagControl) { + NSString* controlKeyString = [NSString stringWithUTF8String:"\xe2\x8c\x83\x01"]; + size = [controlKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [controlKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } + + if (_flags & NSEventModifierFlagFunction) { + NSString* controlKeyString = [NSString stringWithUTF8String:"fn"]; + size = [controlKeyString sizeWithAttributes:attr]; + y = (frame.size.height - size.height) / 2.0; + x -= oneQuarter; + [controlKeyString drawInRect:NSMakeRect(x, y, oneQuarter, size.height) withAttributes:attr]; + } } - (void)noteFlagsChanged:(uint32_t)flags { _flags = flags; NSRect frame = self.frame; - frame.size.width = MODS_WIDTH / 4 * (CGFloat)[self flagsCount]; + frame.size.width = MODS_WIDTH * (CGFloat)[self flagsCount]; self.frame = frame; [self setNeedsDisplay:YES]; } @@ -203,7 +215,7 @@ - (void)noteFlagsChanged:(uint32_t)flags { [_visualizerWindow setFrame:r display:NO]; } -- (void)noteKeyEvent:(KCKeystroke *)keystroke {} +- (void)noteKeyEvent:(KCKeycastrEvent *)event {} - (void)noteMouseEvent:(KCMouseEvent *)mouseEvent {} From 7761adce29739df571afc33e2f7038893df17ee7 Mon Sep 17 00:00:00 2001 From: "Colin T.A. Gray" Date: Thu, 26 Sep 2024 10:34:00 -0400 Subject: [PATCH 5/6] giving up on autosave frame, using defaults directly --- keycastr/ModsVisualizer.m | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/keycastr/ModsVisualizer.m b/keycastr/ModsVisualizer.m index 5e96200..20e4557 100644 --- a/keycastr/ModsVisualizer.m +++ b/keycastr/ModsVisualizer.m @@ -168,7 +168,14 @@ - (id)init { if (!(self = [super init])) return nil; + // autosave frame was not working, despite best efforts. Easy workaround to use defaults instead. + // (and autosave frame _uses_ defaults anyway so same thing in the end?) + NSString *frameValue = [[NSUserDefaults standardUserDefaults] stringForKey:@"mods.savedFrame"]; NSRect windowFrame = { MODS_WIDTH, 100, 0, 100 }; + if (frameValue) { + windowFrame = NSRectFromString(frameValue); + } + _visualizerWindow = [[NSWindow alloc] initWithContentRect:windowFrame styleMask:NSWindowStyleMaskBorderless @@ -177,13 +184,13 @@ - (id)init { [_visualizerWindow setLevel:NSScreenSaverWindowLevel]; [_visualizerWindow setBackgroundColor:[NSColor clearColor]]; [_visualizerWindow setMovableByWindowBackground:YES]; - [_visualizerWindow setFrameAutosaveName:@"mods visualizerFrame"]; - [_visualizerWindow setFrameUsingName:@"mods visualizerFrame" force:YES]; + [_visualizerWindow setFrame:windowFrame display:NO]; [_visualizerWindow setOpaque:NO]; + [_visualizerWindow setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; _visualizerView = [[ModsVisualizerView alloc] init]; - [_visualizerWindow setContentView:_visualizerView]; [_visualizerView noteFlagsChanged:0]; + [_visualizerWindow setContentView:_visualizerView]; return self; } @@ -213,6 +220,7 @@ - (void)noteFlagsChanged:(uint32_t)flags { r.size.width = _visualizerView.frame.size.width; r.origin.x = right - r.size.width; [_visualizerWindow setFrame:r display:NO]; + [[NSUserDefaults standardUserDefaults] setValue:NSStringFromRect(_visualizerWindow.frame) forKey:@"mods.savedFrame"]; } - (void)noteKeyEvent:(KCKeycastrEvent *)event {} From 208c648751e099863ef630b5d80e7fe91387f1ac Mon Sep 17 00:00:00 2001 From: "Colin T.A. Gray" Date: Thu, 26 Sep 2024 10:48:50 -0400 Subject: [PATCH 6/6] if frame.origin.x is on left side of window, grow to the right. Otherwise grow to the left. --- keycastr/ModsVisualizer.m | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/keycastr/ModsVisualizer.m b/keycastr/ModsVisualizer.m index 20e4557..aac9bfc 100644 --- a/keycastr/ModsVisualizer.m +++ b/keycastr/ModsVisualizer.m @@ -215,11 +215,31 @@ - (void)deactivateVisualizer:(id)sender { - (void)noteFlagsChanged:(uint32_t)flags { [_visualizerView noteFlagsChanged:flags]; - NSRect r = _visualizerWindow.frame; - CGFloat right = r.origin.x + r.size.width; - r.size.width = _visualizerView.frame.size.width; - r.origin.x = right - r.size.width; - [_visualizerWindow setFrame:r display:NO]; + NSRect windowFrame = _visualizerWindow.frame; + NSScreen *screen = _visualizerWindow.screen; + if (!screen) { + for (NSScreen *s in NSScreen.screens) { + if (CGRectContainsPoint(s.frame, windowFrame.origin)) { + screen = s; + break; + } + } + + if (!screen) { + screen = NSScreen.screens.firstObject; + } + } + + NSRect screenFrame = screen.frame; + CGFloat screenX = windowFrame.origin.x - screenFrame.origin.x; + if (screenX > screenFrame.size.width / 2) { + CGFloat right = windowFrame.origin.x + windowFrame.size.width; + windowFrame.size.width = _visualizerView.frame.size.width; + windowFrame.origin.x = right - windowFrame.size.width; + } else { + windowFrame.size.width = _visualizerView.frame.size.width; + } + [_visualizerWindow setFrame:windowFrame display:NO]; [[NSUserDefaults standardUserDefaults] setValue:NSStringFromRect(_visualizerWindow.frame) forKey:@"mods.savedFrame"]; }