From 4ad7ade4298dc527956ec5b0ba9e1e0574caaf14 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Fri, 8 Jun 2018 16:05:02 -0400 Subject: [PATCH 1/7] [Mac] #967 - Make platform tests case-insensitive. --- .../KeymanEngine4Mac/KME/KMEngine.m | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m index 62e1d7638e..653d2c191a 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m @@ -869,31 +869,32 @@ const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; - (BOOL)checkPlatform:(NSString *)platform { NSArray *values = [platform componentsSeparatedByString:@" "]; for (NSString *value in values) { - if ([value isEqualToString:@"touch"]) + NSString *lcValue = [value lowercaseString]; + if ([lcValue isEqualToString:@"touch"]) return NO; - else if ([value isEqualToString:@"windows"]) + else if ([lcValue isEqualToString:@"windows"]) return NO; - else if ([value isEqualToString:@"android"]) + else if ([lcValue isEqualToString:@"android"]) return NO; - else if ([value isEqualToString:@"ios"]) + else if ([lcValue isEqualToString:@"ios"]) return NO; - else if ([value isEqualToString:@"linux"]) + else if ([lcValue isEqualToString:@"linux"]) return NO; - else if ([value isEqualToString:@"tablet"]) + else if ([lcValue isEqualToString:@"tablet"]) return NO; - else if ([value isEqualToString:@"phone"]) + else if ([lcValue isEqualToString:@"phone"]) return NO; - else if ([value isEqualToString:@"web"]) + else if ([lcValue isEqualToString:@"web"]) return NO; - else if ([value isEqualToString:@"ie"]) + else if ([lcValue isEqualToString:@"ie"]) return NO; - else if ([value isEqualToString:@"chrome"]) + else if ([lcValue isEqualToString:@"chrome"]) return NO; - else if ([value isEqualToString:@"firefox"]) + else if ([lcValue isEqualToString:@"firefox"]) return NO; - else if ([value isEqualToString:@"safari"]) + else if ([lcValue isEqualToString:@"safari"]) return NO; - else if ([value isEqualToString:@"opera"]) + else if ([lcValue isEqualToString:@"opera"]) return NO; } From 8f8170cbfbfb1262bc0501fa4e2ff5b7057aa4bb Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Thu, 14 Jun 2018 23:35:07 -0400 Subject: [PATCH 2/7] [Mac] #967 - Changed platform implementation to make spec change Any unrecognized platform tokens will cause it to return false (not a match). --- .../KeymanEngine4Mac/KME/KMEngine.m | 41 +++++++------------ 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m index 653d2c191a..a64c94356c 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m @@ -867,34 +867,21 @@ const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; } - (BOOL)checkPlatform:(NSString *)platform { - NSArray *values = [platform componentsSeparatedByString:@" "]; + NSArray *values = [[platform lowercaseString] componentsSeparatedByString:@" "]; for (NSString *value in values) { - NSString *lcValue = [value lowercaseString]; - if ([lcValue isEqualToString:@"touch"]) - return NO; - else if ([lcValue isEqualToString:@"windows"]) - return NO; - else if ([lcValue isEqualToString:@"android"]) - return NO; - else if ([lcValue isEqualToString:@"ios"]) - return NO; - else if ([lcValue isEqualToString:@"linux"]) - return NO; - else if ([lcValue isEqualToString:@"tablet"]) - return NO; - else if ([lcValue isEqualToString:@"phone"]) - return NO; - else if ([lcValue isEqualToString:@"web"]) - return NO; - else if ([lcValue isEqualToString:@"ie"]) - return NO; - else if ([lcValue isEqualToString:@"chrome"]) - return NO; - else if ([lcValue isEqualToString:@"firefox"]) - return NO; - else if ([lcValue isEqualToString:@"safari"]) - return NO; - else if ([lcValue isEqualToString:@"opera"]) + if ([value isEqualToString:@"hardware"]) + continue; + else if ([value isEqualToString:@"macosx"]) + continue; + else if ([value isEqualToString:@"mac"]) + continue; + else if ([value isEqualToString:@"macos"]) + continue; + else if ([value isEqualToString:@"desktop"]) + continue; + else if ([value isEqualToString:@"native"]) + continue; + else return NO; } From 7857e346760f27045c25a6845bd9d250bd470ea9 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Fri, 15 Jun 2018 00:53:22 -0400 Subject: [PATCH 3/7] [Mac] Changed checkPlatform implementation to be regex-based --- .../KeymanEngine4Mac/KME/KMEngine.m | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m index a64c94356c..3afc919241 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m @@ -27,12 +27,21 @@ NSString *const Q_RETURN = @"Q_RETURN"; DWORD VKMap[0x80]; @interface KMEngine () ++ (NSRegularExpression *)regexPlatform; @property (strong, nonatomic) NSMutableString *tmpCtxBuf; @property (strong, nonatomic) NSMutableArray *indexStack; @end @implementation KMEngine ++ (NSRegularExpression *)regexPlatform { + static NSRegularExpression *regex = nil; + if (regex == nil) { + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\b(((mac(os)?)x?)|(native)|(hardware)|(desktop)) *)*" options:NSRegularExpressionCaseInsensitive error:nil]; + } + return regex; +} + NSMutableString* _easterEggForCrashlytics = nil; const NSString* kEasterEggText = @"Cr@shlyt!cs crash#KME"; const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; @@ -867,25 +876,9 @@ const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; } - (BOOL)checkPlatform:(NSString *)platform { - NSArray *values = [[platform lowercaseString] componentsSeparatedByString:@" "]; - for (NSString *value in values) { - if ([value isEqualToString:@"hardware"]) - continue; - else if ([value isEqualToString:@"macosx"]) - continue; - else if ([value isEqualToString:@"mac"]) - continue; - else if ([value isEqualToString:@"macos"]) - continue; - else if ([value isEqualToString:@"desktop"]) - continue; - else if ([value isEqualToString:@"native"]) - continue; - else - return NO; - } - - return YES; + NSRange wholeString = NSMakeRange(0, [platform length]); + NSRange firstMatchRange = [[KMEngine regexPlatform] rangeOfFirstMatchInString:platform options:NSMatchingAnchored range:wholeString]; + return (firstMatchRange.length == wholeString.length); } // Creates a VK map to convert Mac VK codes to Windows VK codes From 3bb54d49435fd69a48bb589f21d55b24d462dca6 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Fri, 15 Jun 2018 02:34:03 -0400 Subject: [PATCH 4/7] [Mac] Added unit tests for checkPlatform --- .../project.pbxproj | 4 + .../KeymanEngine4MacTests/KMEngineTests.m | 75 ++++++++++++++++ .../KeymanEngineTestsStaticHelperMethods.h | 1 + .../KeymanEngineTestsStaticHelperMethods.m | 6 ++ .../KeymanEngine4MacTests/PlatformTest.kmn | 80 ++++++++++++++++++ .../KeymanEngine4MacTests/PlatformTest.kmx | Bin 0 -> 4962 bytes 6 files changed, 166 insertions(+) create mode 100755 mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn create mode 100644 mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmx diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac.xcodeproj/project.pbxproj b/mac/KeymanEngine4Mac/KeymanEngine4Mac.xcodeproj/project.pbxproj index 22ae755b62..2aa2eef6c4 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac.xcodeproj/project.pbxproj +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac.xcodeproj/project.pbxproj @@ -45,6 +45,7 @@ 984C2B161A79CA4F0023F89D /* KVKFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 984C2B021A79CA4F0023F89D /* KVKFile.h */; settings = {ATTRIBUTES = (Public, ); }; }; 984C2B171A79CA4F0023F89D /* KVKFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 984C2B031A79CA4F0023F89D /* KVKFile.m */; }; 984C2B191A79CB020023F89D /* WindowsVKCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 984C2B181A79CB020023F89D /* WindowsVKCodes.h */; }; + E224323F20D37E97006940A1 /* PlatformTest.kmx in Resources */ = {isa = PBXBuildFile; fileRef = E224323E20D37E97006940A1 /* PlatformTest.kmx */; }; E22A5A1120113DC100233965 /* KMEngineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E22A5A1020113DC100233965 /* KMEngineTests.m */; }; E22A5A142011402E00233965 /* KeymanEngineTestsStaticHelperMethods.m in Sources */ = {isa = PBXBuildFile; fileRef = E22A5A132011402E00233965 /* KeymanEngineTestsStaticHelperMethods.m */; }; E2537D9A201641DA0069FEA6 /* TestMacEngine.kmx in Resources */ = {isa = PBXBuildFile; fileRef = E2537D99201641DA0069FEA6 /* TestMacEngine.kmx */; }; @@ -102,6 +103,7 @@ 984C2B021A79CA4F0023F89D /* KVKFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KVKFile.h; sourceTree = ""; }; 984C2B031A79CA4F0023F89D /* KVKFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KVKFile.m; sourceTree = ""; }; 984C2B181A79CB020023F89D /* WindowsVKCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowsVKCodes.h; sourceTree = ""; }; + E224323E20D37E97006940A1 /* PlatformTest.kmx */ = {isa = PBXFileReference; lastKnownFileType = file; path = PlatformTest.kmx; sourceTree = ""; }; E22A5A1020113DC100233965 /* KMEngineTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KMEngineTests.m; sourceTree = ""; }; E22A5A1220113F8100233965 /* KeymanEngineTestsStaticHelperMethods.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeymanEngineTestsStaticHelperMethods.h; sourceTree = ""; }; E22A5A132011402E00233965 /* KeymanEngineTestsStaticHelperMethods.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeymanEngineTestsStaticHelperMethods.m; sourceTree = ""; }; @@ -197,6 +199,7 @@ 984C2AE21A79C98D0023F89D /* Supporting Files */ = { isa = PBXGroup; children = ( + E224323E20D37E97006940A1 /* PlatformTest.kmx */, E2537D99201641DA0069FEA6 /* TestMacEngine.kmx */, 984C2AE31A79C98D0023F89D /* Info.plist */, ); @@ -361,6 +364,7 @@ buildActionMask = 2147483647; files = ( E2537D9A201641DA0069FEA6 /* TestMacEngine.kmx in Resources */, + E224323F20D37E97006940A1 /* PlatformTest.kmx in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m index 6678cad933..2570371631 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m @@ -269,4 +269,79 @@ NSString * names[nCombinations]; } } } + +// The following checkPlatform tests all use the PlatformTest KMX file based on PlatformTest.kmn +// (not included in the project itself, but available in the source repo for reference. This +// keyboard has been craefully crafted to check for all the "wrong" values first, for which checkPlatform +// should return NO, so while these tests are ostensibly testing for YES for the platform components that +// should match on a Mac, they are also testing for NO for all the other non-matching values. + +- (NSString *)checkPlatform_getOutputForKeystroke: (NSString*) character modifierFlags: (NSEventModifierFlags) flag keyCode:(unsigned short)code { + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForPlatformTest]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@""]; + NSString *lcChar = [character lowercaseString]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:flag timestamp:0 windowNumber:0 context:nil characters:character charactersIgnoringModifiers:lcChar isARepeat:NO keyCode:code]; + NSArray *actions = [engine processEvent:event]; + XCTAssert(actions.count == 1, @"Expected 1 action"); + NSDictionary *action = actions[0]; + NSString *actionType = [[action allKeys] objectAtIndex:0]; + XCTAssert([actionType isEqualToString:Q_STR], @"Expected Q_STR action"); + NSString *output = [action objectForKey:actionType]; + return output; +} + +- (void)testCheckPlatform_native_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"u" modifierFlags:0 keyCode:kVK_ANSI_U]; + XCTAssert([output isEqualToString:@" Native"], @"Expected checkPlatform to return YES for native."); +} + +- (void)testCheckPlatform_NATIVE_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"U" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_U]; + XCTAssert([output isEqualToString:@" Native"], @"Expected checkPlatform to return YES for NATIVE."); +} + +- (void)testCheckPlatform_hardware_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"p" modifierFlags:0 keyCode:kVK_ANSI_P]; + XCTAssert([output isEqualToString:@" Hardware"], @"Expected checkPlatform to return YES for hardware."); +} + +- (void)testCheckPlatform_HARDWARE_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"P" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_P]; + XCTAssert([output isEqualToString:@" Hardware"], @"Expected checkPlatform to return YES for HARDWARE."); +} + +- (void)testCheckPlatform_desktop_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"I" modifierFlags:0 keyCode:kVK_ANSI_I]; + XCTAssert([output isEqualToString:@" Desktop"], @"Expected checkPlatform to return YES for desktop."); +} + +- (void)testCheckPlatform_Desktop_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"I" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_I]; + XCTAssert([output isEqualToString:@" Desktop"], @"Expected checkPlatform to return YES for Desktop."); +} + +- (void)testCheckPlatform_macosx_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"o" modifierFlags:0 keyCode:kVK_ANSI_O]; + XCTAssert([output isEqualToString:@" macOS"], @"Expected checkPlatform to return YES for macosx."); +} + +- (void)testCheckPlatform_MacOS_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"K" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_K]; + XCTAssert([output isEqualToString:@" macOS"], @"Expected checkPlatform to return YES for MacOS."); +} + +- (void)testCheckPlatform_MAC_ReturnsYes { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"L" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_L]; + XCTAssert([output isEqualToString:@" mac"], @"Expected checkPlatform to return YES for MAC."); +} + +- (void)testCheckPlatform_Browsers_ReturnsNo { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"y" modifierFlags:0 keyCode:kVK_ANSI_Y]; + XCTAssert([output isEqualToString:@" [Browser Undefined]"], @"Expected checkPlatform to return NO for all browsers (ie, chrome, firefox, safari, opera)."); +} + +- (void)testCheckPlatform_multipleTokens_MatchesCorrectOneForMac { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"m" modifierFlags:0 keyCode:kVK_ANSI_M]; + XCTAssert([output isEqualToString:@" macOS native desktop hardware"], @"Expected checkPlatform to return YES for macOS native desktop hardware."); +} @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.h b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.h index 3e4c6fe7f6..a58f1f5953 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.h +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.h @@ -21,6 +21,7 @@ @interface KeymanEngineTestsStaticHelperMethods : NSObject + (KMXFile *)getKmxFileTestMacEngine; ++ (KMXFile *)getKmxFileForPlatformTest; @end #endif /* KeymanEngineTestsStaticHelperMethods_h */ diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m index 6806fb63f5..f2b32bc2b2 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m @@ -16,4 +16,10 @@ KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:path]; return kmxFile; } + ++ (KMXFile *)getKmxFileForPlatformTest { + NSString *path = [[NSBundle bundleForClass:[KeymanEngineTestsStaticHelperMethods class]] pathForResource:@"PlatformTest.kmx" ofType:nil]; + KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:path]; + return kmxFile; +} @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn new file mode 100755 index 0000000000..265df6d634 --- /dev/null +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn @@ -0,0 +1,80 @@ +store(&TARGETS) 'any' +store(&NAME) 'PlatformTest' +begin Unicode > use(main) + +group(main) using keys + +platform('touch') + [K_P] > ' Touch' +platform('hardware') + [K_P] > ' Hardware' ++ [K_P] > ' [UI Undefined]' + +platform('TOUCH') + [SHIFT K_P] > ' Touch' +platform('HARDWARE') + [SHIFT K_P] > ' Hardware' ++ [SHIFT K_P] > ' [UI Undefined]' + +platform('windows') + [K_O] > ' Windows' +platform('android') + [K_O] > ' Android' +platform('iOS') + [K_O] > ' iOS' +platform('linux') + [K_O] > ' Linux' +platform('macosx') + [K_O] > ' macOS' ++ [K_O] > ' [OS Undefined]' + +platform('WINDOWS') + [SHIFT K_O] > ' Windows' +platform('ANDROID') + [SHIFT K_O] > ' Android' +platform('IOS') + [SHIFT K_O] > ' iOS' +platform('LINUX') + [SHIFT K_O] > ' Linux' +platform('MacOSX') + [SHIFT K_O] > ' macOS' ++ [SHIFT K_O] > ' [OS Undefined]' + +platform('mac') + [K_L] > ' mac' ++ [K_L] > ' [Not a mac]' +platform('MAC') + [SHIFT K_L] > ' mac' ++ [SHIFT K_L] > ' [Not a mac]' +platform('macos') + [K_K] > ' macOS' ++ [K_K] > ' [Not macos]' +platform('MacOS') + [SHIFT K_K] > ' macOS' ++ [SHIFT K_K] > ' [Not macos]' + +platform('tablet') + [K_I] > ' Tablet' +platform('phone') + [K_I] > ' Phone' +platform('desktop') + [K_I] > ' Desktop' ++ [K_I] > ' [FF Undefined]' + +platform('TABLET') + [SHIFT K_I] > ' Tablet' +platform('Phone') + [SHIFT K_I] > ' Phone' +platform('DeskTop') + [SHIFT K_I] > ' Desktop' ++ [SHIFT K_I] > ' [FF Undefined]' + +platform('web') + [K_U] > ' Web' +platform('native') + [K_U] > ' Native' ++ [K_U] > ' [Nativeness Undefined]' + +platform('Web') + [SHIFT K_U] > ' Web' +platform('NATIVE') + [SHIFT K_U] > ' Native' ++ [SHIFT K_U] > ' [Nativeness Undefined]' + +platform('ie') + [K_Y] > ' IE' +platform('chrome') + [K_Y] > ' Chrome' +platform('firefox') + [K_Y] > ' Firefox' +platform('safari') + [K_Y] > ' Safari' +platform('opera') + [K_Y] > ' Opera' ++ [K_Y] > ' [Browser Undefined]' + +platform('IE') + [SHIFT K_Y] > ' IE' +platform('Chrome') + [SHIFT K_Y] > ' Chrome' +platform('FireFox') + [SHIFT K_Y] > ' Firefox' +platform('Safari') + [SHIFT K_Y] > ' Safari' +platform('OPERA') + [SHIFT K_Y] > ' Opera' ++ [SHIFT K_Y] > ' [Browser Undefined]' + +platform('tablet') + [K_T] > ' Mobile' +platform('phone') + [K_T] > ' Mobile' ++ [K_T] > ' [Mobile Undefined]' + +platform('tablet ie web') + [K_M] > ' tablet ie web' +platform('touch phone safari web') + [K_M] > ' phone safari web' +platform('Windows desktop native hardware') + [K_M] > ' Windows desktop native hardware' +platform('Linux desktop native') + [K_M] > ' Linux desktop native' +platform('macOS native desktop hardware Safari') + [K_M] > ' macOS native hardware Safari' +platform('macOS native desktop hardware') + [K_M] > ' macOS native desktop hardware' ++ [K_M] > ' [No match]' diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmx b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmx new file mode 100644 index 0000000000000000000000000000000000000000..0a06ba4784958752f1f3eaa4ff37e8f782505330 GIT binary patch literal 4962 zcmbW5Pi$316vht~5wv0jl&V#)T5GLX0qdU-LRz6sOaBr2YLRMU%WDGyZPQm2j4@p_ z#)Tm)j4{NpAS?`F(GVrX1q(yEFoqy8UAZtUh%tl(VPOaXe`oF;?zz*~SLHV6z3=I7GUYZ6=oejvg1;AaxtYH-frVS~pFo-+7rgHITI%HXpG&lo&w@D+ov8GO^= zrHj)(R~TGraJ9i}4c=t%R)cpMyxZUjgQpDs%HX30A2)c~;4=oFH~4phFB^Q#;2Q>) z-Jgzqg~5@*YYg6CaErl%1|Ko_qQN%}-on~jm8_FV@Mam8AsLVfKJyaEC$a~;8`O?+ zNcQ6!fo*|(jO~+A8RL5#P5HPKh!}Nk*2!9_cc$nKdCM^YOD3DRoQF`ikx%bEOonmp zl_O&TF4(9XkX`gdumQYz`ljDQC^_ktUi#h&Zj~n4PXGGccQcBPVTAUhpaNV+kSB5! zJrCbQbPwPAT)P8u5Uk_eMT>%CebOdf25_>41jxOTm=1Fh3#P+eJ^ zPt_*+>AB{&Ep?m&GDuH`+^EMGtInm4G4JMLubYW6c#cf(NQX3obmr2Q`fLia7hRu? zj(>=pLLQylJ?=RPBZ<{6^5p3EyJXV2(0l1T>-_9@Y#3GNS)Yo|O@Tba*f_eld+2i? z0Jpgun={cZNpwpR-IIy#rsvH(uO_1BAG`HLu8+Dhrlh_N#qubq3zBr@MS$aKpz@4LS?0TyBI zkm9?dQRK^qIGZr5oq(SXv~%!_f%XUd7S>KKy)@r#czJnNtAww|I$W!`T?2emplyZc zv2N3D7=AF&rr_TM+Hv@)KsyVc3A9V_KLhP5y!>H(zv4^Bu^e6%XtnT-fz}G&jrE$? zkKhx5HVHoxXy3tq#ojZq7vQsjb{T#>&~C#kmS5W#5zs8_u-!g+86MX zfp!M|PoOQX;5@=?zK!sMfi?yIInXY^uVCG#FMq*r2HKKGMJh4dt{Pq+XdB?IftG_0 z2HFVxFt*Ly_Xzx0pq+%D3$$P0e`9)PxT{g*D*RTUEnPvMG25;h-huh`tk0+mz9Z1` z@QFa1gim9BJ!|Y~_)md01D_4F%kUe4CM#Lvn9WxOuM4y{;U8iVBe5szoja@1%H$~~ zAz~)|xuKPK?5T1df0pVgGlt^5PdjhFwD1=(BYLLj38|-xR!$$_*UahOoyKbI9!Wnn z#3*N;Z=o_^N2o_F)lht?#%j`OigU2N-|v)22UCAoXql}hFI6^)OJTwE7<)2he& zo=b9CuRgf~f2HmbS2#Y)OD;>c-toR#=kwK%ubsU2W#`SF^WInIeBDW1Jpl8bSDdGx zx=){_Rc^0Zg z(;mImLRLk%15tFLrn8pzg3<<0Ixne*qQb4Od)a}s z5RUle7*_j!7WKa>x^@@ZfjW6B2N{k2eoK3{#zhzRy_#gU-ctKdxX0=Lcp^@cVtd@P oNp9=?|9jl?E=%z}?gi(YZ;z{X-r{@Qi_TYUkE?N>|Gvll3k9@`SO5S3 literal 0 HcmV?d00001 From fe55bbf9d0e907fa1e44663bffb69b7b4fd48d54 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Sun, 17 Jun 2018 21:46:22 -0400 Subject: [PATCH 5/7] [Mac] Updated history for this fix (for issue #967) and for PR 990. --- mac/history.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mac/history.md b/mac/history.md index 0fd0afba06..5e9e7b9e6a 100644 --- a/mac/history.md +++ b/mac/history.md @@ -1,5 +1,9 @@ # Keyman for macOS Version History +## 2018-06-18 10.0.48 beta +* Made other version(s) of LibreOffice use "legacy" mode for character replacements (#990) +* Corrected the way Keyman responds evaluates tokens in **platform** statement (#971) + ## 2018-06-07 10.0.47 beta * Change to build script to use correct build location (#950) From e89b0d5a6a44195b141f9425186b0707b1934fe0 Mon Sep 17 00:00:00 2001 From: Tom Bogle Date: Sun, 17 Jun 2018 23:23:41 -0400 Subject: [PATCH 6/7] [Mac] Fixed logic to handle inverted (NOT_EQUAL) platform check --- .../KeymanEngine4Mac/KME/KMEngine.m | 13 +++++++++---- .../platform-rules/platform-results.xlsx | Bin 20980 -> 21247 bytes 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m index 3afc919241..38aba15da1 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m @@ -797,14 +797,19 @@ const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; DWORD x2 = [keyCtx characterAtIndex:i+3]-1; DWORD x3 = [keyCtx characterAtIndex:i+4]-1; KMCompStore *store = [self.kmx.store objectAtIndex:x3]; - if (x1 == TSS_PLATFORM && x2 == EQUAL) { - if ([self checkPlatform:store.string]) + if (x1 == TSS_PLATFORM) { + BOOL platformMatches = [self checkPlatform:store.string]; + if ((platformMatches && (x2 == EQUAL)) || + (!platformMatches && (x2 == NOT_EQUAL))) { checkPlatform = YES; - else + } + else { return 0; + } } - else + else { return 0; // CODE_IFSYSTEMSTORE is not supported except TSS_PLATFORM + } i+=5; break; diff --git a/windows/src/test/manual-tests/platform-rules/platform-results.xlsx b/windows/src/test/manual-tests/platform-rules/platform-results.xlsx index f3e0eef1ab4ddd74ed1af955c8fcdd6041989fe4..6eb0927ce92e5669c53c19b6a58d3a5452d9d37b 100644 GIT binary patch delta 13890 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 BE!_YB delta 13680 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 Date: Sun, 17 Jun 2018 23:56:54 -0400 Subject: [PATCH 7/7] [Mac] Added unit tests for inverted platform logic --- .../KeymanEngine4MacTests/KMEngineTests.m | 20 ++++++++++++++++++ .../KeymanEngine4MacTests/PlatformTest.kmn | 4 ++++ .../KeymanEngine4MacTests/PlatformTest.kmx | Bin 4962 -> 5188 bytes 3 files changed, 24 insertions(+) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m index 2570371631..290aaf3741 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m @@ -344,4 +344,24 @@ NSString * names[nCombinations]; NSString *output = [self checkPlatform_getOutputForKeystroke:@"m" modifierFlags:0 keyCode:kVK_ANSI_M]; XCTAssert([output isEqualToString:@" macOS native desktop hardware"], @"Expected checkPlatform to return YES for macOS native desktop hardware."); } + +- (void)testContextMatch_InvertedPlatformLogic_NotTouch { + NSString *output = [self checkPlatform_getOutputForKeystroke:@"x" modifierFlags:0 keyCode:kVK_ANSI_X]; + XCTAssert([output isEqualToString:@" !Touch"], @"Expected !touch to be true."); +} + +// This allows for easy debugging of the "manual" platformtest keyboard developed for filling in the test spreadsheet. +//- (void)testCheckPlatform_temp_UnknownPlatformX { +// KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:@"/Users/tom/Documents/keymanapp/keyman/windows/src/test/manual-tests/platform-rules/platformtest.kmx"]; +// +// KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@""]; +// NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"a" charactersIgnoringModifiers:@"a" isARepeat:NO keyCode:kVK_ANSI_A]; +// NSArray *actions = [engine processEvent:event]; +// XCTAssert(actions.count == 1, @"Expected 1 action"); +// NSDictionary *action = actions[0]; +// NSString *actionType = [[action allKeys] objectAtIndex:0]; +// XCTAssert([actionType isEqualToString:Q_STR], @"Expected Q_STR action"); +// NSString *output = [action objectForKey:actionType]; +// XCTAssert([output isEqualToString:@"hardware macosx desktop native undefined !touch undefined macosx"], @"Expected !touch."); +//} @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn index 265df6d634..8ffe47fba4 100755 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmn @@ -71,6 +71,10 @@ platform('tablet') + [K_T] > ' Mobile' platform('phone') + [K_T] > ' Mobile' + [K_T] > ' [Mobile Undefined]' +if(&platform != 'hardware') + [K_X] > ' !Hardware' +if(&platform != 'touch') + [K_X] > ' !Touch' ++ [K_X] > ' [Inverted rule Failed]' + platform('tablet ie web') + [K_M] > ' tablet ie web' platform('touch phone safari web') + [K_M] > ' phone safari web' platform('Windows desktop native hardware') + [K_M] > ' Windows desktop native hardware' diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmx b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/PlatformTest.kmx index 0a06ba4784958752f1f3eaa4ff37e8f782505330..909154f325bcc1e87bab23e141aec7748a5770c8 100644 GIT binary patch literal 5188 zcmbW5Uue~37{{NjT4u|ZnVOmXG&3`^V_A$4*>sML%}wT})=E0_Y-G;uaE_Wvh;%u^ ziwFrB5g`&G5?+*uL>D3wAzg%oNJJN2h)8%L;f3~j-rw)__x#?Sor!0>JKyj3d7tO~ z`+MK#cRIHAZj#4DuKaX)h487-e|+AiC~l%$tP{D*2Ph5tk59|2`1_goOD@!k%uev~ zheYNiI0s&m;5Fb!6Wj`3kl+su9ya)(!D9xG8+^jxvj(3t_;-W88I-*2=6^vV`9yYr zKLT~2?3Z2GMqn+ly_8`Yl_K9IH032J<1y;$tdyLraAl<^ZgfmQl8GiR=6=+T#M8Ei zh)|-fULuy^LK&4kvYnm?C6Bd0-}HMBrB}M8kG{8o+oV}~=-(Fiy&gr!Fhc!NP#LZx zDBwAYUV!hwdlTQouHGKm2i9?Jr$*VaEz&Ms#Ox-j)@*jH2i}e<{Es7ax_W)G6>Woy zpt`a+o~q6C({qh)Yw9@jGC)rT-KdLyArl348`PA~o5OeCEPZA<4_=VzB=L#R5>x+*$1W#SA`O6cO+ z&~?v)+g*%x8SmD_yEXCNl=1GS=j&OoX1pgK`@|Ku`@#A}ZUnk-z}cTja-zy7*A!l>DGp4du+kDdQ`XFW(HaZhEXCzQpI ztDFY@qpMRxX-|ZPCXw5Zi%hT2YO~>s11$$%8)#kd5lV-NSA-u7v@!TGN~fuJ9R5R~ zorPbbbenpA!mkC|E%>x2vh`-c7X;cecw?Zoz&<|#p}cE+o8WDM)(bBLS`q$PpdE&P9cbUfPY2pL_zjBR2b$LW z3zsLeT0MMTpe=zn23iZeK=J!P;|;-g2ihU{QA%erUadC{KOShO;J;Ben0goC*8}Z8 z`22=!y`}Jv18pz-+dw-BzZPh>;H#d>#%qFarF5IVyayi+w0-cgKsy5eCeTj6&ji|e z_#c7xH(X|>ds64B7TyqO^WnKbTMd7oqBn~BG>L43j|AEQ_*kGFf&WbL`&rxl1^#QG zU4mZ?w43lnPcvU}t1ew$41XukTH%`mZ2H4UI?&F+F9q5^@SA~l z2VPH_WZRevUrULYEqiC*y*mf3R-R)lQRZIumif-&Z)v@uiYVUtytDR8D}NEQsrQlI zy?QfgPWAzIjhvqQsjt2*MAA=oGRkf0>u8pd^-4YTy~BFs?|FHT?46i;@(5A4+4V2Y zrTi#(Ah7z(%B#9HBc5U%OPptU3mf2G%W*E{ElfR@ewSfYn-9%)e1__Ci|unI?-x10F5;&7l(#KRVp^-NT$#UWZN#~gkMgpMlFg*NZK<>Qyvk=~ z-ujBOW^)8@Tjp%tNyeUsdCRNL(oaUIYpHp1oYPOf|0?hLxh{^)Mtuv@MoJXOyVCuV=?ioM~YrO#6J zNU7hO&M!SZ!u&JLYQucfk7m^rai+>+(;mI$BE_dxd}i%-Zy-~hK+~PyWG4{mDQg^_ zKqP>u>8z!_AkD&(&P!_11m{6dAWfnp-buqZ1wV`WJC4Sl>IB-rQ#rtB^vy8s*>dMy z+4foz*;=ceKj9gtzZOK?B$dv%7n0c4dOv5}!bxYMhTjIXy@lMS;W=I-uP5!bb8p1I zGWg#oN}TyRClR-0KAE5Nj?A8^i(Hh-XX=a2HrbiF*jX!|sV_NOr89Mjv)uog`adko Bs-yq_ literal 4962 zcmbW5Pi$316vht~5wv0jl&V#)T5GLX0qdU-LRz6sOaBr2YLRMU%WDGyZPQm2j4@p_ z#)Tm)j4{NpAS?`F(GVrX1q(yEFoqy8UAZtUh%tl(VPOaXe`oF;?zz*~SLHV6z3=I7GUYZ6=oejvg1;AaxtYH-frVS~pFo-+7rgHITI%HXpG&lo&w@D+ov8GO^= zrHj)(R~TGraJ9i}4c=t%R)cpMyxZUjgQpDs%HX30A2)c~;4=oFH~4phFB^Q#;2Q>) z-Jgzqg~5@*YYg6CaErl%1|Ko_qQN%}-on~jm8_FV@Mam8AsLVfKJyaEC$a~;8`O?+ zNcQ6!fo*|(jO~+A8RL5#P5HPKh!}Nk*2!9_cc$nKdCM^YOD3DRoQF`ikx%bEOonmp zl_O&TF4(9XkX`gdumQYz`ljDQC^_ktUi#h&Zj~n4PXGGccQcBPVTAUhpaNV+kSB5! zJrCbQbPwPAT)P8u5Uk_eMT>%CebOdf25_>41jxOTm=1Fh3#P+eJ^ zPt_*+>AB{&Ep?m&GDuH`+^EMGtInm4G4JMLubYW6c#cf(NQX3obmr2Q`fLia7hRu? zj(>=pLLQylJ?=RPBZ<{6^5p3EyJXV2(0l1T>-_9@Y#3GNS)Yo|O@Tba*f_eld+2i? z0Jpgun={cZNpwpR-IIy#rsvH(uO_1BAG`HLu8+Dhrlh_N#qubq3zBr@MS$aKpz@4LS?0TyBI zkm9?dQRK^qIGZr5oq(SXv~%!_f%XUd7S>KKy)@r#czJnNtAww|I$W!`T?2emplyZc zv2N3D7=AF&rr_TM+Hv@)KsyVc3A9V_KLhP5y!>H(zv4^Bu^e6%XtnT-fz}G&jrE$? zkKhx5HVHoxXy3tq#ojZq7vQsjb{T#>&~C#kmS5W#5zs8_u-!g+86MX zfp!M|PoOQX;5@=?zK!sMfi?yIInXY^uVCG#FMq*r2HKKGMJh4dt{Pq+XdB?IftG_0 z2HFVxFt*Ly_Xzx0pq+%D3$$P0e`9)PxT{g*D*RTUEnPvMG25;h-huh`tk0+mz9Z1` z@QFa1gim9BJ!|Y~_)md01D_4F%kUe4CM#Lvn9WxOuM4y{;U8iVBe5szoja@1%H$~~ zAz~)|xuKPK?5T1df0pVgGlt^5PdjhFwD1=(BYLLj38|-xR!$$_*UahOoyKbI9!Wnn z#3*N;Z=o_^N2o_F)lht?#%j`OigU2N-|v)22UCAoXql}hFI6^)OJTwE7<)2he& zo=b9CuRgf~f2HmbS2#Y)OD;>c-toR#=kwK%ubsU2W#`SF^WInIeBDW1Jpl8bSDdGx zx=){_Rc^0Zg z(;mImLRLk%15tFLrn8pzg3<<0Ixne*qQb4Od)a}s z5RUle7*_j!7WKa>x^@@ZfjW6B2N{k2eoK3{#zhzRy_#gU-ctKdxX0=Lcp^@cVtd@P oNp9=?|9jl?E=%z}?gi(YZ;z{X-r{@Qi_TYUkE?N>|Gvll3k9@`SO5S3