diff --git a/mac/Keyman4Mac/Keyman4Mac/AppDelegate.m b/mac/Keyman4Mac/Keyman4Mac/AppDelegate.m index 3f37d25e89a..2af130ae928 100644 --- a/mac/Keyman4Mac/Keyman4Mac/AppDelegate.m +++ b/mac/Keyman4Mac/Keyman4Mac/AppDelegate.m @@ -33,127 +33,127 @@ @interface AppDelegate () @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { - // Insert code here to initialize your application - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:self.window]; - [self setKMXList]; - self.kbData = [[NSMutableDictionary alloc] initWithCapacity:0]; - NSMutableString *contextBuffer = [NSMutableString stringWithString:@""]; - [self.kbData setObject:contextBuffer forKey:kContextBufferKey]; - //self.context = [NSMutableString stringWithString:@""]; - [self.kbComboBox setDelegate:self]; - [self.kbComboBox selectItemAtIndex:0]; - [self enableAssistiveDevices]; - [self createEventTap]; - /* - NSArray *kvkFiles = [self KVKFiles]; - for (NSString *path in kvkFiles){ - KVKFile *kvkFile = [[KVKFile alloc] initWithFilePath:path]; - if (debugMode) - NSLog(@"%@", kvkFile); - }*/ + // Insert code here to initialize your application + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:self.window]; + [self setKMXList]; + self.kbData = [[NSMutableDictionary alloc] initWithCapacity:0]; + NSMutableString *contextBuffer = [NSMutableString stringWithString:@""]; + [self.kbData setObject:contextBuffer forKey:kContextBufferKey]; + //self.context = [NSMutableString stringWithString:@""]; + [self.kbComboBox setDelegate:self]; + [self.kbComboBox selectItemAtIndex:0]; + [self enableAssistiveDevices]; + [self createEventTap]; + /* + NSArray *kvkFiles = [self KVKFiles]; + for (NSString *path in kvkFiles){ + KVKFile *kvkFile = [[KVKFile alloc] initWithFilePath:path]; + if (debugMode) + NSLog(@"%@", kvkFile); + }*/ } - (void)applicationWillTerminate:(NSNotification *)aNotification { - // Insert code here to tear down your application - [[NSNotificationCenter defaultCenter] removeObserver:self]; + // Insert code here to tear down your application + [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)awakeFromNib { - // Keep the aspect ratio constant at its current value - [self.window setAspectRatio:self.window.frame.size]; - NSSize size = self.window.frame.size; - [self.window setMaxSize:NSMakeSize(size.width*1.6, size.height*1.6)]; - [self.window setMinSize:NSMakeSize(size.width*0.8, size.height*0.8)]; - [self.window setBackgroundColor:[NSColor colorWithRed:241.0/255.0 green:242.0/255.0 blue:242.0/255.0 alpha:1.0]]; + // Keep the aspect ratio constant at its current value + [self.window setAspectRatio:self.window.frame.size]; + NSSize size = self.window.frame.size; + [self.window setMaxSize:NSMakeSize(size.width*1.6, size.height*1.6)]; + [self.window setMinSize:NSMakeSize(size.width*0.8, size.height*0.8)]; + [self.window setBackgroundColor:[NSColor colorWithRed:241.0/255.0 green:242.0/255.0 blue:242.0/255.0 alpha:1.0]]; } - (void)windowDidResize:(NSNotification *)notification { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "AppDelegate windowDidResize"); - [self.oskView resizeOSKLayout]; + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "AppDelegate windowDidResize"); + [self.oskView resizeOSKLayout]; } - (BOOL)createEventTap { - CGEventMask keyboardMask = CGEventMaskBit(kCGEventKeyDown); - //CGEventMask mouseMask = CGEventMaskBit(kCGEventLeftMouseUp)|CGEventMaskBit(kCGEventRightMouseUp); - CGEventMask mask = keyboardMask; // + mouseMask; - self.machPortRef = CGEventTapCreate( - kCGAnnotatedSessionEventTap, - kCGHeadInsertEventTap, - kCGEventTapOptionDefault, - mask, - (CGEventTapCallBack)eventTapFunction, - (__bridge void *)(self.kbData)); - if (!self.machPortRef) { - NSLog(@"Can't install keyboard & mouse hook."); - return NO; - } - - CFRunLoopSourceRef keyboardEventSrc = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.machPortRef, 0); - if (!keyboardEventSrc) - return NO; - - CFRunLoopRef runLoop = CFRunLoopGetCurrent(); - if (!runLoop) { - CFRelease(keyboardEventSrc); - return NO; - } - - CFRunLoopAddSource(runLoop, keyboardEventSrc, kCFRunLoopDefaultMode); + CGEventMask keyboardMask = CGEventMaskBit(kCGEventKeyDown); + //CGEventMask mouseMask = CGEventMaskBit(kCGEventLeftMouseUp)|CGEventMaskBit(kCGEventRightMouseUp); + CGEventMask mask = keyboardMask; // + mouseMask; + self.machPortRef = CGEventTapCreate( + kCGAnnotatedSessionEventTap, + kCGHeadInsertEventTap, + kCGEventTapOptionDefault, + mask, + (CGEventTapCallBack)eventTapFunction, + (__bridge void *)(self.kbData)); + if (!self.machPortRef) { + NSLog(@"Can't install keyboard & mouse hook."); + return NO; + } + + CFRunLoopSourceRef keyboardEventSrc = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.machPortRef, 0); + if (!keyboardEventSrc) + return NO; + + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + if (!runLoop) { CFRelease(keyboardEventSrc); - return YES; + return NO; + } + + CFRunLoopAddSource(runLoop, keyboardEventSrc, kCFRunLoopDefaultMode); + CFRelease(keyboardEventSrc); + return YES; } CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { - // If key map is not enable, return the event without modifying - if (!isKeyMapEnabled) - return event; - - // Get a pointer to the context - NSMutableDictionary *kbData = (__bridge NSMutableDictionary *)(refcon); - NSMutableString *contextBuffer = [kbData objectForKey:kContextBufferKey]; - KMXFile *kmx = [kbData objectForKey:kKMXFileKey]; - BOOL handled = NO; - - if (type == NX_KEYDOWN) { - NSLog(@"AppDelegate eventTapFunction key down event: %@", event); - // Key down event - NSEvent *mEvent = [NSEvent eventWithCGEvent:event]; - KMEngine *kme = [[KMEngine alloc] initWithKMX:kmx context:contextBuffer verboseLogging:debugMode]; - CoreKeyOutput *coreKeyOutput = [kme processEvent:mEvent]; - if (coreKeyOutput) { - if (coreKeyOutput.hasTextToInsert) { - NSString *output = coreKeyOutput.textToInsert; - UniChar *outCStr = (UniChar *)[output cStringUsingEncoding:NSUTF16StringEncoding]; - unsigned short kc = [mEvent keyCode]; - CGEventRef kEventDown = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kc, true); - CGEventRef kEventUp = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kc, false); - CGEventKeyboardSetUnicodeString(kEventDown, output.length, outCStr); - CGEventKeyboardSetUnicodeString(kEventUp, output.length, outCStr); - CGEventTapPostEvent(proxy, kEventDown); - CGEventTapPostEvent(proxy, kEventUp); - CFRelease(kEventDown); - CFRelease(kEventUp); - } - if (coreKeyOutput.emitKeystroke) { - return NULL; - } - if (coreKeyOutput.alert) { - [[NSSound soundNamed:@"Tink"] play]; - } - - handled = YES; - } + // If key map is not enable, return the event without modifying + if (!isKeyMapEnabled) + return event; + + // Get a pointer to the context + NSMutableDictionary *kbData = (__bridge NSMutableDictionary *)(refcon); + NSMutableString *contextBuffer = [kbData objectForKey:kContextBufferKey]; + KMXFile *kmx = [kbData objectForKey:kKMXFileKey]; + BOOL handled = NO; + + if (type == NX_KEYDOWN) { + NSLog(@"AppDelegate eventTapFunction key down event: %@", event); + // Key down event + NSEvent *mEvent = [NSEvent eventWithCGEvent:event]; + KMEngine *kme = [[KMEngine alloc] initWithKMX:kmx context:contextBuffer verboseLogging:debugMode]; + CoreKeyOutput *coreKeyOutput = [kme processEvent:mEvent]; + if (coreKeyOutput) { + if (coreKeyOutput.hasTextToInsert) { + NSString *output = coreKeyOutput.textToInsert; + UniChar *outCStr = (UniChar *)[output cStringUsingEncoding:NSUTF16StringEncoding]; + unsigned short kc = [mEvent keyCode]; + CGEventRef kEventDown = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kc, true); + CGEventRef kEventUp = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kc, false); + CGEventKeyboardSetUnicodeString(kEventDown, output.length, outCStr); + CGEventKeyboardSetUnicodeString(kEventUp, output.length, outCStr); + CGEventTapPostEvent(proxy, kEventDown); + CGEventTapPostEvent(proxy, kEventUp); + CFRelease(kEventDown); + CFRelease(kEventUp); + } + if (coreKeyOutput.emitKeystroke) { + return NULL; + } + if (coreKeyOutput.alert) { + [[NSSound soundNamed:@"Tink"] play]; + } + + handled = YES; } - - return handled?NULL:event; + } + + return handled?NULL:event; } - (void)enableAssistiveDevices { - NSDictionary *errorDict; - NSAppleEventDescriptor *returnDescriptor = NULL; - - NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithSource: + NSDictionary *errorDict; + NSAppleEventDescriptor *returnDescriptor = NULL; + + NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithSource: @"\ on isUIScriptingOn()\n\ tell application \"System Events\" to set isUIScriptingEnabled to UI elements enabled\n\ @@ -172,139 +172,139 @@ on turnUIScriptingOn(switch)\n\ display dialog \"Access for assistive devices for Keyman is now on\"\n\ end if\n\ end run"]; - - returnDescriptor = [scriptObject executeAndReturnError: &errorDict]; - - if (returnDescriptor != NULL) { - // successful execution - if (kAENullEvent != [returnDescriptor descriptorType]) { - // script returned an AppleScript result - if (cAEList == [returnDescriptor descriptorType]) { - // result is a list of other descriptors - } - else { - // coerce the result to the appropriate ObjC type - } - } - } - else { - // no script result, handle error here + + returnDescriptor = [scriptObject executeAndReturnError: &errorDict]; + + if (returnDescriptor != NULL) { + // successful execution + if (kAENullEvent != [returnDescriptor descriptorType]) { + // script returned an AppleScript result + if (cAEList == [returnDescriptor descriptorType]) { + // result is a list of other descriptors + } + else { + // coerce the result to the appropriate ObjC type + } } + } + else { + // no script result, handle error here + } } - (void)comboBoxSelectionDidChange:(NSNotification *)notification { - if (self.kbComboBox.indexOfSelectedItem == 0) { - isKeyMapEnabled = NO; - self.imgView.image = nil; - //self.oskView.hidden = YES; + if (self.kbComboBox.indexOfSelectedItem == 0) { + isKeyMapEnabled = NO; + self.imgView.image = nil; + //self.oskView.hidden = YES; + } + else { + isKeyMapEnabled = YES; + [self clearContext]; + NSString *kmxPath = [self.kmxList objectAtIndex:self.kbComboBox.indexOfSelectedItem-1]; + KMXFile *kmx = [[KMXFile alloc] initWithFilePath:kmxPath]; + if (![kmx isValid]) { + NSAlert *alert = [[NSAlert alloc] init]; + [alert addButtonWithTitle:@"OK"]; + [alert setMessageText:@"Invalid KMX file"]; + [alert setInformativeText:@"This KMX file contains some invalid code!"]; + [alert setAlertStyle:NSAlertStyleWarning]; + [alert runModal]; } - else { - isKeyMapEnabled = YES; - [self clearContext]; - NSString *kmxPath = [self.kmxList objectAtIndex:self.kbComboBox.indexOfSelectedItem-1]; - KMXFile *kmx = [[KMXFile alloc] initWithFilePath:kmxPath]; - if (![kmx isValid]) { - NSAlert *alert = [[NSAlert alloc] init]; - [alert addButtonWithTitle:@"OK"]; - [alert setMessageText:@"Invalid KMX file"]; - [alert setInformativeText:@"This KMX file contains some invalid code!"]; - [alert setAlertStyle:NSAlertStyleWarning]; - [alert runModal]; - } - - NSString *packagePath = [kmxPath stringByDeletingLastPathComponent]; - NSDictionary *infoDict = [KMXFile keyboardInfoFromKmxFile:kmxPath]; - NSString *kvkFilename = [infoDict objectForKey:kKMVisualKeyboardKey]; - if (kvkFilename && [kvkFilename length]) { - NSString *kvkPath = [packagePath stringByAppendingPathComponent:kvkFilename]; - _kvk = [[KVKFile alloc] initWithFilePath:kvkPath]; - [self.oskView setKvk:_kvk]; - //NSLog(@"kvk:nkeys: \n %@", _kvk.keys); - } - - [self.kbData setObject:kmx forKey:kKMXFileKey]; - self.imgView.image = kmx.bitmap; - - int index = 0; - for (NSObject *kmStore in kmx.store) { - NSLog(@"%d: %@", index, kmStore); - index++; - } - - for (NSObject *gp in kmx.group) { - if (debugMode) { - NSLog(@"Group %@", gp); - //NSLog(@"match = %@", gp.match); - //NSLog(@"nomatch = %@", gp.noMatch); - /* - for (KMCompKey *kmKey in gp.keys) { - NSLog(@"\nKey: %@", kmKey); - }*/ - } - } + + NSString *packagePath = [kmxPath stringByDeletingLastPathComponent]; + NSDictionary *infoDict = [KMXFile keyboardInfoFromKmxFile:kmxPath]; + NSString *kvkFilename = [infoDict objectForKey:kKMVisualKeyboardKey]; + if (kvkFilename && [kvkFilename length]) { + NSString *kvkPath = [packagePath stringByAppendingPathComponent:kvkFilename]; + _kvk = [[KVKFile alloc] initWithFilePath:kvkPath]; + [self.oskView setKvk:_kvk]; + //NSLog(@"kvk:nkeys: \n %@", _kvk.keys); } + + [self.kbData setObject:kmx forKey:kKMXFileKey]; + self.imgView.image = kmx.bitmap; + + int index = 0; + for (NSObject *kmStore in kmx.store) { + NSLog(@"%d: %@", index, kmStore); + index++; + } + + for (NSObject *gp in kmx.group) { + if (debugMode) { + NSLog(@"Group %@", gp); + //NSLog(@"match = %@", gp.match); + //NSLog(@"nomatch = %@", gp.noMatch); + /* + for (KMCompKey *kmKey in gp.keys) { + NSLog(@"\nKey: %@", kmKey); + }*/ + } + } + } } - (void)postKeyUpDown { - // + // } - (void)clearContext { - NSMutableString *contextBuffer = [self.kbData objectForKey:kContextBufferKey]; - [contextBuffer setString:@""]; + NSMutableString *contextBuffer = [self.kbData objectForKey:kContextBufferKey]; + [contextBuffer setString:@""]; } - (void)setKMXList { - self.kmxList = [NSMutableArray arrayWithArray:[self KMXFiles]]; - NSMutableArray *kmxDesc = [[NSMutableArray alloc] initWithCapacity:0]; - for (NSString *path in self.kmxList) { - NSDictionary *infoDict = [KMXFile keyboardInfoFromKmxFile:path]; - if (!infoDict) - continue; - - //if (debugMode) - // NSLog(@"%@", infoDict); - //NSString *str = [NSString stringWithFormat:@"%@ (%@)", [infoDict objectForKey:kKMKeyboardNameKey], [infoDict objectForKey:kKMKeyboardVersionKey]]; - NSString *str = [infoDict objectForKey:kKMKeyboardNameKey]; - [kmxDesc addObject:str]; - } + self.kmxList = [NSMutableArray arrayWithArray:[self KMXFiles]]; + NSMutableArray *kmxDesc = [[NSMutableArray alloc] initWithCapacity:0]; + for (NSString *path in self.kmxList) { + NSDictionary *infoDict = [KMXFile keyboardInfoFromKmxFile:path]; + if (!infoDict) + continue; - [self.kbComboBox addItemsWithObjectValues:kmxDesc]; + //if (debugMode) + // NSLog(@"%@", infoDict); + //NSString *str = [NSString stringWithFormat:@"%@ (%@)", [infoDict objectForKey:kKMKeyboardNameKey], [infoDict objectForKey:kKMKeyboardVersionKey]]; + NSString *str = [infoDict objectForKey:kKMKeyboardNameKey]; + [kmxDesc addObject:str]; + } + + [self.kbComboBox addItemsWithObjectValues:kmxDesc]; } - (NSString *)keyboardsPath { - if (_keyboardsPath == nil) { - NSString *documentDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - _keyboardsPath = [documentDirPath stringByAppendingPathComponent:@"Keyboards"]; - } - - return _keyboardsPath; + if (_keyboardsPath == nil) { + NSString *documentDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + _keyboardsPath = [documentDirPath stringByAppendingPathComponent:@"Keyboards"]; + } + + return _keyboardsPath; } - (NSArray *)KMXFiles { - NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:self.keyboardsPath]; - NSMutableArray *kmxFiles = [[NSMutableArray alloc] initWithCapacity:0]; - NSString *filePath; - while (filePath = (NSString *)[dirEnum nextObject]) { - NSString *extension = [[filePath pathExtension] lowercaseString]; - if ([extension isEqualToString:@"kmx"]) - [kmxFiles addObject:[self.keyboardsPath stringByAppendingPathComponent:filePath]]; - } - - return kmxFiles; + NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:self.keyboardsPath]; + NSMutableArray *kmxFiles = [[NSMutableArray alloc] initWithCapacity:0]; + NSString *filePath; + while (filePath = (NSString *)[dirEnum nextObject]) { + NSString *extension = [[filePath pathExtension] lowercaseString]; + if ([extension isEqualToString:@"kmx"]) + [kmxFiles addObject:[self.keyboardsPath stringByAppendingPathComponent:filePath]]; + } + + return kmxFiles; } - (NSArray *)KVKFiles { - NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:self.keyboardsPath]; - NSMutableArray *kvkFiles = [[NSMutableArray alloc] initWithCapacity:0]; - NSString *filePath; - while (filePath = (NSString *)[dirEnum nextObject]) { - NSString *extension = [[filePath pathExtension] lowercaseString]; - if ([extension isEqualToString:@"kvk"]) - [kvkFiles addObject:[self.keyboardsPath stringByAppendingPathComponent:filePath]]; - } - - return kvkFiles; + NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:self.keyboardsPath]; + NSMutableArray *kvkFiles = [[NSMutableArray alloc] initWithCapacity:0]; + NSString *filePath; + while (filePath = (NSString *)[dirEnum nextObject]) { + NSString *extension = [[filePath pathExtension] lowercaseString]; + if ([extension isEqualToString:@"kvk"]) + [kvkFiles addObject:[self.keyboardsPath stringByAppendingPathComponent:filePath]]; + } + + return kvkFiles; } @end diff --git a/mac/Keyman4Mac/Keyman4Mac/KMBarView.m b/mac/Keyman4Mac/Keyman4Mac/KMBarView.m index 8978f8a28f5..ece15372743 100644 --- a/mac/Keyman4Mac/Keyman4Mac/KMBarView.m +++ b/mac/Keyman4Mac/Keyman4Mac/KMBarView.m @@ -11,29 +11,29 @@ @implementation KMBarView - (void)drawRect:(NSRect)rect { - CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; - - NSRect rect1 = NSMakeRect(0, 0, rect.size.width*0.56, rect.size.height); - NSRect rect2 = NSMakeRect(rect1.size.width, 0, rect.size.width*0.23, rect.size.height); - NSRect rect3 = NSMakeRect(rect2.origin.x + rect2.size.width, 0, rect.size.width*0.21, rect.size.height); - - CGContextSetFillColorWithColor(context, [NSColor colorWithRed:1.0 green:104.0/255.0 blue:38.0/255.0 alpha:1.0].CGColor); - CGContextBeginPath(context); - CGContextAddRect(context, rect1); - CGContextClosePath(context); - CGContextDrawPath(context, kCGPathFill); - - CGContextSetFillColorWithColor(context, [NSColor colorWithRed:200.0/255.0 green:0.0 blue:54.0/255.0 alpha:1.0].CGColor); - CGContextBeginPath(context); - CGContextAddRect(context, rect2); - CGContextClosePath(context); - CGContextDrawPath(context, kCGPathFill); - - CGContextSetFillColorWithColor(context, [NSColor colorWithRed:74.0/255.0 green:186.0/255.0 blue:208.0/255.0 alpha:1.0].CGColor); - CGContextBeginPath(context); - CGContextAddRect(context, rect3); - CGContextClosePath(context); - CGContextDrawPath(context, kCGPathFill); + CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; + + NSRect rect1 = NSMakeRect(0, 0, rect.size.width*0.56, rect.size.height); + NSRect rect2 = NSMakeRect(rect1.size.width, 0, rect.size.width*0.23, rect.size.height); + NSRect rect3 = NSMakeRect(rect2.origin.x + rect2.size.width, 0, rect.size.width*0.21, rect.size.height); + + CGContextSetFillColorWithColor(context, [NSColor colorWithRed:1.0 green:104.0/255.0 blue:38.0/255.0 alpha:1.0].CGColor); + CGContextBeginPath(context); + CGContextAddRect(context, rect1); + CGContextClosePath(context); + CGContextDrawPath(context, kCGPathFill); + + CGContextSetFillColorWithColor(context, [NSColor colorWithRed:200.0/255.0 green:0.0 blue:54.0/255.0 alpha:1.0].CGColor); + CGContextBeginPath(context); + CGContextAddRect(context, rect2); + CGContextClosePath(context); + CGContextDrawPath(context, kCGPathFill); + + CGContextSetFillColorWithColor(context, [NSColor colorWithRed:74.0/255.0 green:186.0/255.0 blue:208.0/255.0 alpha:1.0].CGColor); + CGContextBeginPath(context); + CGContextAddRect(context, rect3); + CGContextClosePath(context); + CGContextDrawPath(context, kCGPathFill); } @end diff --git a/mac/Keyman4Mac/Keyman4Mac/main.m b/mac/Keyman4Mac/Keyman4Mac/main.m index 96bc2e50eed..6fce1a08448 100644 --- a/mac/Keyman4Mac/Keyman4Mac/main.m +++ b/mac/Keyman4Mac/Keyman4Mac/main.m @@ -9,5 +9,5 @@ #import int main(int argc, const char * argv[]) { - return NSApplicationMain(argc, argv); + return NSApplicationMain(argc, argv); } diff --git a/mac/Keyman4MacIM/Keyman4MacIM/Categories/NSString+SuppMethods.m b/mac/Keyman4MacIM/Keyman4MacIM/Categories/NSString+SuppMethods.m index 120e67a42f4..7806b8d88e4 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/Categories/NSString+SuppMethods.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/Categories/NSString+SuppMethods.m @@ -11,7 +11,7 @@ @implementation NSString (SuppMethods) - (BOOL)startsWith:(NSString *)str { - return [[self lowercaseString] hasPrefix:[str lowercaseString]]; + return [[self lowercaseString] hasPrefix:[str lowercaseString]]; } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/Categories/NSWindow+SuppMethods.m b/mac/Keyman4MacIM/Keyman4MacIM/Categories/NSWindow+SuppMethods.m index be9364a4cb2..44af2cf5952 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/Categories/NSWindow+SuppMethods.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/Categories/NSWindow+SuppMethods.m @@ -11,50 +11,50 @@ @implementation NSWindow (SuppMethods) - (void)centerInParent { - if (self.parentWindow == nil) { - [self center]; - return; - } - - NSRect cFrame = self.frame; - NSRect pFrame = self.parentWindow.frame; - CGFloat x = pFrame.origin.x + (NSWidth(pFrame) - NSWidth(cFrame))/2; - CGFloat y = pFrame.origin.y + (NSHeight(pFrame) - NSHeight(cFrame))/2; - [self setFrameOrigin:NSMakePoint(x, y)]; + if (self.parentWindow == nil) { + [self center]; + return; + } + + NSRect cFrame = self.frame; + NSRect pFrame = self.parentWindow.frame; + CGFloat x = pFrame.origin.x + (NSWidth(pFrame) - NSWidth(cFrame))/2; + CGFloat y = pFrame.origin.y + (NSHeight(pFrame) - NSHeight(cFrame))/2; + [self setFrameOrigin:NSMakePoint(x, y)]; } - (void)centerInWindow:(NSWindow *)window { - if (window == nil) { - [self center]; - return; - } - - NSRect sFrame = self.frame; - NSRect wFrame = window.frame; - CGFloat x = wFrame.origin.x + (NSWidth(wFrame) - NSWidth(sFrame))/2; - CGFloat y = wFrame.origin.y + (NSHeight(wFrame) - NSHeight(sFrame))/2; - [self setFrameOrigin:NSMakePoint(x, y)]; + if (window == nil) { + [self center]; + return; + } + + NSRect sFrame = self.frame; + NSRect wFrame = window.frame; + CGFloat x = wFrame.origin.x + (NSWidth(wFrame) - NSWidth(sFrame))/2; + CGFloat y = wFrame.origin.y + (NSHeight(wFrame) - NSHeight(sFrame))/2; + [self setFrameOrigin:NSMakePoint(x, y)]; } - (void)addViewToTitleBar:(NSView *)viewToAdd positionX:(CGFloat)x { - viewToAdd.frame = NSMakeRect(x, NSHeight([self.contentView frame]), NSWidth(viewToAdd.frame), self.titleBarHeight); - - NSUInteger mask = 0; - if(x > NSWidth(self.frame)/2.0) { - mask |= NSViewMinXMargin; - } - else { - mask |= NSViewMaxXMargin; - } - - [viewToAdd setAutoresizingMask:mask|NSViewMinYMargin]; - [[self.contentView superview] addSubview:viewToAdd]; + viewToAdd.frame = NSMakeRect(x, NSHeight([self.contentView frame]), NSWidth(viewToAdd.frame), self.titleBarHeight); + + NSUInteger mask = 0; + if(x > NSWidth(self.frame)/2.0) { + mask |= NSViewMinXMargin; + } + else { + mask |= NSViewMaxXMargin; + } + + [viewToAdd setAutoresizingMask:mask|NSViewMinYMargin]; + [[self.contentView superview] addSubview:viewToAdd]; } - (CGFloat)titleBarHeight { - NSRect sFrame = [self.contentView superview].frame; - NSRect cFrame = [self.contentView frame]; - return NSHeight(sFrame) - NSHeight(cFrame); + NSRect sFrame = [self.contentView superview].frame; + NSRect cFrame = [self.contentView frame]; + return NSHeight(sFrame) - NSHeight(cFrame); } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutBGView.m b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutBGView.m index e2cda092d8a..030e1b4ed25 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutBGView.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutBGView.m @@ -17,26 +17,26 @@ @implementation KMAboutBGView // topFill origin=(0,252) size=(66,450) // botFill origin=(0,0) size=(252,450) - (void)drawRect:(NSRect)rect { - NSRect topFill, botFill; - topFill = rect; - botFill = rect; -// NSLog(@"rect origin x %f y %f size h %f w %f", rect.origin.x, rect.origin.y, rect.size.height, rect.size.width); - NSView *topImgView = [self viewWithTag:1]; -// NSLog(@"topImgView origin x %f y %f size h %f w %f before", topImgView.frame.origin.x, topImgView.frame.origin.y, topImgView.frame.size.height, topImgView.frame.size.width); - NSInteger imgOriginHeightDelta = topImgView.frame.origin.y - rect.origin.y; - topFill.origin.y += imgOriginHeightDelta; - topFill.size.height -= imgOriginHeightDelta; - botFill.size.height = imgOriginHeightDelta; -// NSLog(@"topFill origin x %f y %f size h %f w %f after raising to imgHeight %ld", topFill.origin.x, topFill.origin.y, topFill.size.height, topFill.size.width, imgOriginHeightDelta); -// NSLog(@"botFill origin x %f y %f size h %f w %f after reducing by imgHeight %ld", botFill.origin.x, botFill.origin.y, botFill.size.height, botFill.size.width, imgOriginHeightDelta); - [[NSColor whiteColor] setFill]; - NSRectFillUsingOperation(topFill, NSCompositingOperationSourceOver); - [[NSColor windowBackgroundColor] setFill]; - NSRectFillUsingOperation(botFill, NSCompositingOperationSourceOver); + NSRect topFill, botFill; + topFill = rect; + botFill = rect; + // NSLog(@"rect origin x %f y %f size h %f w %f", rect.origin.x, rect.origin.y, rect.size.height, rect.size.width); + NSView *topImgView = [self viewWithTag:1]; + // NSLog(@"topImgView origin x %f y %f size h %f w %f before", topImgView.frame.origin.x, topImgView.frame.origin.y, topImgView.frame.size.height, topImgView.frame.size.width); + NSInteger imgOriginHeightDelta = topImgView.frame.origin.y - rect.origin.y; + topFill.origin.y += imgOriginHeightDelta; + topFill.size.height -= imgOriginHeightDelta; + botFill.size.height = imgOriginHeightDelta; + // NSLog(@"topFill origin x %f y %f size h %f w %f after raising to imgHeight %ld", topFill.origin.x, topFill.origin.y, topFill.size.height, topFill.size.width, imgOriginHeightDelta); + // NSLog(@"botFill origin x %f y %f size h %f w %f after reducing by imgHeight %ld", botFill.origin.x, botFill.origin.y, botFill.size.height, botFill.size.width, imgOriginHeightDelta); + [[NSColor whiteColor] setFill]; + NSRectFillUsingOperation(topFill, NSCompositingOperationSourceOver); + [[NSColor windowBackgroundColor] setFill]; + NSRectFillUsingOperation(botFill, NSCompositingOperationSourceOver); } - (BOOL)mouseDownCanMoveWindow { - return YES; + return YES; } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutWindow.m b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutWindow.m index bcc68e64730..28d8881e09c 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutWindow.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutWindow.m @@ -11,7 +11,7 @@ @implementation KMAboutWindow - (BOOL)isMovableByWindowBackground { - return YES; + return YES; } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutWindowController.m index ba7d1a030f3..d8674184c06 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMAboutWindowController.m @@ -22,73 +22,73 @@ @interface KMAboutWindowController () @implementation KMAboutWindowController - (KMInputMethodAppDelegate *)AppDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; + return (KMInputMethodAppDelegate *)[NSApp delegate]; } - (void)windowDidLoad { - [super windowDidLoad]; - - // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. - [self.window setBackgroundColor:[NSColor whiteColor]]; - - KeymanVersionInfo versionInfo = [[self AppDelegate] versionInfo]; - NSString *versionString = NSLocalizedString(@"version-label-text", nil); - [self.versionLabel setStringValue:[NSString localizedStringWithFormat:versionString, versionInfo.versionWithTag]]; - + [super windowDidLoad]; + + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. + [self.window setBackgroundColor:[NSColor whiteColor]]; + + KeymanVersionInfo versionInfo = [[self AppDelegate] versionInfo]; + NSString *versionString = NSLocalizedString(@"version-label-text", nil); + [self.versionLabel setStringValue:[NSString localizedStringWithFormat:versionString, versionInfo.versionWithTag]]; + NSMutableString *copyrightInfo = [[NSMutableString alloc] initWithString: [[[NSBundle mainBundle] infoDictionary] objectForKey:@"NSHumanReadableCopyright"]]; - [self.copyrightLabel setStringValue:copyrightInfo]; - - NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:[self.licenseButton bounds] - options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways - owner:self - userInfo:nil]; - [self.licenseButton addTrackingArea:trackingArea]; - [self setLicenseButtonTitle:self.licenseButton.title underlined:NO]; + [self.copyrightLabel setStringValue:copyrightInfo]; + + NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:[self.licenseButton bounds] + options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways + owner:self + userInfo:nil]; + [self.licenseButton addTrackingArea:trackingArea]; + [self setLicenseButtonTitle:self.licenseButton.title underlined:NO]; } - (IBAction)configAction:(id)sender { - // Using `showConfigurationWindow` instead of `showPreferences:` because `showPreferences:` is missing in - // High Sierra (10.13.1 - 10.13.3). See: https://bugreport.apple.com/web/?problemID=35422518 - // rrb: where Apple's API is broken (10.13.1-10.13.3) call our workaround, otherwise, call showPreferences - u_int16_t systemVersion = [KMOSVersion SystemVersion]; - if ([KMOSVersion Version_10_13_1] <= systemVersion && systemVersion <= [KMOSVersion Version_10_13_3]) // between 10.13.1 and 10.13.3 inclusive - { - NSLog(@"About Box: calling workaround instead of showPreferences (sys ver %x)", systemVersion); - [self.AppDelegate showConfigurationWindow]; // call our workaround - } - else - { - NSLog(@"About Box: calling Apple's showPreferences (sys ver %x)", systemVersion); - [self.AppDelegate.inputController showPreferences:sender]; // call Apple API - } - [self close]; + // Using `showConfigurationWindow` instead of `showPreferences:` because `showPreferences:` is missing in + // High Sierra (10.13.1 - 10.13.3). See: https://bugreport.apple.com/web/?problemID=35422518 + // rrb: where Apple's API is broken (10.13.1-10.13.3) call our workaround, otherwise, call showPreferences + u_int16_t systemVersion = [KMOSVersion SystemVersion]; + if ([KMOSVersion Version_10_13_1] <= systemVersion && systemVersion <= [KMOSVersion Version_10_13_3]) // between 10.13.1 and 10.13.3 inclusive + { + NSLog(@"About Box: calling workaround instead of showPreferences (sys ver %x)", systemVersion); + [self.AppDelegate showConfigurationWindow]; // call our workaround + } + else + { + NSLog(@"About Box: calling Apple's showPreferences (sys ver %x)", systemVersion); + [self.AppDelegate.inputController showPreferences:sender]; // call Apple API + } + [self close]; } - (IBAction)closeAction:(id)sender { - [self close]; + [self close]; } - (IBAction)licenseAction:(id)sender { - [[NSWorkspace sharedWorkspace] openURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"keyman-for-mac-os-license" ofType:@"html"]]]; + [[NSWorkspace sharedWorkspace] openURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"keyman-for-mac-os-license" ofType:@"html"]]]; } - (void)mouseEntered:(NSEvent *)theEvent{ - [self setLicenseButtonTitle:self.licenseButton.title underlined:YES]; + [self setLicenseButtonTitle:self.licenseButton.title underlined:YES]; } - (void)mouseExited:(NSEvent *)theEvent{ - [self setLicenseButtonTitle:self.licenseButton.title underlined:NO]; + [self setLicenseButtonTitle:self.licenseButton.title underlined:NO]; } - (void)setLicenseButtonTitle:(NSString *)title underlined:(BOOL)underlined { - NSMutableAttributedString *aTitle = [[NSMutableAttributedString alloc] initWithString:title]; - [aTitle addAttribute:NSFontAttributeName value:[self.licenseButton font] range:NSMakeRange(0, title.length)]; - NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; - [paragraphStyle setAlignment:NSTextAlignmentCenter]; - [aTitle addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, title.length)]; - if (underlined) - [aTitle addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSUnderlineStyleSingle] range:NSMakeRange(0, title.length)]; - [self.licenseButton setAttributedTitle:aTitle]; + NSMutableAttributedString *aTitle = [[NSMutableAttributedString alloc] initWithString:title]; + [aTitle addAttribute:NSFontAttributeName value:[self.licenseButton font] range:NSMakeRange(0, title.length)]; + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + [paragraphStyle setAlignment:NSTextAlignmentCenter]; + [aTitle addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, title.length)]; + if (underlined) + [aTitle addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSUnderlineStyleSingle] range:NSMakeRange(0, title.length)]; + [self.licenseButton setAttributedTitle:aTitle]; } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMBarView.m b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMBarView.m index 2b0604c534b..b9a400706a3 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMBarView.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMAboutWindow/KMBarView.m @@ -11,29 +11,29 @@ @implementation KMBarView - (void)drawRect:(NSRect)rect { - CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; - - NSRect rect1 = NSMakeRect(0, 0, rect.size.width*0.56, rect.size.height); - NSRect rect2 = NSMakeRect(rect1.size.width, 0, rect.size.width*0.23, rect.size.height); - NSRect rect3 = NSMakeRect(rect2.origin.x + rect2.size.width, 0, rect.size.width*0.21, rect.size.height); - - CGContextSetFillColorWithColor(context, [NSColor colorWithSRGBRed:246.0/255.0 green:137.0/255.0 blue:36.0/255.0 alpha:1.0].CGColor); - CGContextBeginPath(context); - CGContextAddRect(context, rect1); - CGContextClosePath(context); - CGContextDrawPath(context, kCGPathFill); - - CGContextSetFillColorWithColor(context, [NSColor colorWithSRGBRed:204.0/255.0 green:56.0/255.0 blue:70.0/255.0 alpha:1.0].CGColor); - CGContextBeginPath(context); - CGContextAddRect(context, rect2); - CGContextClosePath(context); - CGContextDrawPath(context, kCGPathFill); - - CGContextSetFillColorWithColor(context, [NSColor colorWithSRGBRed:121.0/255.0 green:195.0/255.0 blue:218.0/255.0 alpha:1.0].CGColor); - CGContextBeginPath(context); - CGContextAddRect(context, rect3); - CGContextClosePath(context); - CGContextDrawPath(context, kCGPathFill); + CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; + + NSRect rect1 = NSMakeRect(0, 0, rect.size.width*0.56, rect.size.height); + NSRect rect2 = NSMakeRect(rect1.size.width, 0, rect.size.width*0.23, rect.size.height); + NSRect rect3 = NSMakeRect(rect2.origin.x + rect2.size.width, 0, rect.size.width*0.21, rect.size.height); + + CGContextSetFillColorWithColor(context, [NSColor colorWithSRGBRed:246.0/255.0 green:137.0/255.0 blue:36.0/255.0 alpha:1.0].CGColor); + CGContextBeginPath(context); + CGContextAddRect(context, rect1); + CGContextClosePath(context); + CGContextDrawPath(context, kCGPathFill); + + CGContextSetFillColorWithColor(context, [NSColor colorWithSRGBRed:204.0/255.0 green:56.0/255.0 blue:70.0/255.0 alpha:1.0].CGColor); + CGContextBeginPath(context); + CGContextAddRect(context, rect2); + CGContextClosePath(context); + CGContextDrawPath(context, kCGPathFill); + + CGContextSetFillColorWithColor(context, [NSColor colorWithSRGBRed:121.0/255.0 green:195.0/255.0 blue:218.0/255.0 alpha:1.0].CGColor); + CGContextBeginPath(context); + CGContextAddRect(context, rect3); + CGContextClosePath(context); + CGContextDrawPath(context, kCGPathFill); } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m index f4c28857c1c..acb6a4140ff 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m @@ -28,574 +28,574 @@ @interface KMConfigurationWindowController () @implementation KMConfigurationWindowController - (KMInputMethodAppDelegate *)AppDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; + return (KMInputMethodAppDelegate *)[NSApp delegate]; } - (id)initWithWindowNibName:(NSString *)windowNibName { - self = [super initWithWindowNibName:windowNibName]; - if (self) { - if (self.AppDelegate.infoWindow_.window != nil) { - [self.window addChildWindow:self.AppDelegate.infoWindow_.window ordered:NSWindowAbove]; - [self.AppDelegate.infoWindow_.window centerInParent]; - } - else if (self.AppDelegate.downloadKBWindow_.window != nil) { - [self.window addChildWindow:self.AppDelegate.downloadKBWindow_.window ordered:NSWindowAbove]; - [self.AppDelegate.downloadKBWindow_.window centerInParent]; - } - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(timerAction:) name:kKeymanKeyboardDownloadCompletedNotification object:nil]; + self = [super initWithWindowNibName:windowNibName]; + if (self) { + if (self.AppDelegate.infoWindow_.window != nil) { + [self.window addChildWindow:self.AppDelegate.infoWindow_.window ordered:NSWindowAbove]; + [self.AppDelegate.infoWindow_.window centerInParent]; + } + else if (self.AppDelegate.downloadKBWindow_.window != nil) { + [self.window addChildWindow:self.AppDelegate.downloadKBWindow_.window ordered:NSWindowAbove]; + [self.AppDelegate.downloadKBWindow_.window centerInParent]; } - return self; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(timerAction:) name:kKeymanKeyboardDownloadCompletedNotification object:nil]; + } + + return self; } - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [self stopTimer]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self stopTimer]; } - (void)windowDidLoad { - [self.AppDelegate registerConfigurationWindow:self]; - [super windowDidLoad]; - [self.window center]; - [_tableView registerForDraggedTypes:@[NSFilenamesPboardType]]; - _lastReloadDate = [NSDate date]; - [self startTimer]; - - [self.webView setFrameLoadDelegate:(id)self]; - [self.webView setPolicyDelegate:(id)self]; - - NSURL *homeUrl = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html" subdirectory:@"Help"]; - [self.webView.mainFrame loadRequest:[NSURLRequest requestWithURL:homeUrl]]; - - [self.alwaysShowOSKCheckBox setState:(self.AppDelegate.alwaysShowOSK ? NSOnState : NSOffState)]; - [self.useVerboseLoggingCheckBox setState:(self.AppDelegate.useVerboseLogging ? NSOnState : NSOffState)]; + [self.AppDelegate registerConfigurationWindow:self]; + [super windowDidLoad]; + [self.window center]; + [_tableView registerForDraggedTypes:@[NSFilenamesPboardType]]; + _lastReloadDate = [NSDate date]; + [self startTimer]; + + [self.webView setFrameLoadDelegate:(id)self]; + [self.webView setPolicyDelegate:(id)self]; + + NSURL *homeUrl = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html" subdirectory:@"Help"]; + [self.webView.mainFrame loadRequest:[NSURLRequest requestWithURL:homeUrl]]; + + [self.alwaysShowOSKCheckBox setState:(self.AppDelegate.alwaysShowOSK ? NSOnState : NSOffState)]; + [self.useVerboseLoggingCheckBox setState:(self.AppDelegate.useVerboseLogging ? NSOnState : NSOffState)]; } - (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id)listener { - [[NSWorkspace sharedWorkspace] openURL:[actionInformation objectForKey:WebActionOriginalURLKey]]; - [listener ignore]; + [[NSWorkspace sharedWorkspace] openURL:[actionInformation objectForKey:WebActionOriginalURLKey]]; + [listener ignore]; } - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { - NSString* url = [[request URL] absoluteString]; - if (self.AppDelegate.debugMode) - NSLog(@"decidePolicyForNavigationAction, navigating to %@", url); - - if([url hasPrefix: @"file:"]) { - [listener use]; - } else { - [listener ignore]; - [[NSWorkspace sharedWorkspace] openURL: [request URL]]; - } + NSString* url = [[request URL] absoluteString]; + if (self.AppDelegate.debugMode) + NSLog(@"decidePolicyForNavigationAction, navigating to %@", url); + + if([url hasPrefix: @"file:"]) { + [listener use]; + } else { + [listener ignore]; + [[NSWorkspace sharedWorkspace] openURL: [request URL]]; + } } - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame; { - self.supportBack.enabled = [self.webView canGoBack]; - self.supportForward.enabled = [self.webView canGoForward]; + self.supportBack.enabled = [self.webView canGoBack]; + self.supportForward.enabled = [self.webView canGoForward]; } - (IBAction)supportBackAction:(id)sender { - [self.webView goBack]; + [self.webView goBack]; } - (IBAction)supportForwardAction:(id)sender { - [self.webView goForward]; + [self.webView goForward]; } - (IBAction)supportHomeAction:(id)sender { - NSURL *homeUrl = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html" subdirectory:@"Help"]; - [self.webView.mainFrame loadRequest:[NSURLRequest requestWithURL:homeUrl]]; - + NSURL *homeUrl = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html" subdirectory:@"Help"]; + [self.webView.mainFrame loadRequest:[NSURLRequest requestWithURL:homeUrl]]; + } - (void)setTableView:(NSTableView *)tableView { - _tableView = tableView; - NSMenu *menu = [[NSMenu alloc] init]; - NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"Refresh" action:@selector(refreshAction:) keyEquivalent:@""]; - [menu addItem:item]; - [_tableView setMenu:menu]; + _tableView = tableView; + NSMenu *menu = [[NSMenu alloc] init]; + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@"Refresh" action:@selector(refreshAction:) keyEquivalent:@""]; + [menu addItem:item]; + [_tableView setMenu:menu]; } - (void)refreshAction:(id)sender { - [self.AppDelegate setKmxFileList:nil]; - [self setTableContents:nil]; - [self saveActiveKeyboards]; - [self.tableView reloadData]; - _lastReloadDate = [NSDate date]; + [self.AppDelegate setKmxFileList:nil]; + [self setTableContents:nil]; + [self saveActiveKeyboards]; + [self.tableView reloadData]; + _lastReloadDate = [NSDate date]; } - (NSArray *)tableContents { - if (_tableContents == nil) { - _tableContents = [[NSMutableArray alloc] initWithCapacity:0]; - for (int i = 0; i < self.kmxFileList.count; i++) { - id obj = [self.kmxFileList objectAtIndex:i]; - if ([obj isKindOfClass:[NSArray class]]) { - NSArray *pArray = (NSArray *)obj; - NSString *packageFolder = [self packageFolderFromPath:[pArray objectAtIndex:0]]; - NSString *packageName = [self.AppDelegate packageNameFromPackageInfo:packageFolder]; - [_tableContents addObject:[NSDictionary dictionaryWithObjectsAndKeys:packageName, @"HeaderTitle", nil]]; - for (NSString *path in pArray) { - NSDictionary *info = [KMXFile keyboardInfoFromKmxFile:path]; - if (!info) { - info = [[NSDictionary alloc] initWithObjectsAndKeys: - NSLocalizedString(@"message-error-loading-keyboard", nil), kKMKeyboardNameKey, - NSLocalizedString(@"message-error-unknown-metadata", nil), kKMKeyboardVersionKey, - NSLocalizedString(@"message-error-unknown-metadata", nil), kKMKeyboardCopyrightKey, - NSLocalizedString(@"message-error-unknown-metadata", nil), kKMVisualKeyboardKey, - nil]; - } - [_tableContents addObject:info]; - } - } - else { - NSString *path = (NSString *)obj; - NSDictionary *info = [KMXFile keyboardInfoFromKmxFile:path]; - if (!info) { - info = [[NSDictionary alloc] initWithObjectsAndKeys: - NSLocalizedString(@"message-error-loading-keyboard", nil), kKMKeyboardNameKey, - NSLocalizedString(@"message-error-unknown-metadata", nil), kKMKeyboardVersionKey, - NSLocalizedString(@"message-error-unknown-metadata", nil), kKMKeyboardCopyrightKey, - NSLocalizedString(@"message-error-unknown-metadata", nil), kKMVisualKeyboardKey, - nil]; - } - [_tableContents addObject:info]; - } + if (_tableContents == nil) { + _tableContents = [[NSMutableArray alloc] initWithCapacity:0]; + for (int i = 0; i < self.kmxFileList.count; i++) { + id obj = [self.kmxFileList objectAtIndex:i]; + if ([obj isKindOfClass:[NSArray class]]) { + NSArray *pArray = (NSArray *)obj; + NSString *packageFolder = [self packageFolderFromPath:[pArray objectAtIndex:0]]; + NSString *packageName = [self.AppDelegate packageNameFromPackageInfo:packageFolder]; + [_tableContents addObject:[NSDictionary dictionaryWithObjectsAndKeys:packageName, @"HeaderTitle", nil]]; + for (NSString *path in pArray) { + NSDictionary *info = [KMXFile keyboardInfoFromKmxFile:path]; + if (!info) { + info = [[NSDictionary alloc] initWithObjectsAndKeys: + NSLocalizedString(@"message-error-loading-keyboard", nil), kKMKeyboardNameKey, + NSLocalizedString(@"message-error-unknown-metadata", nil), kKMKeyboardVersionKey, + NSLocalizedString(@"message-error-unknown-metadata", nil), kKMKeyboardCopyrightKey, + NSLocalizedString(@"message-error-unknown-metadata", nil), kKMVisualKeyboardKey, + nil]; + } + [_tableContents addObject:info]; } + } + else { + NSString *path = (NSString *)obj; + NSDictionary *info = [KMXFile keyboardInfoFromKmxFile:path]; + if (!info) { + info = [[NSDictionary alloc] initWithObjectsAndKeys: + NSLocalizedString(@"message-error-loading-keyboard", nil), kKMKeyboardNameKey, + NSLocalizedString(@"message-error-unknown-metadata", nil), kKMKeyboardVersionKey, + NSLocalizedString(@"message-error-unknown-metadata", nil), kKMKeyboardCopyrightKey, + NSLocalizedString(@"message-error-unknown-metadata", nil), kKMVisualKeyboardKey, + nil]; + } + [_tableContents addObject:info]; + } } - - return _tableContents; + } + + return _tableContents; } - (NSString *)kmxFilePathAtIndex:(NSUInteger)index { - return [self.AppDelegate kmxFilePathAtIndex:index]; + return [self.AppDelegate kmxFilePathAtIndex:index]; } - (NSString *)packagePathAtIndex:(NSUInteger)index { - return [self.AppDelegate packagePathAtIndex:index]; + return [self.AppDelegate packagePathAtIndex:index]; } - (NSInteger)indexForPackageFolder:(NSString *)packageFolder { - return [self.AppDelegate indexForPackageFolder:packageFolder]; + return [self.AppDelegate indexForPackageFolder:packageFolder]; } - (NSString *)packageFolderFromPath:(NSString *)path { - return [self.AppDelegate packageFolderFromPath:path]; + return [self.AppDelegate packageFolderFromPath:path]; } - (NSString *)keyboardsPath { - return self.AppDelegate.keyboardsPath; + return self.AppDelegate.keyboardsPath; } - (NSArray *)kmxFileList { - return self.AppDelegate.kmxFileList; + return self.AppDelegate.kmxFileList; } - (NSMutableArray *)activeKeyboards { - return self.AppDelegate.activeKeyboards; + return self.AppDelegate.activeKeyboards; } - (void)saveActiveKeyboards { - [self.AppDelegate saveActiveKeyboards]; + [self.AppDelegate saveActiveKeyboards]; } - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { - return self.tableContents.count; + return self.tableContents.count; } - (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes { - return 0; + return 0; } - (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row { - NSDictionary *info = [self.tableContents objectAtIndex:row]; - BOOL isHeader = ([info objectForKey:@"HeaderTitle"] != nil); - if (isHeader) { - NSTableRowView *rowView = [[NSTableRowView alloc] init]; - NSTextField *textField = [[NSTextField alloc] initWithFrame:NSMakeRect(4, 4, tableView.frame.size.width-86, tableView.rowHeight-8)]; - [textField setEditable:NO]; - [textField setBordered:NO]; - [textField setBackgroundColor:[NSColor clearColor]]; - [textField setAlignment:NSTextAlignmentLeft]; - [textField setFont:[NSFont systemFontOfSize:tableView.rowHeight*0.5]]; - [textField setTextColor:[NSColor colorWithSRGBRed:0.0 green:0.0 blue:0.1 alpha:1.0]]; - [textField setStringValue:[info objectForKey:@"HeaderTitle"]]; - [rowView addSubview:textField]; - return rowView; - } - - return nil; + NSDictionary *info = [self.tableContents objectAtIndex:row]; + BOOL isHeader = ([info objectForKey:@"HeaderTitle"] != nil); + if (isHeader) { + NSTableRowView *rowView = [[NSTableRowView alloc] init]; + NSTextField *textField = [[NSTextField alloc] initWithFrame:NSMakeRect(4, 4, tableView.frame.size.width-86, tableView.rowHeight-8)]; + [textField setEditable:NO]; + [textField setBordered:NO]; + [textField setBackgroundColor:[NSColor clearColor]]; + [textField setAlignment:NSTextAlignmentLeft]; + [textField setFont:[NSFont systemFontOfSize:tableView.rowHeight*0.5]]; + [textField setTextColor:[NSColor colorWithSRGBRed:0.0 green:0.0 blue:0.1 alpha:1.0]]; + [textField setStringValue:[info objectForKey:@"HeaderTitle"]]; + [rowView addSubview:textField]; + return rowView; + } + + return nil; } - (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row { - NSDictionary *info = [self.tableContents objectAtIndex:row]; - BOOL isHeader = ([info objectForKey:@"HeaderTitle"] != nil); - if (isHeader) - [rowView setBackgroundColor:[NSColor colorWithSRGBRed:186.0/255.0 green:211.0/255.0 blue:1.0 alpha:1.0]]; + NSDictionary *info = [self.tableContents objectAtIndex:row]; + BOOL isHeader = ([info objectForKey:@"HeaderTitle"] != nil); + if (isHeader) + [rowView setBackgroundColor:[NSColor colorWithSRGBRed:186.0/255.0 green:211.0/255.0 blue:1.0 alpha:1.0]]; } - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { - NSDictionary *info = [self.tableContents objectAtIndex:row]; - NSString *identifier = [tableColumn identifier]; - NSString *headerTitle = [info objectForKey:@"HeaderTitle"]; - BOOL isHeader = (headerTitle != nil); - BOOL isOthers = NO; - NSString *kmxFilePath = [self kmxFilePathAtIndex:row]; - if (kmxFilePath != nil) - isOthers = [[self packageFolderFromPath:kmxFilePath] isEqualToString:@"Others"]; - else if (isHeader && [headerTitle isEqualToString:@"Others"]) - isOthers = YES; - - if ([identifier isEqualToString:@"Column1"]) { - KMConfigColumn1CellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self]; - - if (isHeader) - [cellView setHidden:YES]; - else { - [cellView setHidden:NO]; - cellView.imageView.objectValue = [info objectForKey:kKMKeyboardIconKey]; - [cellView.checkBox setTag:row]; - [cellView.checkBox setAction:@selector(checkBoxAction:)]; - [cellView.checkBox setState:([self.activeKeyboards containsObject:[self kmxFilePathAtIndex:row]])?NSOnState:NSOffState]; - } - - return cellView; + NSDictionary *info = [self.tableContents objectAtIndex:row]; + NSString *identifier = [tableColumn identifier]; + NSString *headerTitle = [info objectForKey:@"HeaderTitle"]; + BOOL isHeader = (headerTitle != nil); + BOOL isOthers = NO; + NSString *kmxFilePath = [self kmxFilePathAtIndex:row]; + if (kmxFilePath != nil) + isOthers = [[self packageFolderFromPath:kmxFilePath] isEqualToString:@"Others"]; + else if (isHeader && [headerTitle isEqualToString:@"Others"]) + isOthers = YES; + + if ([identifier isEqualToString:@"Column1"]) { + KMConfigColumn1CellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self]; + + if (isHeader) + [cellView setHidden:YES]; + else { + [cellView setHidden:NO]; + cellView.imageView.objectValue = [info objectForKey:kKMKeyboardIconKey]; + [cellView.checkBox setTag:row]; + [cellView.checkBox setAction:@selector(checkBoxAction:)]; + [cellView.checkBox setState:([self.activeKeyboards containsObject:[self kmxFilePathAtIndex:row]])?NSOnState:NSOffState]; } - else if ([identifier isEqualToString:@"Column2"]) { - NSTableCellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self]; - if (!isHeader) { - [cellView setHidden:NO]; - //cellView.textField.stringValue = [NSString stringWithFormat:@"%@ (%@)", [info objectForKey:kKMKeyboardNameKey], [info objectForKey:kKMKeyboardVersionKey]]; - cellView.textField.stringValue = [info objectForKey:kKMKeyboardNameKey]; - } - else { - cellView.textField.stringValue = @""; - [cellView setHidden:YES]; - } - - return cellView; + + return cellView; + } + else if ([identifier isEqualToString:@"Column2"]) { + NSTableCellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self]; + if (!isHeader) { + [cellView setHidden:NO]; + //cellView.textField.stringValue = [NSString stringWithFormat:@"%@ (%@)", [info objectForKey:kKMKeyboardNameKey], [info objectForKey:kKMKeyboardVersionKey]]; + cellView.textField.stringValue = [info objectForKey:kKMKeyboardNameKey]; } - else if ([identifier isEqualToString:@"Column3"]) { - KMConfigColumn3CellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self]; - - if ((!isHeader && !isOthers) || (isHeader && isOthers)) { - [cellView.removeButton setHidden:YES]; - [cellView.infoButton setHidden:YES]; - [cellView.helpButton setHidden:YES]; - } - else if (isOthers) { - [cellView.removeButton setHidden:NO]; - [cellView.infoButton setHidden:YES]; - [cellView.helpButton setHidden:YES]; - } - else { - [cellView.removeButton setHidden:NO]; - - [cellView.infoButton setHidden:NO]; - [cellView.infoButton setTag:row]; - [cellView.infoButton setAction:@selector(infoAction:)]; - [cellView.infoButton setBordered:NO]; - [cellView.infoButton setWantsLayer:YES]; - CALayer *btnLayer = [cellView.infoButton layer]; - btnLayer.backgroundColor = [NSColor clearColor].CGColor; - btnLayer.cornerRadius = 9.5; - - [cellView.helpButton setHidden:NO]; - [cellView.helpButton setTag:row]; - [cellView.helpButton setAction:@selector(helpAction:)]; - [cellView.helpButton setEnabled:[self hasHelpDocumentation:row]]; - } - - if (![cellView.removeButton isHidden]) { - [cellView.removeButton setTag:row]; - [cellView.removeButton setAction:@selector(removeAction:)]; - [cellView.removeButton setBordered:NO]; - [cellView.removeButton setWantsLayer:YES]; - CALayer *btnLayer = [cellView.removeButton layer]; - btnLayer.backgroundColor = [NSColor whiteColor].CGColor; - btnLayer.cornerRadius = 9.5; - btnLayer.borderWidth = 1.0; - btnLayer.borderColor = [NSColor grayColor].CGColor; - } - - return cellView; + else { + cellView.textField.stringValue = @""; + [cellView setHidden:YES]; } - return nil; + return cellView; + } + else if ([identifier isEqualToString:@"Column3"]) { + KMConfigColumn3CellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self]; + + if ((!isHeader && !isOthers) || (isHeader && isOthers)) { + [cellView.removeButton setHidden:YES]; + [cellView.infoButton setHidden:YES]; + [cellView.helpButton setHidden:YES]; + } + else if (isOthers) { + [cellView.removeButton setHidden:NO]; + [cellView.infoButton setHidden:YES]; + [cellView.helpButton setHidden:YES]; + } + else { + [cellView.removeButton setHidden:NO]; + + [cellView.infoButton setHidden:NO]; + [cellView.infoButton setTag:row]; + [cellView.infoButton setAction:@selector(infoAction:)]; + [cellView.infoButton setBordered:NO]; + [cellView.infoButton setWantsLayer:YES]; + CALayer *btnLayer = [cellView.infoButton layer]; + btnLayer.backgroundColor = [NSColor clearColor].CGColor; + btnLayer.cornerRadius = 9.5; + + [cellView.helpButton setHidden:NO]; + [cellView.helpButton setTag:row]; + [cellView.helpButton setAction:@selector(helpAction:)]; + [cellView.helpButton setEnabled:[self hasHelpDocumentation:row]]; + } + + if (![cellView.removeButton isHidden]) { + [cellView.removeButton setTag:row]; + [cellView.removeButton setAction:@selector(removeAction:)]; + [cellView.removeButton setBordered:NO]; + [cellView.removeButton setWantsLayer:YES]; + CALayer *btnLayer = [cellView.removeButton layer]; + btnLayer.backgroundColor = [NSColor whiteColor].CGColor; + btnLayer.cornerRadius = 9.5; + btnLayer.borderWidth = 1.0; + btnLayer.borderColor = [NSColor grayColor].CGColor; + } + + return cellView; + } + + return nil; } - (NSDragOperation)tableView:(NSTableView*)tv validateDrop:(id )info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)op { - return NSDragOperationCopy; + return NSDragOperationCopy; } - (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation { - NSPasteboard *pboard = [info draggingPasteboard]; - NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType]; - NSMutableArray *kmpFiles = nil; - for (NSString *filename in filenames) { - if ([[filename lastNChars:4] isEqualTo:@".kmp"]) { - if (kmpFiles == nil) - kmpFiles = [NSMutableArray arrayWithObject:filename]; - else - [kmpFiles addObject:filename]; - } - } - - for (NSString *kmpFile in kmpFiles) { - if ([self.AppDelegate unzipFile:kmpFile]) - [self refreshAction:nil]; - else - [kmpFiles removeObject:kmpFile]; + NSPasteboard *pboard = [info draggingPasteboard]; + NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType]; + NSMutableArray *kmpFiles = nil; + for (NSString *filename in filenames) { + if ([[filename lastNChars:4] isEqualTo:@".kmp"]) { + if (kmpFiles == nil) + kmpFiles = [NSMutableArray arrayWithObject:filename]; + else + [kmpFiles addObject:filename]; } - - if (kmpFiles.count < 1) - kmpFiles = nil; - - return (kmpFiles==nil?NO:YES); + } + + for (NSString *kmpFile in kmpFiles) { + if ([self.AppDelegate unzipFile:kmpFile]) + [self refreshAction:nil]; + else + [kmpFiles removeObject:kmpFile]; + } + + if (kmpFiles.count < 1) + kmpFiles = nil; + + return (kmpFiles==nil?NO:YES); } - (void)checkBoxAction:(id)sender { - NSButton *checkBox = (NSButton *)sender; - NSString *kmxFilePath = [self kmxFilePathAtIndex:checkBox.tag]; - if (checkBox.state == NSOnState) { - if ([self.AppDelegate debugMode]) - NSLog(@"Adding active keyboard: %@", kmxFilePath); - [self.activeKeyboards addObject:kmxFilePath]; - [self saveActiveKeyboards]; - } - else if (checkBox.state == NSOffState) { - if ([self.AppDelegate debugMode]) - NSLog(@"Disabling active keyboard: %@", kmxFilePath); - [self.activeKeyboards removeObject:kmxFilePath]; - [self saveActiveKeyboards]; - } + NSButton *checkBox = (NSButton *)sender; + NSString *kmxFilePath = [self kmxFilePathAtIndex:checkBox.tag]; + if (checkBox.state == NSOnState) { + if ([self.AppDelegate debugMode]) + NSLog(@"Adding active keyboard: %@", kmxFilePath); + [self.activeKeyboards addObject:kmxFilePath]; + [self saveActiveKeyboards]; + } + else if (checkBox.state == NSOffState) { + if ([self.AppDelegate debugMode]) + NSLog(@"Disabling active keyboard: %@", kmxFilePath); + [self.activeKeyboards removeObject:kmxFilePath]; + [self saveActiveKeyboards]; + } } - (void)infoAction:(id)sender { - NSButton *infoButton = (NSButton *)sender; - NSString *packagePath = [self packagePathAtIndex:infoButton.tag]; - if (packagePath != nil) { - if (self.AppDelegate.infoWindow_.window != nil) - [self.AppDelegate.infoWindow_ close]; - - [self.window addChildWindow:self.AppDelegate.infoWindow.window ordered:NSWindowAbove]; - [self.AppDelegate.infoWindow.window centerInParent]; - [self.AppDelegate.infoWindow.window makeKeyAndOrderFront:nil]; - [self.AppDelegate.infoWindow setPackagePath:packagePath]; - } + NSButton *infoButton = (NSButton *)sender; + NSString *packagePath = [self packagePathAtIndex:infoButton.tag]; + if (packagePath != nil) { + if (self.AppDelegate.infoWindow_.window != nil) + [self.AppDelegate.infoWindow_ close]; + + [self.window addChildWindow:self.AppDelegate.infoWindow.window ordered:NSWindowAbove]; + [self.AppDelegate.infoWindow.window centerInParent]; + [self.AppDelegate.infoWindow.window makeKeyAndOrderFront:nil]; + [self.AppDelegate.infoWindow setPackagePath:packagePath]; + } } - (void)helpAction:(id)sender { - NSButton *helpButton = (NSButton *)sender; - NSString *packagePath = [self packagePathAtIndex:helpButton.tag]; - if (packagePath != nil) { - if (self.AppDelegate.kbHelpWindow_.window != nil) - [self.AppDelegate.kbHelpWindow_ close]; - - [self.window addChildWindow:self.AppDelegate.kbHelpWindow.window ordered:NSWindowAbove]; - [self.AppDelegate.kbHelpWindow.window centerInParent]; - [self.AppDelegate.kbHelpWindow.window makeKeyAndOrderFront:nil]; - [self.AppDelegate.kbHelpWindow setPackagePath:packagePath]; - } + NSButton *helpButton = (NSButton *)sender; + NSString *packagePath = [self packagePathAtIndex:helpButton.tag]; + if (packagePath != nil) { + if (self.AppDelegate.kbHelpWindow_.window != nil) + [self.AppDelegate.kbHelpWindow_ close]; + + [self.window addChildWindow:self.AppDelegate.kbHelpWindow.window ordered:NSWindowAbove]; + [self.AppDelegate.kbHelpWindow.window centerInParent]; + [self.AppDelegate.kbHelpWindow.window makeKeyAndOrderFront:nil]; + [self.AppDelegate.kbHelpWindow setPackagePath:packagePath]; + } } - (void)removeAction:(id)sender { - NSButton *removeButton = (NSButton *)sender; - NSDictionary *info = [self.tableContents objectAtIndex:removeButton.tag]; - NSString *deleteKeyboardMessage = NSLocalizedString(@"message-confirm-delete-keyboard", nil); - - if ([info objectForKey:@"HeaderTitle"] != nil) - [self.deleteAlertView setMessageText:[NSString localizedStringWithFormat:deleteKeyboardMessage, [info objectForKey:@"HeaderTitle"]]]; - else - [self.deleteAlertView setMessageText:[NSString localizedStringWithFormat:deleteKeyboardMessage, [info objectForKey:kKMKeyboardNameKey]]]; - - [self.deleteAlertView beginSheetModalForWindow:self.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:(__bridge void *)([NSNumber numberWithInteger:removeButton.tag])]; + NSButton *removeButton = (NSButton *)sender; + NSDictionary *info = [self.tableContents objectAtIndex:removeButton.tag]; + NSString *deleteKeyboardMessage = NSLocalizedString(@"message-confirm-delete-keyboard", nil); + + if ([info objectForKey:@"HeaderTitle"] != nil) + [self.deleteAlertView setMessageText:[NSString localizedStringWithFormat:deleteKeyboardMessage, [info objectForKey:@"HeaderTitle"]]]; + else + [self.deleteAlertView setMessageText:[NSString localizedStringWithFormat:deleteKeyboardMessage, [info objectForKey:kKMKeyboardNameKey]]]; + + [self.deleteAlertView beginSheetModalForWindow:self.window + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:(__bridge void *)([NSNumber numberWithInteger:removeButton.tag])]; } - (IBAction)downloadAction:(id)sender { - if (self.AppDelegate.infoWindow_.window != nil) - [self.AppDelegate.infoWindow_ close]; - - if (self.AppDelegate.kbHelpWindow_.window != nil) - [self.AppDelegate.kbHelpWindow_ close]; - - [self.window addChildWindow:self.AppDelegate.downloadKBWindow.window ordered:NSWindowAbove]; - [self.AppDelegate.downloadKBWindow.window centerInParent]; - [self.AppDelegate.downloadKBWindow.window makeKeyAndOrderFront:nil]; + if (self.AppDelegate.infoWindow_.window != nil) + [self.AppDelegate.infoWindow_ close]; + + if (self.AppDelegate.kbHelpWindow_.window != nil) + [self.AppDelegate.kbHelpWindow_ close]; + + [self.window addChildWindow:self.AppDelegate.downloadKBWindow.window ordered:NSWindowAbove]; + [self.AppDelegate.downloadKBWindow.window centerInParent]; + [self.AppDelegate.downloadKBWindow.window makeKeyAndOrderFront:nil]; } - (IBAction)alwaysShowOSKCheckBoxAction:(id)sender { - NSButton *checkBox = (NSButton *)sender; - [self.AppDelegate setAlwaysShowOSK:(checkBox.state == NSOnState)]; + NSButton *checkBox = (NSButton *)sender; + [self.AppDelegate setAlwaysShowOSK:(checkBox.state == NSOnState)]; } - (IBAction)useVerboseLoggingCheckBoxAction:(id)sender { - NSButton *checkBox = (NSButton *)sender; - BOOL verboseLoggingOn = checkBox.state == NSOnState; - [self.AppDelegate setUseVerboseLogging:verboseLoggingOn]; - [self.verboseLoggingInfo setHidden:!verboseLoggingOn]; + NSButton *checkBox = (NSButton *)sender; + BOOL verboseLoggingOn = checkBox.state == NSOnState; + [self.AppDelegate setUseVerboseLogging:verboseLoggingOn]; + [self.verboseLoggingInfo setHidden:!verboseLoggingOn]; } - (void)handleRequestToInstallPackage:(KMPackage *) package { - NSString *keyboardInfoString = NSLocalizedString(@"info-install-keyboard-filename", nil); - [self.confirmKmpInstallAlertView setInformativeText:[NSString localizedStringWithFormat:keyboardInfoString, package.getOrigKmpFilename]]; - - if ([self.AppDelegate debugMode]) { - NSLog(@"Asking user to confirm installation of %@...", package.getOrigKmpFilename); - NSLog(@"KMP - temp file name: %@", package.getTempKmpFilename); - } - - [self.confirmKmpInstallAlertView beginSheetModalForWindow:self.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:(__bridge void *)(package)]; + NSString *keyboardInfoString = NSLocalizedString(@"info-install-keyboard-filename", nil); + [self.confirmKmpInstallAlertView setInformativeText:[NSString localizedStringWithFormat:keyboardInfoString, package.getOrigKmpFilename]]; + + if ([self.AppDelegate debugMode]) { + NSLog(@"Asking user to confirm installation of %@...", package.getOrigKmpFilename); + NSLog(@"KMP - temp file name: %@", package.getTempKmpFilename); + } + + [self.confirmKmpInstallAlertView beginSheetModalForWindow:self.window + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:(__bridge void *)(package)]; } - (void)installPackageFile:(NSString *)kmpFile { - // kmpFile could be a temp file (in fact, it always is!), so don't display the name. - - if ([self.AppDelegate debugMode]) { - NSLog(@"KMP - Ready to unzip/install Package File: %@", kmpFile); - } + // kmpFile could be a temp file (in fact, it always is!), so don't display the name. + + if ([self.AppDelegate debugMode]) { + NSLog(@"KMP - Ready to unzip/install Package File: %@", kmpFile); + } + + BOOL didUnzip = [self.AppDelegate unzipFile:kmpFile]; + + if (!didUnzip) { + NSAlert *failure = [[NSAlert alloc] init]; + [failure addButtonWithTitle:NSLocalizedString(@"button-keyboard-file-unreadable", @"Alert button")]; - BOOL didUnzip = [self.AppDelegate unzipFile:kmpFile]; + NSString *errorString = NSLocalizedString(@"message-keyboard-file-unreadable", nil); + [failure setMessageText:[NSString localizedStringWithFormat:errorString, kmpFile.lastPathComponent]]; - if (!didUnzip) { - NSAlert *failure = [[NSAlert alloc] init]; - [failure addButtonWithTitle:NSLocalizedString(@"button-keyboard-file-unreadable", @"Alert button")]; - - NSString *errorString = NSLocalizedString(@"message-keyboard-file-unreadable", nil); - [failure setMessageText:[NSString localizedStringWithFormat:errorString, kmpFile.lastPathComponent]]; - - [failure setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; - [failure setAlertStyle:NSAlertStyleWarning]; - [failure beginSheetModalForWindow:self.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; - } - else if ([self.AppDelegate debugMode]) { - NSLog(@"Completed installation of KMP file."); - } + [failure setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; + [failure setAlertStyle:NSAlertStyleWarning]; + [failure beginSheetModalForWindow:self.window + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; + } + else if ([self.AppDelegate debugMode]) { + NSLog(@"Completed installation of KMP file."); + } } - (void)startTimer { - if (_reloadTimer == nil) { - TimerTarget *timerTarget = [[TimerTarget alloc] init]; - timerTarget.target = self; - _reloadTimer = [NSTimer scheduledTimerWithTimeInterval:5.0f - target:timerTarget - selector:@selector(timerAction:) - userInfo:nil - repeats:YES]; - } + if (_reloadTimer == nil) { + TimerTarget *timerTarget = [[TimerTarget alloc] init]; + timerTarget.target = self; + _reloadTimer = [NSTimer scheduledTimerWithTimeInterval:5.0f + target:timerTarget + selector:@selector(timerAction:) + userInfo:nil + repeats:YES]; + } } - (void)stopTimer { - if (_reloadTimer != nil) { - [_reloadTimer invalidate]; - _reloadTimer = nil; - } + if (_reloadTimer != nil) { + [_reloadTimer invalidate]; + _reloadTimer = nil; + } } - (void)timerAction:(NSTimer *)timer { - if ([self shouldReloadData]) { - [self.AppDelegate setKmxFileList:nil]; - [self setTableContents:nil]; - [self saveActiveKeyboards]; - [self.tableView reloadData]; - _lastReloadDate = [NSDate date]; - } + if ([self shouldReloadData]) { + [self.AppDelegate setKmxFileList:nil]; + [self setTableContents:nil]; + [self saveActiveKeyboards]; + [self.tableView reloadData]; + _lastReloadDate = [NSDate date]; + } } - (BOOL)shouldReloadData { - NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:self.keyboardsPath error:nil]; - NSDate *lastModDate = [attrs fileModificationDate]; - return ([lastModDate compare:_lastReloadDate] == NSOrderedDescending); + NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:self.keyboardsPath error:nil]; + NSDate *lastModDate = [attrs fileModificationDate]; + return ([lastModDate compare:_lastReloadDate] == NSOrderedDescending); } - (BOOL)hasHelpDocumentation:(NSUInteger)row { - NSString *packagePath = [self packagePathAtIndex:row]; - if (packagePath != nil) { - NSString *welcomeFile = [packagePath stringByAppendingPathComponent:@"welcome.htm"]; - if ([[NSFileManager defaultManager] fileExistsAtPath:welcomeFile]) - return YES; - } - - return NO; + NSString *packagePath = [self packagePathAtIndex:row]; + if (packagePath != nil) { + NSString *welcomeFile = [packagePath stringByAppendingPathComponent:@"welcome.htm"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:welcomeFile]) + return YES; + } + + return NO; } - (NSAlert *)deleteAlertView { - if (_deleteAlertView == nil) { - _deleteAlertView = [[NSAlert alloc] init]; - [_deleteAlertView setInformativeText:NSLocalizedString(@"info-cannot-undo-delete-keyboard", nil)]; - [_deleteAlertView addButtonWithTitle:NSLocalizedString(@"button-delete-keyboard", nil)]; - [_deleteAlertView addButtonWithTitle:NSLocalizedString(@"button-cancel-delete-keyboard", nil)]; - [_deleteAlertView setAlertStyle:NSAlertStyleWarning]; - [_deleteAlertView setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; - } - - return _deleteAlertView; + if (_deleteAlertView == nil) { + _deleteAlertView = [[NSAlert alloc] init]; + [_deleteAlertView setInformativeText:NSLocalizedString(@"info-cannot-undo-delete-keyboard", nil)]; + [_deleteAlertView addButtonWithTitle:NSLocalizedString(@"button-delete-keyboard", nil)]; + [_deleteAlertView addButtonWithTitle:NSLocalizedString(@"button-cancel-delete-keyboard", nil)]; + [_deleteAlertView setAlertStyle:NSAlertStyleWarning]; + [_deleteAlertView setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; + } + + return _deleteAlertView; } - (NSAlert *)confirmKmpInstallAlertView { - if (_confirmKmpInstallAlertView == nil) { - _confirmKmpInstallAlertView = [[NSAlert alloc] init]; - [_confirmKmpInstallAlertView addButtonWithTitle:NSLocalizedString(@"button-install-keyboard", nil)]; - [_confirmKmpInstallAlertView addButtonWithTitle:NSLocalizedString(@"button-cancel-install-keyboard", nil)]; - [_confirmKmpInstallAlertView setMessageText:NSLocalizedString(@"message-confirm-install-keyboard", nil)]; - [_confirmKmpInstallAlertView setAlertStyle:NSAlertStyleInformational]; - [_confirmKmpInstallAlertView setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; - } - - return _confirmKmpInstallAlertView; + if (_confirmKmpInstallAlertView == nil) { + _confirmKmpInstallAlertView = [[NSAlert alloc] init]; + [_confirmKmpInstallAlertView addButtonWithTitle:NSLocalizedString(@"button-install-keyboard", nil)]; + [_confirmKmpInstallAlertView addButtonWithTitle:NSLocalizedString(@"button-cancel-install-keyboard", nil)]; + [_confirmKmpInstallAlertView setMessageText:NSLocalizedString(@"message-confirm-install-keyboard", nil)]; + [_confirmKmpInstallAlertView setAlertStyle:NSAlertStyleInformational]; + [_confirmKmpInstallAlertView setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; + } + + return _confirmKmpInstallAlertView; } - (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { - if ([self.AppDelegate debugMode]) { - NSLog(@"User responded to NSAlert"); + if ([self.AppDelegate debugMode]) { + NSLog(@"User responded to NSAlert"); + } + if (alert == _deleteAlertView) { + if (returnCode == NSAlertFirstButtonReturn) { // Delete + [self deleteFileAtIndex:(__bridge NSNumber *)contextInfo]; } - if (alert == _deleteAlertView) { - if (returnCode == NSAlertFirstButtonReturn) { // Delete - [self deleteFileAtIndex:(__bridge NSNumber *)contextInfo]; - } - - _deleteAlertView = nil; + + _deleteAlertView = nil; + } + else if (alert == _confirmKmpInstallAlertView) { + KMPackage *package = (__bridge KMPackage *)contextInfo; + if ([self.AppDelegate debugMode]) { + NSLog(@"KMP - Temp file: %@", package.getTempKmpFilename); } - else if (alert == _confirmKmpInstallAlertView) { - KMPackage *package = (__bridge KMPackage *)contextInfo; - if ([self.AppDelegate debugMode]) { - NSLog(@"KMP - Temp file: %@", package.getTempKmpFilename); - } - if (returnCode == NSAlertFirstButtonReturn) { // Install - [self installPackageFile: package.getTempKmpFilename]; - } - - [package releaseTempKMPFile]; - _confirmKmpInstallAlertView = nil; + if (returnCode == NSAlertFirstButtonReturn) { // Install + [self installPackageFile: package.getTempKmpFilename]; } - // else, just a message - nothing to do. + + [package releaseTempKMPFile]; + _confirmKmpInstallAlertView = nil; + } + // else, just a message - nothing to do. } - (void)deleteFileAtIndex:(NSNumber *) n { - NSInteger index = [n integerValue]; - NSString *path2Remove = nil; - NSString *kmxFilePath = [self kmxFilePathAtIndex:index]; - if (kmxFilePath == nil) { - kmxFilePath = [self kmxFilePathAtIndex:index+1]; - path2Remove = [[self keyboardsPath] stringByAppendingPathComponent:[self packageFolderFromPath:kmxFilePath]]; - } - else { - path2Remove = kmxFilePath; - } - - NSError *error; - [[NSFileManager defaultManager] removeItemAtPath:path2Remove error:&error]; - if (error == nil) { - [self performSelector:@selector(timerAction:) withObject:nil afterDelay:1.0]; - } + NSInteger index = [n integerValue]; + NSString *path2Remove = nil; + NSString *kmxFilePath = [self kmxFilePathAtIndex:index]; + if (kmxFilePath == nil) { + kmxFilePath = [self kmxFilePathAtIndex:index+1]; + path2Remove = [[self keyboardsPath] stringByAppendingPathComponent:[self packageFolderFromPath:kmxFilePath]]; + } + else { + path2Remove = kmxFilePath; + } + + NSError *error; + [[NSFileManager defaultManager] removeItemAtPath:path2Remove error:&error]; + if (error == nil) { + [self performSelector:@selector(timerAction:) withObject:nil afterDelay:1.0]; + } } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m index a0b7859ed02..e7b42138f54 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMDownloadKeyboard/KMDownloadKBWindowController.m @@ -16,91 +16,91 @@ @interface KMDownloadKBWindowController () @implementation KMDownloadKBWindowController - (KMInputMethodAppDelegate *)AppDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; + return (KMInputMethodAppDelegate *)[NSApp delegate]; } - (void)windowDidLoad { - [super windowDidLoad]; - - [self.webView setFrameLoadDelegate:(id)self]; - [self.webView setGroupName:@"KMDownloadKB"]; - [self.webView setPolicyDelegate:(id)self]; - - NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; - KeymanVersionInfo keymanVersionInfo = [[self AppDelegate] versionInfo]; - NSString *url = [NSString stringWithFormat:@"https://%@/go/macos/14.0/download-keyboards/?version=%@", keymanVersionInfo.keymanCom, version]; - if (self.AppDelegate.debugMode) - NSLog(@"KMDownloadKBWindowController opening url = %@, version = '%@'", url, version); - [self.webView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]]; + [super windowDidLoad]; + + [self.webView setFrameLoadDelegate:(id)self]; + [self.webView setGroupName:@"KMDownloadKB"]; + [self.webView setPolicyDelegate:(id)self]; + + NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; + KeymanVersionInfo keymanVersionInfo = [[self AppDelegate] versionInfo]; + NSString *url = [NSString stringWithFormat:@"https://%@/go/macos/14.0/download-keyboards/?version=%@", keymanVersionInfo.keymanCom, version]; + if (self.AppDelegate.debugMode) + NSLog(@"KMDownloadKBWindowController opening url = %@, version = '%@'", url, version); + [self.webView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]]; } - (void)webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id)listener { - [[NSWorkspace sharedWorkspace] openURL:[actionInformation objectForKey:WebActionOriginalURLKey]]; - [listener ignore]; + [[NSWorkspace sharedWorkspace] openURL:[actionInformation objectForKey:WebActionOriginalURLKey]]; + [listener ignore]; } - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { - NSString* url = [[request URL] absoluteString]; + NSString* url = [[request URL] absoluteString]; + if (self.AppDelegate.debugMode) + NSLog(@"decidePolicyForNavigationAction, navigating to %@", url); + + // The pattern for matching links matches work in #3602 + NSString* urlPathMatchKeyboardsInstall = @"^http(?:s)?://keyman(?:-staging)?\\.com(?:\\.local)?/keyboards/install/([^?/]+)(?:\\?(.+))?$"; + // e.g. https://keyman.com/keyboards/install/foo + NSString* urlPathMatchKeyboardsRoot = @"^http(?:s)?://keyman(?:-staging)?\\.com(?:\\.local)?/keyboards([/?].*)?$"; + // http://keyman.com.local/keyboards/foo + NSString* urlPathMatchKeyboardsGo = @"^http(?:s)?://keyman(?:-staging)?\\.com(?:\\.local)?/go/macos/[^/]+/download-keyboards"; + // https://keyman-staging.com/go/macos/14.0/download-keyboards?version=14.0.146.0 + NSRange range = NSMakeRange(0, url.length); + + NSError* error; + NSRegularExpression* regexInstall = [NSRegularExpression regularExpressionWithPattern: urlPathMatchKeyboardsInstall options: 0 error: &error]; + NSRegularExpression* regexRoot = [NSRegularExpression regularExpressionWithPattern: urlPathMatchKeyboardsRoot options: 0 error: &error]; + NSRegularExpression* regexGo = [NSRegularExpression regularExpressionWithPattern: urlPathMatchKeyboardsGo options: 0 error: &error]; + + NSArray* matchesInstall = [regexInstall matchesInString:url options:0 range:range]; + + if(matchesInstall.count > 0) { if (self.AppDelegate.debugMode) - NSLog(@"decidePolicyForNavigationAction, navigating to %@", url); - - // The pattern for matching links matches work in #3602 - NSString* urlPathMatchKeyboardsInstall = @"^http(?:s)?://keyman(?:-staging)?\\.com(?:\\.local)?/keyboards/install/([^?/]+)(?:\\?(.+))?$"; - // e.g. https://keyman.com/keyboards/install/foo - NSString* urlPathMatchKeyboardsRoot = @"^http(?:s)?://keyman(?:-staging)?\\.com(?:\\.local)?/keyboards([/?].*)?$"; - // http://keyman.com.local/keyboards/foo - NSString* urlPathMatchKeyboardsGo = @"^http(?:s)?://keyman(?:-staging)?\\.com(?:\\.local)?/go/macos/[^/]+/download-keyboards"; - // https://keyman-staging.com/go/macos/14.0/download-keyboards?version=14.0.146.0 - NSRange range = NSMakeRange(0, url.length); - - NSError* error; - NSRegularExpression* regexInstall = [NSRegularExpression regularExpressionWithPattern: urlPathMatchKeyboardsInstall options: 0 error: &error]; - NSRegularExpression* regexRoot = [NSRegularExpression regularExpressionWithPattern: urlPathMatchKeyboardsRoot options: 0 error: &error]; - NSRegularExpression* regexGo = [NSRegularExpression regularExpressionWithPattern: urlPathMatchKeyboardsGo options: 0 error: &error]; - - NSArray* matchesInstall = [regexInstall matchesInString:url options:0 range:range]; - - if(matchesInstall.count > 0) { - if (self.AppDelegate.debugMode) - NSLog(@"Farming out download to app delegate."); - [listener ignore]; - NSTextCheckingResult* match = (NSTextCheckingResult*) matchesInstall[0]; - NSString* matchKeyboardId = [url substringWithRange:[match rangeAtIndex:1]]; - // Install keyboard link - [self.AppDelegate downloadKeyboardFromKeyboardId:matchKeyboardId]; - //[self.AppDelegate processURL:url]; - } - else if([regexRoot numberOfMatchesInString:url options:0 range:range] > 0 || - [regexGo numberOfMatchesInString:url options:0 range:range] > 0) { - // allow https://keyman.com/keyboards* to go through - // allow https://keyman.com/go/macos/download-keyboards to go through - if (self.AppDelegate.debugMode) - NSLog(@"Accepting link in this browser."); - [listener use]; - } - else if([url startsWith:@"keyman:"]) { - if ([url startsWith:@"keyman:link?url="]) - { - if (self.AppDelegate.debugMode) - NSLog(@"Opening keyman:link URL in default browser: %@", url); - [listener ignore]; - url = [request.URL.absoluteString substringFromIndex:[@"keyman:link?url=" length]]; - [[NSWorkspace sharedWorkspace] openURL: [[NSURL alloc] initWithString:url]]; - } - else { - if (self.AppDelegate.debugMode) - NSLog(@"Farming out download to app delegate."); - [listener ignore]; - [self.AppDelegate processURL:url]; - } - } - else + NSLog(@"Farming out download to app delegate."); + [listener ignore]; + NSTextCheckingResult* match = (NSTextCheckingResult*) matchesInstall[0]; + NSString* matchKeyboardId = [url substringWithRange:[match rangeAtIndex:1]]; + // Install keyboard link + [self.AppDelegate downloadKeyboardFromKeyboardId:matchKeyboardId]; + //[self.AppDelegate processURL:url]; + } + else if([regexRoot numberOfMatchesInString:url options:0 range:range] > 0 || + [regexGo numberOfMatchesInString:url options:0 range:range] > 0) { + // allow https://keyman.com/keyboards* to go through + // allow https://keyman.com/go/macos/download-keyboards to go through + if (self.AppDelegate.debugMode) + NSLog(@"Accepting link in this browser."); + [listener use]; + } + else if([url startsWith:@"keyman:"]) { + if ([url startsWith:@"keyman:link?url="]) { - // Open in external browser - if (self.AppDelegate.debugMode) - NSLog(@"Opening URL in default browser: %@", url); - [listener ignore]; - [[NSWorkspace sharedWorkspace] openURL: [[NSURL alloc] initWithString:url]]; + if (self.AppDelegate.debugMode) + NSLog(@"Opening keyman:link URL in default browser: %@", url); + [listener ignore]; + url = [request.URL.absoluteString substringFromIndex:[@"keyman:link?url=" length]]; + [[NSWorkspace sharedWorkspace] openURL: [[NSURL alloc] initWithString:url]]; } + else { + if (self.AppDelegate.debugMode) + NSLog(@"Farming out download to app delegate."); + [listener ignore]; + [self.AppDelegate processURL:url]; + } + } + else + { + // Open in external browser + if (self.AppDelegate.debugMode) + NSLog(@"Opening URL in default browser: %@", url); + [listener ignore]; + [[NSWorkspace sharedWorkspace] openURL: [[NSURL alloc] initWithString:url]]; + } } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m index fc5d602ad8e..a37d66148bd 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m @@ -24,205 +24,205 @@ @interface KMInfoWindowController () @implementation KMInfoWindowController - (KMInputMethodAppDelegate *)AppDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; + return (KMInputMethodAppDelegate *)[NSApp delegate]; } - (void)windowDidLoad { - [super windowDidLoad]; + [super windowDidLoad]; - [self.tabView setDelegate:self]; - [self.detailsView setFrameLoadDelegate:(id)self]; - [self.detailsView setPolicyDelegate:(id)self]; - [self.readmeView setFrameLoadDelegate:(id)self]; - [self.readmeView setPolicyDelegate:(id)self]; + [self.tabView setDelegate:self]; + [self.detailsView setFrameLoadDelegate:(id)self]; + [self.detailsView setPolicyDelegate:(id)self]; + [self.readmeView setFrameLoadDelegate:(id)self]; + [self.readmeView setPolicyDelegate:(id)self]; } // TODO: rename, refactor, reset PackageInfo directly rather than making getter do it? - (void)setPackagePath:(NSString *)packagePath { - _packagePath = packagePath; - _packageInfo = nil; - [self.tabView selectTabViewItemAtIndex:0]; - if (packagePath != nil && packagePath.length) { - NSString *imgName = self.packageInfo.graphicFilename; - if (imgName != nil) { - NSString *imgFile = [packagePath stringByAppendingPathComponent:imgName]; - NSImage *img = [[NSImage alloc] initWithContentsOfFile:imgFile]; - [self.imageView setImage:img]; - } - else { - [self.imageView setImage:[NSImage imageNamed:@"SideImage.bmp"]]; - } - - NSString *detailsHtml = [self detailsHtml]; - if (detailsHtml != nil) - [self.detailsView.mainFrame loadHTMLString:detailsHtml baseURL:[[NSBundle mainBundle] resourceURL]]; - else - [self.detailsView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]]; - - NSString *readmeFilename = self.packageInfo.readmeFilename; - if (readmeFilename != nil) { - [self.readmeView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[packagePath stringByAppendingPathComponent:readmeFilename]]]]; - if (_readMeTab != nil && ![self.tabView.tabViewItems containsObject:_readMeTab]) { - [self.tabView addTabViewItem:_readMeTab]; - _readMeTab = nil; - } - } - else { - [self.readmeView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]]; - if ([self.tabView.tabViewItems count] > 1) { - _readMeTab = [self.tabView tabViewItemAtIndex:1]; - [self.tabView removeTabViewItem:_readMeTab]; - } - } + _packagePath = packagePath; + _packageInfo = nil; + [self.tabView selectTabViewItemAtIndex:0]; + if (packagePath != nil && packagePath.length) { + NSString *imgName = self.packageInfo.graphicFilename; + if (imgName != nil) { + NSString *imgFile = [packagePath stringByAppendingPathComponent:imgName]; + NSImage *img = [[NSImage alloc] initWithContentsOfFile:imgFile]; + [self.imageView setImage:img]; } + else { + [self.imageView setImage:[NSImage imageNamed:@"SideImage.bmp"]]; + } + + NSString *detailsHtml = [self detailsHtml]; + if (detailsHtml != nil) + [self.detailsView.mainFrame loadHTMLString:detailsHtml baseURL:[[NSBundle mainBundle] resourceURL]]; + else + [self.detailsView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]]; + + NSString *readmeFilename = self.packageInfo.readmeFilename; + if (readmeFilename != nil) { + [self.readmeView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[packagePath stringByAppendingPathComponent:readmeFilename]]]]; + if (_readMeTab != nil && ![self.tabView.tabViewItems containsObject:_readMeTab]) { + [self.tabView addTabViewItem:_readMeTab]; + _readMeTab = nil; + } + } + else { + [self.readmeView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]]; + if ([self.tabView.tabViewItems count] > 1) { + _readMeTab = [self.tabView tabViewItemAtIndex:1]; + [self.tabView removeTabViewItem:_readMeTab]; + } + } + } } - (BOOL)tabView:(NSTabView *)tabView shouldSelectTabViewItem:(NSTabViewItem *)tabViewItem { - return YES; + return YES; } // TODO: refactor: any reason for this to be HTML? hard to read stringWithFormat applied to template with 16 arguments - (NSString *)detailsHtml { NSString *errorString = NSLocalizedString(@"message-keyboard-file-unreadable", nil); - - @try { - NSString *htmlFormat = - @"" - "" - "" - "Keyman" - "" - "" - "" - "" - "

%@

" - "
" - "
" - "
" - "" - "
Scan this code to load this keyboard on another device or " - "share online
" - "
" - "

%@


" - "%@" - "
" - "

%@


" - "%@" - "
" - "

%@

%@


" - "

%@

%@


" - "

%@

%@


" - "

%@

%@

" - "
" - "" - ""; - - NSString *pBodyFormat = @"

%@


"; - NSMutableString *keyboardString = [NSMutableString stringWithString:@""]; - - if (self.packageInfo.keyboards.count) { - for (KMKeyboardInfo *keyboard in self.packageInfo.keyboards) { - [keyboardString appendString:[NSString stringWithFormat:pBodyFormat, keyboard.name]]; - } - } else { - keyboardString = [NSMutableString stringWithString:@"


"]; - } - - NSArray *fonts = self.packageInfo.fonts; - NSMutableString *fontsStr = [NSMutableString stringWithString:@""]; - - if (fonts != nil && fonts.count) { - for (NSString *font in fonts) { - [fontsStr appendString:[NSString stringWithFormat:pBodyFormat, font]]; - } - } - else { - fontsStr = [NSMutableString stringWithString:@"


"]; - } - - NSString *linkFormat = @"%@"; - NSString *packageId = [self.packagePath lastPathComponent]; - - KeymanVersionInfo keymanVersionInfo = [[self AppDelegate] versionInfo]; - NSString *shareUrl = [NSString stringWithFormat:@"https://%@/go/keyboard/%@/share", keymanVersionInfo.keymanCom, packageId]; - - NSString *name = self.packageInfo.packageName; - if (name == nil) - name = @"Unknown Keyboard Package"; - - NSString *version = self.packageInfo.packageVersion; - if (version == nil) - version = @""; - - NSString *authorV1 = self.packageInfo.authorName; - NSString *authorV2 = self.packageInfo.authorUrl; - NSString *author = @""; - if (authorV1.length && authorV2.length) - author = [NSString stringWithFormat:linkFormat, authorV2, authorV1]; - else if (authorV1.length) - author = authorV1; - else if (authorV2.length) - author = [NSString stringWithFormat:linkFormat, authorV2, authorV2]; - - NSString *website = @""; - if (self.packageInfo.website.length) - website = [NSString stringWithFormat:linkFormat, self.packageInfo.website, self.packageInfo.website]; - - NSString *copyright = @""; - if (self.packageInfo.copyright.length) - copyright = self.packageInfo.copyright; - - // get localized label strings - NSString *keyboardsLabel = NSLocalizedString(@"keyboards-label", nil); - NSString *fontsLabel = NSLocalizedString(@"fonts-label", nil); - NSString *packageVersionLabel = NSLocalizedString(@"package-version-label", nil); - NSString *authorLabel = NSLocalizedString(@"author-label", nil); - NSString *websiteLabel = NSLocalizedString(@"website-label", nil); - NSString *copyrightLabel = NSLocalizedString(@"copyright-label", nil); - - - NSString *htmlStr = [NSString stringWithFormat:htmlFormat, name, shareUrl, shareUrl, - keyboardsLabel, keyboardString, fontsLabel, fontsStr, - packageVersionLabel, version, authorLabel, author, - websiteLabel, website, copyrightLabel, copyright]; - - return htmlStr; + + @try { + NSString *htmlFormat = + @"" + "" + "" + "Keyman" + "" + "" + "" + "" + "

%@

" + "
" + "
" + "
" + "" + "
Scan this code to load this keyboard on another device or " + "share online
" + "
" + "

%@


" + "%@" + "
" + "

%@


" + "%@" + "
" + "

%@

%@


" + "

%@

%@


" + "

%@

%@


" + "

%@

%@

" + "
" + "" + ""; + + NSString *pBodyFormat = @"

%@


"; + NSMutableString *keyboardString = [NSMutableString stringWithString:@""]; + + if (self.packageInfo.keyboards.count) { + for (KMKeyboardInfo *keyboard in self.packageInfo.keyboards) { + [keyboardString appendString:[NSString stringWithFormat:pBodyFormat, keyboard.name]]; + } + } else { + keyboardString = [NSMutableString stringWithString:@"


"]; + } + + NSArray *fonts = self.packageInfo.fonts; + NSMutableString *fontsStr = [NSMutableString stringWithString:@""]; + + if (fonts != nil && fonts.count) { + for (NSString *font in fonts) { + [fontsStr appendString:[NSString stringWithFormat:pBodyFormat, font]]; + } } - @catch (NSException *e) { - NSLog(@"Error = %@", e.description); - return nil; + else { + fontsStr = [NSMutableString stringWithString:@"


"]; } + + NSString *linkFormat = @"%@"; + NSString *packageId = [self.packagePath lastPathComponent]; + + KeymanVersionInfo keymanVersionInfo = [[self AppDelegate] versionInfo]; + NSString *shareUrl = [NSString stringWithFormat:@"https://%@/go/keyboard/%@/share", keymanVersionInfo.keymanCom, packageId]; + + NSString *name = self.packageInfo.packageName; + if (name == nil) + name = @"Unknown Keyboard Package"; + + NSString *version = self.packageInfo.packageVersion; + if (version == nil) + version = @""; + + NSString *authorV1 = self.packageInfo.authorName; + NSString *authorV2 = self.packageInfo.authorUrl; + NSString *author = @""; + if (authorV1.length && authorV2.length) + author = [NSString stringWithFormat:linkFormat, authorV2, authorV1]; + else if (authorV1.length) + author = authorV1; + else if (authorV2.length) + author = [NSString stringWithFormat:linkFormat, authorV2, authorV2]; + + NSString *website = @""; + if (self.packageInfo.website.length) + website = [NSString stringWithFormat:linkFormat, self.packageInfo.website, self.packageInfo.website]; + + NSString *copyright = @""; + if (self.packageInfo.copyright.length) + copyright = self.packageInfo.copyright; + + // get localized label strings + NSString *keyboardsLabel = NSLocalizedString(@"keyboards-label", nil); + NSString *fontsLabel = NSLocalizedString(@"fonts-label", nil); + NSString *packageVersionLabel = NSLocalizedString(@"package-version-label", nil); + NSString *authorLabel = NSLocalizedString(@"author-label", nil); + NSString *websiteLabel = NSLocalizedString(@"website-label", nil); + NSString *copyrightLabel = NSLocalizedString(@"copyright-label", nil); + + + NSString *htmlStr = [NSString stringWithFormat:htmlFormat, name, shareUrl, shareUrl, + keyboardsLabel, keyboardString, fontsLabel, fontsStr, + packageVersionLabel, version, authorLabel, author, + websiteLabel, website, copyrightLabel, copyright]; + + return htmlStr; + } + @catch (NSException *e) { + NSLog(@"Error = %@", e.description); + return nil; + } } - (KMPackageInfo *)packageInfo { - if(_packageInfo == nil) { - _packageInfo = [self.AppDelegate loadPackageInfo:self.packagePath]; - } - - return _packageInfo; + if(_packageInfo == nil) { + _packageInfo = [self.AppDelegate loadPackageInfo:self.packagePath]; + } + + return _packageInfo; } - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { - NSNumber *navType = [actionInformation objectForKey:WebActionNavigationTypeKey]; - if (navType.integerValue == WebNavigationTypeLinkClicked && ![request.URL isFileURL]) { - NSString *urlStr = [[request URL] absoluteString]; - if ([urlStr startsWith:@"link:"]) - urlStr = [urlStr substringFromIndex:5]; - - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlStr]]; - } - else - [listener use]; + NSNumber *navType = [actionInformation objectForKey:WebActionNavigationTypeKey]; + if (navType.integerValue == WebNavigationTypeLinkClicked && ![request.URL isFileURL]) { + NSString *urlStr = [[request URL] absoluteString]; + if ([urlStr startsWith:@"link:"]) + urlStr = [urlStr substringFromIndex:5]; + + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlStr]]; + } + else + [listener use]; } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputController.m index 8ba6966dab2..7c65bd97490 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputController.m @@ -17,174 +17,174 @@ @implementation KMInputController NSMutableArray *servers; - (KMInputMethodAppDelegate *)AppDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; + return (KMInputMethodAppDelegate *)[NSApp delegate]; } - (id)initWithServer:(IMKServer *)server delegate:(id)delegate client:(id)inputClient { - if ([self.AppDelegate debugMode]) { - NSLog(@"Initializing Keyman Input Method with server: %@", server); - } - - self = [super initWithServer:server delegate:delegate client:inputClient]; - if (self) { - servers = [[NSMutableArray alloc] initWithCapacity:2]; - self.AppDelegate.inputController = self; - if (self.AppDelegate.kvk != nil && self.AppDelegate.alwaysShowOSK) { - [self.AppDelegate showOSK]; - } + if ([self.AppDelegate debugMode]) { + NSLog(@"Initializing Keyman Input Method with server: %@", server); + } + + self = [super initWithServer:server delegate:delegate client:inputClient]; + if (self) { + servers = [[NSMutableArray alloc] initWithCapacity:2]; + self.AppDelegate.inputController = self; + if (self.AppDelegate.kvk != nil && self.AppDelegate.alwaysShowOSK) { + [self.AppDelegate showOSK]; } - - return self; + } + + return self; } - (NSUInteger)recognizedEvents:(id)sender { - return NSEventMaskKeyDown | NSEventMaskFlagsChanged; + return NSEventMaskKeyDown | NSEventMaskFlagsChanged; } - (BOOL)handleEvent:(NSEvent *)event client:(id)sender { + if ([self.AppDelegate debugMode]) + NSLog(@"handleEvent: event = %@", event); + + if (event == nil || sender == nil || self.kmx == nil || _eventHandler == nil) { if ([self.AppDelegate debugMode]) - NSLog(@"handleEvent: event = %@", event); - - if (event == nil || sender == nil || self.kmx == nil || _eventHandler == nil) { - if ([self.AppDelegate debugMode]) - NSLog(@"handleEvent: not handling event"); - return NO; // Not sure this can ever happen. - } - - return [_eventHandler handleEvent:event client:sender]; + NSLog(@"handleEvent: not handling event"); + return NO; // Not sure this can ever happen. + } + + return [_eventHandler handleEvent:event client:sender]; } // Passthrough from the app delegate low level event hook // to the input method event handler for handleBackspace. - (void)handleBackspace:(NSEvent *)event { - [self.AppDelegate logDebugMessage:@"KMInputController handleBackspace, event = %@", event]; - if(_eventHandler != nil) { - [_eventHandler handleBackspace:event]; - } + [self.AppDelegate logDebugMessage:@"KMInputController handleBackspace, event = %@", event]; + if(_eventHandler != nil) { + [_eventHandler handleBackspace:event]; + } } - (void)activateServer:(id)sender { - @synchronized(servers) { - [sender overrideKeyboardWithKeyboardNamed:@"com.apple.keylayout.US"]; - - [self.AppDelegate wakeUpWith:sender]; - [servers addObject:sender]; - - if (_eventHandler != nil) { - [_eventHandler deactivate]; - } - - NSRunningApplication *currApp = [[NSWorkspace sharedWorkspace] frontmostApplication]; - NSString *clientAppId = [currApp bundleIdentifier]; - if ([self.AppDelegate debugMode]) { - NSLog(@"activateServer, new active app: '%@', sender %@", clientAppId, sender); - } - - _eventHandler = [[KMInputMethodEventHandler alloc] initWithClient:clientAppId client:sender]; - + @synchronized(servers) { + [sender overrideKeyboardWithKeyboardNamed:@"com.apple.keylayout.US"]; + + [self.AppDelegate wakeUpWith:sender]; + [servers addObject:sender]; + + if (_eventHandler != nil) { + [_eventHandler deactivate]; } + + NSRunningApplication *currApp = [[NSWorkspace sharedWorkspace] frontmostApplication]; + NSString *clientAppId = [currApp bundleIdentifier]; + if ([self.AppDelegate debugMode]) { + NSLog(@"activateServer, new active app: '%@', sender %@", clientAppId, sender); + } + + _eventHandler = [[KMInputMethodEventHandler alloc] initWithClient:clientAppId client:sender]; + + } } - (void)deactivateServer:(id)sender { - if ([self.AppDelegate debugMode]) { - NSLog(@"*** deactivateServer ***"); - NSLog(@"sender: %@", sender); - NSLog(@"***"); + if ([self.AppDelegate debugMode]) { + NSLog(@"*** deactivateServer ***"); + NSLog(@"sender: %@", sender); + NSLog(@"***"); + } + @synchronized(servers) { + for (int i = 0; i < servers.count; i++) { + if (servers[i] == sender) { + [servers removeObjectAtIndex:i]; + break; + } } - @synchronized(servers) { - for (int i = 0; i < servers.count; i++) { - if (servers[i] == sender) { - [servers removeObjectAtIndex:i]; - break; - } - } - if (servers.count == 0) { - if ([self.AppDelegate debugMode]) { - NSLog(@"No known active server for Keyman IM. Starting countdown to sleep..."); - } - [self performSelector:@selector(timerAction:) withObject:sender afterDelay:0.7]; - } + if (servers.count == 0) { + if ([self.AppDelegate debugMode]) { + NSLog(@"No known active server for Keyman IM. Starting countdown to sleep..."); + } + [self performSelector:@selector(timerAction:) withObject:sender afterDelay:0.7]; } + } } - (void)timerAction:(id)lastServer { - @synchronized(servers) { - if (servers.count == 0) { - if (_eventHandler != nil) { - [_eventHandler deactivate]; - _eventHandler = nil; - } - [self.AppDelegate sleepFollowingDeactivationOfServer:lastServer]; - } + @synchronized(servers) { + if (servers.count == 0) { + if (_eventHandler != nil) { + [_eventHandler deactivate]; + _eventHandler = nil; + } + [self.AppDelegate sleepFollowingDeactivationOfServer:lastServer]; } + } } /* -- (NSDictionary *)modes:(id)sender { - if ([self.AppDelegate debugMode]) - NSLog(@"*** Modes ***"); - if (_kmModes == nil) { - NSDictionary *amhMode = [[NSDictionary alloc] initWithObjectsAndKeys:@"keyman.png", kTSInputModeAlternateMenuIconFileKey, - [NSNumber numberWithBool:YES], kTSInputModeDefaultStateKey, - [NSNumber numberWithBool:YES], kTSInputModeIsVisibleKey, - @"A", kTSInputModeKeyEquivalentKey, - [NSNumber numberWithInteger:4608], kTSInputModeKeyEquivalentModifiersKey, - [NSNumber numberWithBool:YES], kTSInputModeDefaultStateKey, - @"keyman.png", kTSInputModeMenuIconFileKey, - @"keyman.png", kTSInputModePaletteIconFileKey, - [NSNumber numberWithBool:YES], kTSInputModePrimaryInScriptKey, - @"smUnicodeScript", kTSInputModeScriptKey, - @"amh", @"TISIntendedLanguage", nil]; - - NSDictionary *hinMode = [[NSDictionary alloc] initWithObjectsAndKeys:@"keyman.png", kTSInputModeAlternateMenuIconFileKey, - [NSNumber numberWithBool:YES], kTSInputModeDefaultStateKey, - [NSNumber numberWithBool:YES], kTSInputModeIsVisibleKey, - @"H", kTSInputModeKeyEquivalentKey, - [NSNumber numberWithInteger:4608], kTSInputModeKeyEquivalentModifiersKey, - [NSNumber numberWithBool:YES], kTSInputModeDefaultStateKey, - @"keyman.png", kTSInputModeMenuIconFileKey, - @"keyman.png", kTSInputModePaletteIconFileKey, - [NSNumber numberWithBool:YES], kTSInputModePrimaryInScriptKey, - @"smUnicodeScript", kTSInputModeScriptKey, - @"hin", @"TISIntendedLanguage", nil]; - - NSDictionary *modeList = [[NSDictionary alloc] initWithObjectsAndKeys:amhMode, @"com.apple.inputmethod.amh", hinMode, @"com.apple.inputmethod.hin", nil]; - NSArray *modeOrder = [[NSArray alloc] initWithObjects:@"com.apple.inputmethod.amh", @"com.apple.inputmethod.hin", nil]; - _kmModes = [[NSDictionary alloc] initWithObjectsAndKeys:modeList, kTSInputModeListKey, - modeOrder, kTSVisibleInputModeOrderedArrayKey, nil]; - } - - return _kmModes; -} -*/ + - (NSDictionary *)modes:(id)sender { + if ([self.AppDelegate debugMode]) + NSLog(@"*** Modes ***"); + if (_kmModes == nil) { + NSDictionary *amhMode = [[NSDictionary alloc] initWithObjectsAndKeys:@"keyman.png", kTSInputModeAlternateMenuIconFileKey, + [NSNumber numberWithBool:YES], kTSInputModeDefaultStateKey, + [NSNumber numberWithBool:YES], kTSInputModeIsVisibleKey, + @"A", kTSInputModeKeyEquivalentKey, + [NSNumber numberWithInteger:4608], kTSInputModeKeyEquivalentModifiersKey, + [NSNumber numberWithBool:YES], kTSInputModeDefaultStateKey, + @"keyman.png", kTSInputModeMenuIconFileKey, + @"keyman.png", kTSInputModePaletteIconFileKey, + [NSNumber numberWithBool:YES], kTSInputModePrimaryInScriptKey, + @"smUnicodeScript", kTSInputModeScriptKey, + @"amh", @"TISIntendedLanguage", nil]; + + NSDictionary *hinMode = [[NSDictionary alloc] initWithObjectsAndKeys:@"keyman.png", kTSInputModeAlternateMenuIconFileKey, + [NSNumber numberWithBool:YES], kTSInputModeDefaultStateKey, + [NSNumber numberWithBool:YES], kTSInputModeIsVisibleKey, + @"H", kTSInputModeKeyEquivalentKey, + [NSNumber numberWithInteger:4608], kTSInputModeKeyEquivalentModifiersKey, + [NSNumber numberWithBool:YES], kTSInputModeDefaultStateKey, + @"keyman.png", kTSInputModeMenuIconFileKey, + @"keyman.png", kTSInputModePaletteIconFileKey, + [NSNumber numberWithBool:YES], kTSInputModePrimaryInScriptKey, + @"smUnicodeScript", kTSInputModeScriptKey, + @"hin", @"TISIntendedLanguage", nil]; + + NSDictionary *modeList = [[NSDictionary alloc] initWithObjectsAndKeys:amhMode, @"com.apple.inputmethod.amh", hinMode, @"com.apple.inputmethod.hin", nil]; + NSArray *modeOrder = [[NSArray alloc] initWithObjects:@"com.apple.inputmethod.amh", @"com.apple.inputmethod.hin", nil]; + _kmModes = [[NSDictionary alloc] initWithObjectsAndKeys:modeList, kTSInputModeListKey, + modeOrder, kTSVisibleInputModeOrderedArrayKey, nil]; + } + + return _kmModes; + } + */ - (NSMenu *)menu { - return self.AppDelegate.menu; + return self.AppDelegate.menu; } - (KMXFile *)kmx { - return self.AppDelegate.kmx; + return self.AppDelegate.kmx; } - (void)menuAction:(id)sender { - NSMenuItem *mItem = [sender objectForKey:kIMKCommandMenuItemName]; - NSInteger itag = mItem.tag; - if ([self.AppDelegate debugMode]) - NSLog(@"Keyman menu clicked - tag: %lu", itag); - if (itag == CONFIG_MENUITEM_TAG) { - [self showConfigurationWindow:sender]; - } - else if (itag == OSK_MENUITEM_TAG) { - [self.AppDelegate showOSK]; - } - else if (itag == ABOUT_MENUITEM_TAG) { - [self.AppDelegate showAboutWindow]; - } - else if (itag >= KEYMAN_FIRST_KEYBOARD_MENUITEM_TAG) { - [self.AppDelegate selectKeyboardFromMenu:itag]; - } + NSMenuItem *mItem = [sender objectForKey:kIMKCommandMenuItemName]; + NSInteger itag = mItem.tag; + if ([self.AppDelegate debugMode]) + NSLog(@"Keyman menu clicked - tag: %lu", itag); + if (itag == CONFIG_MENUITEM_TAG) { + [self showConfigurationWindow:sender]; + } + else if (itag == OSK_MENUITEM_TAG) { + [self.AppDelegate showOSK]; + } + else if (itag == ABOUT_MENUITEM_TAG) { + [self.AppDelegate showAboutWindow]; + } + else if (itag >= KEYMAN_FIRST_KEYBOARD_MENUITEM_TAG) { + [self.AppDelegate selectKeyboardFromMenu:itag]; + } } - (void)showConfigurationWindow:(id)sender { @@ -194,13 +194,13 @@ - (void)showConfigurationWindow:(id)sender { u_int16_t systemVersion = [KMOSVersion SystemVersion]; if ([KMOSVersion Version_10_13_1] <= systemVersion && systemVersion <= [KMOSVersion Version_10_13_3]) // between 10.13.1 and 10.13.3 inclusive { - NSLog(@"Input Menu: calling workaround instead of showPreferences (sys ver %x)", systemVersion); - [self.AppDelegate showConfigurationWindow]; // call our workaround + NSLog(@"Input Menu: calling workaround instead of showPreferences (sys ver %x)", systemVersion); + [self.AppDelegate showConfigurationWindow]; // call our workaround } else { - NSLog(@"Input Menu: calling Apple's showPreferences (sys ver %x)", systemVersion); - [self showPreferences:sender]; // call Apple API + NSLog(@"Input Menu: calling Apple's showPreferences (sys ver %x)", systemVersion); + [self showPreferences:sender]; // call Apple API } } diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index dad846bdb78..e5311f55053 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -29,11 +29,11 @@ NSString *const kKMSelectedKeyboardKey = @"KMSelectedKeyboardKey"; NSString *const kKMActiveKeyboardsKey = @"KMActiveKeyboardsKey"; /** - The following constant "KMSavedStoresKey" is left here for documentation - though we have abandoned stores written to UserDefaults with this key because - they used a less-reliable numeric key prior to integration with Keyman Core. - It is replaced by the renamed "KMPersistedOptionsKey" which directly - represents what it is saving. + The following constant "KMSavedStoresKey" is left here for documentation + though we have abandoned stores written to UserDefaults with this key because + they used a less-reliable numeric key prior to integration with Keyman Core. + It is replaced by the renamed "KMPersistedOptionsKey" which directly + represents what it is saving. */ NSString *const kKMDeprecatedPersistedOptionsKey = @"KMSavedStoresKey"; NSString *const kKMPersistedOptionsKey = @"KMPersistedOptionsKey"; @@ -54,14 +54,14 @@ @implementation NSString (VersionNumbers) * ``` */ - (NSString *)minimalVersionNumberString { - static NSString *const unnecessaryVersionSuffix = @".0"; - NSString *minimalVersionNumber = self; - - while ([minimalVersionNumber hasSuffix:unnecessaryVersionSuffix]) { - minimalVersionNumber = [minimalVersionNumber substringToIndex:minimalVersionNumber.length - unnecessaryVersionSuffix.length]; - } - - return minimalVersionNumber; + static NSString *const unnecessaryVersionSuffix = @".0"; + NSString *minimalVersionNumber = self; + + while ([minimalVersionNumber hasSuffix:unnecessaryVersionSuffix]) { + minimalVersionNumber = [minimalVersionNumber substringToIndex:minimalVersionNumber.length - unnecessaryVersionSuffix.length]; + } + + return minimalVersionNumber; } @end @@ -85,25 +85,25 @@ @implementation KMInputMethodAppDelegate NSString* _keymanDataPath = nil; - (id)init { - self = [super init]; - if (self) { + self = [super init]; + if (self) { #ifdef DEBUG - // If debugging, we'll turn it on by default, regardless of setting. If developer - // really wants it off, they can either change this line of code temporarily or - // go to the config screen and turn it off explicitly. - _debugMode = YES; + // If debugging, we'll turn it on by default, regardless of setting. If developer + // really wants it off, they can either change this line of code temporarily or + // go to the config screen and turn it off explicitly. + _debugMode = YES; #else - _debugMode = self.useVerboseLogging; + _debugMode = self.useVerboseLogging; #endif - - // first notify user and request access to Accessibility/PostEvent permissions - // pass block as completion handler to complete init with initCompletion - [PrivacyConsent.shared requestPrivacyAccess:^void (void){ - [self initCompletion]; - }]; - } - - return self; + + // first notify user and request access to Accessibility/PostEvent permissions + // pass block as completion handler to complete init with initCompletion + [PrivacyConsent.shared requestPrivacyAccess:^void (void){ + [self initCompletion]; + }]; + } + + return self; } - (void)initCompletion { @@ -112,7 +112,7 @@ - (void)initCompletion { andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; - + self.lowLevelEventTap = CGEventTapCreate(kCGAnnotatedSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, @@ -122,21 +122,21 @@ - (void)initCompletion { CGEventMaskBit(kCGEventKeyDown), (CGEventTapCallBack)eventTapFunction, nil); - + if (!self.lowLevelEventTap) { - NSLog(@"Unable to create lowLevelEventTap!"); + NSLog(@"Unable to create lowLevelEventTap!"); } else { - NSLog(@"Successfully created lowLevelEventTap with CGEventTapCreate."); - CFRelease(self.lowLevelEventTap); + NSLog(@"Successfully created lowLevelEventTap with CGEventTapCreate."); + CFRelease(self.lowLevelEventTap); } - + self.runLoopEventSrc = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.lowLevelEventTap, 0); - + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); - + if (self.runLoopEventSrc && runLoop) { - CFRunLoopAddSource(runLoop, self.runLoopEventSrc, kCFRunLoopDefaultMode); + CFRunLoopAddSource(runLoop, self.runLoopEventSrc, kCFRunLoopDefaultMode); } } @@ -150,372 +150,372 @@ -(void)logDebugMessage:(NSString *)format, ... { } - (KeymanVersionInfo)versionInfo { - KeymanVersionInfo result; - // Get version information from Info.plist, which is filled in - // by build.sh. - NSDictionary *keymanInfo =[[[NSBundle mainBundle] infoDictionary] objectForKey:@"Keyman"]; - result.sentryEnvironment = [keymanInfo objectForKey:@"SentryEnvironment"]; - result.tier = [keymanInfo objectForKey:@"Tier"]; - result.versionRelease = [keymanInfo objectForKey:@"VersionRelease"]; - result.versionWithTag = [keymanInfo objectForKey:@"VersionWithTag"]; - result.versionGitTag = [keymanInfo objectForKey:@"VersionGitTag"]; - // if([result.tier isEqualToString:@"stable"]) { // #7227 disabling: - result.keymanCom = @"keyman.com"; - result.helpKeymanCom = @"help.keyman.com"; - result.apiKeymanCom = @"api.keyman.com"; - /*} - else { - result.keymanCom = @"keyman-staging.com"; - result.helpKeymanCom = @"help.keyman-staging.com"; - result.apiKeymanCom = @"api.keyman-staging.com"; - }*/ - return result; + KeymanVersionInfo result; + // Get version information from Info.plist, which is filled in + // by build.sh. + NSDictionary *keymanInfo =[[[NSBundle mainBundle] infoDictionary] objectForKey:@"Keyman"]; + result.sentryEnvironment = [keymanInfo objectForKey:@"SentryEnvironment"]; + result.tier = [keymanInfo objectForKey:@"Tier"]; + result.versionRelease = [keymanInfo objectForKey:@"VersionRelease"]; + result.versionWithTag = [keymanInfo objectForKey:@"VersionWithTag"]; + result.versionGitTag = [keymanInfo objectForKey:@"VersionGitTag"]; + // if([result.tier isEqualToString:@"stable"]) { // #7227 disabling: + result.keymanCom = @"keyman.com"; + result.helpKeymanCom = @"help.keyman.com"; + result.apiKeymanCom = @"api.keyman.com"; + /*} + else { + result.keymanCom = @"keyman-staging.com"; + result.helpKeymanCom = @"help.keyman-staging.com"; + result.apiKeymanCom = @"api.keyman-staging.com"; + }*/ + return result; } -(void)applicationDidFinishLaunching:(NSNotification *)aNotification { - [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @YES }]; - - KeymanVersionInfo keymanVersionInfo = [self versionInfo]; - NSString *releaseName = [NSString stringWithFormat:@"%@", keymanVersionInfo.versionGitTag]; - - [SentrySDK startWithConfigureOptions:^(SentryOptions *options) { - options.dsn = @"https://960f8b8e574c46e3be385d60ce8e1fea@o1005580.ingest.sentry.io/5983522"; - options.releaseName = releaseName; - options.environment = keymanVersionInfo.sentryEnvironment; - // options.debug = @YES; - }]; - - // [SentrySDK captureMessage:@"Starting Keyman [test message]"]; + [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @YES }]; + + KeymanVersionInfo keymanVersionInfo = [self versionInfo]; + NSString *releaseName = [NSString stringWithFormat:@"%@", keymanVersionInfo.versionGitTag]; + + [SentrySDK startWithConfigureOptions:^(SentryOptions *options) { + options.dsn = @"https://960f8b8e574c46e3be385d60ce8e1fea@o1005580.ingest.sentry.io/5983522"; + options.releaseName = releaseName; + options.environment = keymanVersionInfo.sentryEnvironment; + // options.debug = @YES; + }]; + + // [SentrySDK captureMessage:@"Starting Keyman [test message]"]; } #ifdef USE_ALERT_SHOW_HELP_TO_FORCE_EASTER_EGG_CRASH_FROM_ENGINE - (BOOL)alertShowHelp:(NSAlert *)alert { - NSLog(@"Sentry - KME: Got call to force crash from engine"); - [SentrySDK crash]; - NSLog(@"Sentry - KME: should not have gotten this far!"); - return NO; + NSLog(@"Sentry - KME: Got call to force crash from engine"); + [SentrySDK crash]; + NSLog(@"Sentry - KME: should not have gotten this far!"); + return NO; } #endif - (void)handleURLEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent { - - [self processURL:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]]; + + [self processURL:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]]; } - (void)processURL:(NSString*)rawUrl { - NSMutableString *urlStr = [NSMutableString stringWithString:rawUrl]; - [urlStr replaceOccurrencesOfString:@"keyman:" withString:@"keyman/" options:0 range:NSMakeRange(0, 7)]; - NSURL *url = [NSURL URLWithString:urlStr]; - if (self.debugMode) - NSLog(@"url = %@", url); - - if ([url.lastPathComponent isEqualToString:@"download"]) { - if (_connection != nil) { - if (self.debugMode) - NSLog(@"Already downloading a keyboard."); - return; - } - - NSURL *downloadUrl; - NSArray *params = [[url query] componentsSeparatedByString:@"&"]; - for (NSString *value in params) { - NSUInteger index = NSNotFound; - if ((index = [value rangeOfString:@"filename="].location) != NSNotFound) - _downloadFilename = [NSString stringWithString:[value substringFromIndex:index+9]]; - else if ((index = [value rangeOfString:@"url="].location) != NSNotFound) { - NSString *urlString = [NSString stringWithString:[value substringFromIndex:index+4]]; - urlString = [urlString stringByRemovingPercentEncoding]; - downloadUrl = [NSURL URLWithString:urlString]; - } - } + NSMutableString *urlStr = [NSMutableString stringWithString:rawUrl]; + [urlStr replaceOccurrencesOfString:@"keyman:" withString:@"keyman/" options:0 range:NSMakeRange(0, 7)]; + NSURL *url = [NSURL URLWithString:urlStr]; + if (self.debugMode) + NSLog(@"url = %@", url); + + if ([url.lastPathComponent isEqualToString:@"download"]) { + if (_connection != nil) { + if (self.debugMode) + NSLog(@"Already downloading a keyboard."); + return; } + + NSURL *downloadUrl; + NSArray *params = [[url query] componentsSeparatedByString:@"&"]; + for (NSString *value in params) { + NSUInteger index = NSNotFound; + if ((index = [value rangeOfString:@"filename="].location) != NSNotFound) + _downloadFilename = [NSString stringWithString:[value substringFromIndex:index+9]]; + else if ((index = [value rangeOfString:@"url="].location) != NSNotFound) { + NSString *urlString = [NSString stringWithString:[value substringFromIndex:index+4]]; + urlString = [urlString stringByRemovingPercentEncoding]; + downloadUrl = [NSURL URLWithString:urlString]; + } + } + } } + (KMInputMethodAppDelegate *)AppDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; + return (KMInputMethodAppDelegate *)[NSApp delegate]; } -(void) sleepFollowingDeactivationOfServer:(id)lastServer { + if ([self debugMode]) { + NSLog(@"Keyman no longer active IM."); + } + self.sleeping = YES; + if ([self.oskWindow.window isVisible]) { if ([self debugMode]) { - NSLog(@"Keyman no longer active IM."); - } - self.sleeping = YES; - if ([self.oskWindow.window isVisible]) { - if ([self debugMode]) { - NSLog(@"Hiding OSK."); - } - // Storing this ensures that if the deactivation is temporary, resulting from dropping down a menu, - // the OSK will re-display when that client application re-activates. - _lastServerWithOSKShowing = lastServer; - [self.oskWindow.window setIsVisible:NO]; + NSLog(@"Hiding OSK."); } - if (self.lowLevelEventTap) { - if ([self debugMode]) { - NSLog(@"Disabling event tap..."); - } - CGEventTapEnable(self.lowLevelEventTap, NO); + // Storing this ensures that if the deactivation is temporary, resulting from dropping down a menu, + // the OSK will re-display when that client application re-activates. + _lastServerWithOSKShowing = lastServer; + [self.oskWindow.window setIsVisible:NO]; + } + if (self.lowLevelEventTap) { + if ([self debugMode]) { + NSLog(@"Disabling event tap..."); } + CGEventTapEnable(self.lowLevelEventTap, NO); + } } -(void) wakeUpWith:(id)newServer { - self.sleeping = NO; - if (self.lowLevelEventTap && !CGEventTapIsEnabled(self.lowLevelEventTap)) { - if ([self debugMode]) { - NSLog(@"Keyman is now the active IM. Re-enabling event tap..."); - } - CGEventTapEnable(self.lowLevelEventTap, YES); - } - // See note in sleepFollowingDeactivationOfServer. - if (_kvk != nil && (_alwaysShowOSK || _lastServerWithOSKShowing == newServer)) { - [self showOSK]; + self.sleeping = NO; + if (self.lowLevelEventTap && !CGEventTapIsEnabled(self.lowLevelEventTap)) { + if ([self debugMode]) { + NSLog(@"Keyman is now the active IM. Re-enabling event tap..."); } - - _lastServerWithOSKShowing = nil; + CGEventTapEnable(self.lowLevelEventTap, YES); + } + // See note in sleepFollowingDeactivationOfServer. + if (_kvk != nil && (_alwaysShowOSK || _lastServerWithOSKShowing == newServer)) { + [self showOSK]; + } + + _lastServerWithOSKShowing = nil; } CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { - KMInputMethodAppDelegate *appDelegate = [KMInputMethodAppDelegate AppDelegate]; - if (appDelegate != nil) { - if (type == kCGEventTapDisabledByTimeout || type == kCGEventTapDisabledByUserInput) { - // kCGEventTapDisabledByUserInput most likely means we're "sleeping", in which case we want it to stay - // disabled until we get the wake-up call. - if (!appDelegate.sleeping) { - // REVIEW: We might need to consider putting in some kind of counter/flag to ensure that the very next - // event is not another disable so we don't end up in an endless cycle. - NSLog(@"Event tap disabled by %@! Attempting to restart...", (type == kCGEventTapDisabledByTimeout ? @"timeout" : @"user")); - CGEventTapEnable(appDelegate.lowLevelEventTap, YES); - if (!CGEventTapIsEnabled(appDelegate.lowLevelEventTap)) { - if (appDelegate.runLoopEventSrc) { // This should always be true - CFRunLoopRef runLoop = CFRunLoopGetCurrent(); - if (runLoop) { - CFRunLoopRemoveSource(runLoop, appDelegate.runLoopEventSrc, kCFRunLoopDefaultMode); - } - appDelegate.runLoopEventSrc = nil; - } - appDelegate.lowLevelEventTap = nil; - } + KMInputMethodAppDelegate *appDelegate = [KMInputMethodAppDelegate AppDelegate]; + if (appDelegate != nil) { + if (type == kCGEventTapDisabledByTimeout || type == kCGEventTapDisabledByUserInput) { + // kCGEventTapDisabledByUserInput most likely means we're "sleeping", in which case we want it to stay + // disabled until we get the wake-up call. + if (!appDelegate.sleeping) { + // REVIEW: We might need to consider putting in some kind of counter/flag to ensure that the very next + // event is not another disable so we don't end up in an endless cycle. + NSLog(@"Event tap disabled by %@! Attempting to restart...", (type == kCGEventTapDisabledByTimeout ? @"timeout" : @"user")); + CGEventTapEnable(appDelegate.lowLevelEventTap, YES); + if (!CGEventTapIsEnabled(appDelegate.lowLevelEventTap)) { + if (appDelegate.runLoopEventSrc) { // This should always be true + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + if (runLoop) { + CFRunLoopRemoveSource(runLoop, appDelegate.runLoopEventSrc, kCFRunLoopDefaultMode); } - return event; + appDelegate.runLoopEventSrc = nil; + } + appDelegate.lowLevelEventTap = nil; } - - NSEvent* sysEvent = [NSEvent eventWithCGEvent:event]; - // Too many of these to be useful for most debugging sessions, but we'll keep this around to be - // un-commented when needed. - //if (appDelegate.debugMode) - // NSLog(@"System Event: %@", sysEvent); - - switch (type) { - case kCGEventFlagsChanged: - if (appDelegate.debugMode) - NSLog(@"eventTapFunction: system event kCGEventFlagsChanged to: %x", (int) sysEvent.modifierFlags); - appDelegate.currentModifierFlags = sysEvent.modifierFlags; - if (appDelegate.currentModifierFlags & NSEventModifierFlagCommand) { - appDelegate.contextChangedByLowLevelEvent = YES; - } - break; - - case kCGEventLeftMouseUp: - case kCGEventLeftMouseDown: - case kCGEventOtherMouseUp: - case kCGEventOtherMouseDown: - NSLog(@"Event tap context invalidation flagged due to event: %@", event); - appDelegate.contextChangedByLowLevelEvent = YES; - break; - - case kCGEventKeyDown: - NSLog(@"Event tap keydown event, keyCode: %hu, event: %@", sysEvent.keyCode, event); - // Pass back low-level backspace events to the input method event handler - // because some non-compliant apps do not allow us to see backspace events - // that we have generated (and we need to see them, for serialization - // of events) - if(sysEvent.keyCode == kVK_Delete && appDelegate.inputController != nil) { - NSLog(@"Event tap handling kVK_Delete."); - [appDelegate.inputController handleBackspace:sysEvent]; - } else if(sysEvent.keyCode == kVK_Delete) { - NSLog(@"Event tap not handling kVK_Delete, appDelegate.inputController = %@", appDelegate.inputController); - } - if(sysEvent.keyCode == 255) { - NSLog(@"*** kKeymanEventKeyCode = 0xFF"); - } else { - NSLog(@"*** other: %d(%x)", (char) sysEvent.keyCode, sysEvent.keyCode); - } - - switch(sysEvent.keyCode) { - case kVK_Home: - case kVK_PageUp: - case kVK_End: - case kVK_PageDown: - // While these four may not actually move the cursor, this is application-dependent, - // so we'll treat them all as a context change. This means we lose deadkeys if these - // are pressed, but that's actually probably a good thing anyway! - case kVK_LeftArrow: - case kVK_RightArrow: - case kVK_DownArrow: - case kVK_UpArrow: - // Cursor movement means that we need to recheck the context - case kVK_Escape: - // Escape key should be treated as a context reset - case kVK_F1: - case kVK_F2: - case kVK_F3: - case kVK_F4: - case kVK_F5: - case kVK_F6: - case kVK_F7: - case kVK_F8: - case kVK_F9: - case kVK_F10: - case kVK_F11: - case kVK_F12: - case kVK_F13: - case kVK_F14: - case kVK_F15: - case kVK_F16: - case kVK_F17: - case kVK_F18: - case kVK_F19: - case kVK_F20: - // Function keys are command keys, so context is invalid - case kVK_Tab: - // A tab between cells in a Word document, for instance, is a context change - case kVK_ForwardDelete: - // Text modification by the forward delete key should reset context, but - // note that normal Delete (aka Bksp) is already managed by Keyman correctly. - appDelegate.contextChangedByLowLevelEvent = YES; - break; - } - break; - - default: - break; + } + return event; + } + + NSEvent* sysEvent = [NSEvent eventWithCGEvent:event]; + // Too many of these to be useful for most debugging sessions, but we'll keep this around to be + // un-commented when needed. + //if (appDelegate.debugMode) + // NSLog(@"System Event: %@", sysEvent); + + switch (type) { + case kCGEventFlagsChanged: + if (appDelegate.debugMode) + NSLog(@"eventTapFunction: system event kCGEventFlagsChanged to: %x", (int) sysEvent.modifierFlags); + appDelegate.currentModifierFlags = sysEvent.modifierFlags; + if (appDelegate.currentModifierFlags & NSEventModifierFlagCommand) { + appDelegate.contextChangedByLowLevelEvent = YES; + } + break; + + case kCGEventLeftMouseUp: + case kCGEventLeftMouseDown: + case kCGEventOtherMouseUp: + case kCGEventOtherMouseDown: + NSLog(@"Event tap context invalidation flagged due to event: %@", event); + appDelegate.contextChangedByLowLevelEvent = YES; + break; + + case kCGEventKeyDown: + NSLog(@"Event tap keydown event, keyCode: %hu, event: %@", sysEvent.keyCode, event); + // Pass back low-level backspace events to the input method event handler + // because some non-compliant apps do not allow us to see backspace events + // that we have generated (and we need to see them, for serialization + // of events) + if(sysEvent.keyCode == kVK_Delete && appDelegate.inputController != nil) { + NSLog(@"Event tap handling kVK_Delete."); + [appDelegate.inputController handleBackspace:sysEvent]; + } else if(sysEvent.keyCode == kVK_Delete) { + NSLog(@"Event tap not handling kVK_Delete, appDelegate.inputController = %@", appDelegate.inputController); + } + if(sysEvent.keyCode == 255) { + NSLog(@"*** kKeymanEventKeyCode = 0xFF"); + } else { + NSLog(@"*** other: %d(%x)", (char) sysEvent.keyCode, sysEvent.keyCode); + } + + switch(sysEvent.keyCode) { + case kVK_Home: + case kVK_PageUp: + case kVK_End: + case kVK_PageDown: + // While these four may not actually move the cursor, this is application-dependent, + // so we'll treat them all as a context change. This means we lose deadkeys if these + // are pressed, but that's actually probably a good thing anyway! + case kVK_LeftArrow: + case kVK_RightArrow: + case kVK_DownArrow: + case kVK_UpArrow: + // Cursor movement means that we need to recheck the context + case kVK_Escape: + // Escape key should be treated as a context reset + case kVK_F1: + case kVK_F2: + case kVK_F3: + case kVK_F4: + case kVK_F5: + case kVK_F6: + case kVK_F7: + case kVK_F8: + case kVK_F9: + case kVK_F10: + case kVK_F11: + case kVK_F12: + case kVK_F13: + case kVK_F14: + case kVK_F15: + case kVK_F16: + case kVK_F17: + case kVK_F18: + case kVK_F19: + case kVK_F20: + // Function keys are command keys, so context is invalid + case kVK_Tab: + // A tab between cells in a Word document, for instance, is a context change + case kVK_ForwardDelete: + // Text modification by the forward delete key should reset context, but + // note that normal Delete (aka Bksp) is already managed by Keyman correctly. + appDelegate.contextChangedByLowLevelEvent = YES; + break; } + break; + + default: + break; } - return event; + } + return event; } - (NSMenu *)menu { - return _menu; + return _menu; } - (KMEngine *)kme { - if (_kme == nil) { - _kme = [[KMEngine alloc] initWithKMX:nil context:self.contextBuffer verboseLogging:self.debugMode]; - } - - return _kme; + if (_kme == nil) { + _kme = [[KMEngine alloc] initWithKMX:nil context:self.contextBuffer verboseLogging:self.debugMode]; + } + + return _kme; } - (KMPackageReader *)packageReader { - if (_packageReader == nil) { - _packageReader = [[KMPackageReader alloc] init]; - [_packageReader setDebugMode:self.debugMode]; - } - - return _packageReader; + if (_packageReader == nil) { + _packageReader = [[KMPackageReader alloc] init]; + [_packageReader setDebugMode:self.debugMode]; + } + + return _packageReader; } - (void)setKmx:(KMXFile *)kmx { - _kmx = kmx; - [self.kme setKmx:_kmx]; + _kmx = kmx; + [self.kme setKmx:_kmx]; } - (void)setKvk:(KVKFile *)kvk { - _kvk = kvk; - if (_oskWindow != nil) - [_oskWindow resetOSK]; + _kvk = kvk; + if (_oskWindow != nil) + [_oskWindow resetOSK]; } - (void)setKeyboardName:(NSString *)keyboardName { - _keyboardName = keyboardName; - if (_oskWindow != nil) - [_oskWindow.window setTitle:self.oskWindowTitle]; + _keyboardName = keyboardName; + if (_oskWindow != nil) + [_oskWindow.window setTitle:self.oskWindowTitle]; } - (void)readPersistedOptions { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - NSDictionary *allPersistedOptions = [userData dictionaryForKey:kKMPersistedOptionsKey]; - if (!allPersistedOptions) { - return; - } - NSDictionary *persistedOptionsForSelectedKeyboard = [allPersistedOptions objectForKey:_selectedKeyboard]; - if (!persistedOptionsForSelectedKeyboard) { - NSLog(@"no persisted options found in UserDefaults for keyboard %@ ", _selectedKeyboard); - return; - } - + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + NSDictionary *allPersistedOptions = [userData dictionaryForKey:kKMPersistedOptionsKey]; + if (!allPersistedOptions) { + return; + } + NSDictionary *persistedOptionsForSelectedKeyboard = [allPersistedOptions objectForKey:_selectedKeyboard]; + if (!persistedOptionsForSelectedKeyboard) { + NSLog(@"no persisted options found in UserDefaults for keyboard %@ ", _selectedKeyboard); + return; + } + // TODO: pass array instead of making repeated calls - for (NSString *key in persistedOptionsForSelectedKeyboard) { - NSString *value = [persistedOptionsForSelectedKeyboard objectForKey:key]; - NSLog(@"persisted options found in UserDefaults for keyboard %@, key: %@, value: %@", _selectedKeyboard, key, value); - [self.kme setCoreOptions:key withValue:value]; - } + for (NSString *key in persistedOptionsForSelectedKeyboard) { + NSString *value = [persistedOptionsForSelectedKeyboard objectForKey:key]; + NSLog(@"persisted options found in UserDefaults for keyboard %@, key: %@, value: %@", _selectedKeyboard, key, value); + [self.kme setCoreOptions:key withValue:value]; + } } - (void)writePersistedOptions:(NSString *)storeKey withValue:(NSString* )value { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - NSDictionary *allPersistedOptions = [userData dictionaryForKey:kKMPersistedOptionsKey]; - NSDictionary *persistedOptionsForSelectedKeyboard; - - if (allPersistedOptions) { - persistedOptionsForSelectedKeyboard = [allPersistedOptions objectForKey:_selectedKeyboard]; - } - - if (persistedOptionsForSelectedKeyboard) { - NSMutableDictionary *newSavedStores = [persistedOptionsForSelectedKeyboard mutableCopy]; - [newSavedStores setObject:value forKey:storeKey]; - persistedOptionsForSelectedKeyboard = newSavedStores; - } else { - persistedOptionsForSelectedKeyboard = [[NSDictionary alloc] initWithObjectsAndKeys:value, storeKey, nil]; - } - - if (allPersistedOptions) { - NSMutableDictionary *newAllSavedStores = [allPersistedOptions mutableCopy]; - [newAllSavedStores setObject:persistedOptionsForSelectedKeyboard forKey:_selectedKeyboard]; - allPersistedOptions = newAllSavedStores; - } else { - allPersistedOptions = [[NSDictionary alloc] initWithObjectsAndKeys:persistedOptionsForSelectedKeyboard, _selectedKeyboard, nil]; - } - - [userData setObject:allPersistedOptions forKey:kKMPersistedOptionsKey]; - [userData synchronize]; + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + NSDictionary *allPersistedOptions = [userData dictionaryForKey:kKMPersistedOptionsKey]; + NSDictionary *persistedOptionsForSelectedKeyboard; + + if (allPersistedOptions) { + persistedOptionsForSelectedKeyboard = [allPersistedOptions objectForKey:_selectedKeyboard]; + } + + if (persistedOptionsForSelectedKeyboard) { + NSMutableDictionary *newSavedStores = [persistedOptionsForSelectedKeyboard mutableCopy]; + [newSavedStores setObject:value forKey:storeKey]; + persistedOptionsForSelectedKeyboard = newSavedStores; + } else { + persistedOptionsForSelectedKeyboard = [[NSDictionary alloc] initWithObjectsAndKeys:value, storeKey, nil]; + } + + if (allPersistedOptions) { + NSMutableDictionary *newAllSavedStores = [allPersistedOptions mutableCopy]; + [newAllSavedStores setObject:persistedOptionsForSelectedKeyboard forKey:_selectedKeyboard]; + allPersistedOptions = newAllSavedStores; + } else { + allPersistedOptions = [[NSDictionary alloc] initWithObjectsAndKeys:persistedOptionsForSelectedKeyboard, _selectedKeyboard, nil]; + } + + [userData setObject:allPersistedOptions forKey:kKMPersistedOptionsKey]; + [userData synchronize]; } - (NSString *)oskWindowTitle { - if (_keyboardName == nil || !_keyboardName.length) - return [NSString stringWithFormat:@"Keyman"]; - else - return [NSString stringWithFormat:@"%@ - Keyman", _keyboardName]; + if (_keyboardName == nil || !_keyboardName.length) + return [NSString stringWithFormat:@"Keyman"]; + else + return [NSString stringWithFormat:@"%@ - Keyman", _keyboardName]; } - (void)setAlwaysShowOSK:(BOOL)alwaysShowOSK { - _alwaysShowOSK = alwaysShowOSK; - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setBool:alwaysShowOSK forKey:kKMAlwaysShowOSKKey]; - [userData synchronize]; + _alwaysShowOSK = alwaysShowOSK; + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setBool:alwaysShowOSK forKey:kKMAlwaysShowOSKKey]; + [userData synchronize]; } - (void)setUseVerboseLogging:(BOOL)useVerboseLogging { - NSLog(@"Turning verbose logging %@", useVerboseLogging ? @"on." : @"off."); - _debugMode = useVerboseLogging; - if (_kme != nil) - [_kme setUseVerboseLogging:useVerboseLogging]; - if (_packageReader != nil) { - [_packageReader setDebugMode:useVerboseLogging]; - } - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setBool:useVerboseLogging forKey:kKMUseVerboseLogging]; - [userData synchronize]; + NSLog(@"Turning verbose logging %@", useVerboseLogging ? @"on." : @"off."); + _debugMode = useVerboseLogging; + if (_kme != nil) + [_kme setUseVerboseLogging:useVerboseLogging]; + if (_packageReader != nil) { + [_packageReader setDebugMode:useVerboseLogging]; + } + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setBool:useVerboseLogging forKey:kKMUseVerboseLogging]; + [userData synchronize]; } - (BOOL)alwaysShowOSK { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - _alwaysShowOSK = [userData boolForKey:kKMAlwaysShowOSKKey]; - return _alwaysShowOSK; + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + _alwaysShowOSK = [userData boolForKey:kKMAlwaysShowOSKKey]; + return _alwaysShowOSK; } - (BOOL)useVerboseLogging { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - return [userData boolForKey:kKMUseVerboseLogging]; + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + return [userData boolForKey:kKMUseVerboseLogging]; } #pragma mark - Keyman Data @@ -524,16 +524,16 @@ - (BOOL)useVerboseLogging { * Locate and create the Keyman data path; currently in ~/Documents/Keyman-Keyboards */ - (NSString *)keymanDataPath { - if(_keymanDataPath == nil) { - NSString *documentDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - _keymanDataPath = [documentDirPath stringByAppendingPathComponent:@"Keyman-Keyboards"]; - - NSFileManager *fm = [NSFileManager defaultManager]; - if (![fm fileExistsAtPath:_keymanDataPath]) { - [fm createDirectoryAtPath:_keymanDataPath withIntermediateDirectories:YES attributes:nil error:nil]; - } + if(_keymanDataPath == nil) { + NSString *documentDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + _keymanDataPath = [documentDirPath stringByAppendingPathComponent:@"Keyman-Keyboards"]; + + NSFileManager *fm = [NSFileManager defaultManager]; + if (![fm fileExistsAtPath:_keymanDataPath]) { + [fm createDirectoryAtPath:_keymanDataPath withIntermediateDirectories:YES attributes:nil error:nil]; } - return _keymanDataPath; + } + return _keymanDataPath; } /** @@ -541,242 +541,242 @@ - (NSString *)keymanDataPath { * as the keymanDataPath, but may diverge in future versions (possibly a sub-folder) */ - (NSString *)keyboardsPath { - if (_keyboardsPath == nil) { - _keyboardsPath = [self keymanDataPath]; - } - - return _keyboardsPath; + if (_keyboardsPath == nil) { + _keyboardsPath = [self keymanDataPath]; + } + + return _keyboardsPath; } - (NSArray *)kmxFileList { - if (_kmxFileList == nil) { - NSArray *kmxFiles = [self KMXFiles]; - _kmxFileList = [[NSMutableArray alloc] initWithCapacity:0]; - NSMutableArray *others = nil; - for (NSString *filePath in kmxFiles) { - NSString *packageFolder = [self packageFolderFromPath:filePath]; - NSInteger index = [self indexForPackageFolder:packageFolder]; - if ([packageFolder isEqualToString:@"Others"]) { - if (others == nil) - others = [NSMutableArray arrayWithCapacity:0]; - [others addObject:filePath]; - } - else { - if (index >= 0) { - [[_kmxFileList objectAtIndex:index] addObject:filePath]; - } - else { - NSMutableArray *pArray = [[NSMutableArray alloc] initWithObjects:filePath, nil]; - [_kmxFileList addObject:pArray]; - } - } + if (_kmxFileList == nil) { + NSArray *kmxFiles = [self KMXFiles]; + _kmxFileList = [[NSMutableArray alloc] initWithCapacity:0]; + NSMutableArray *others = nil; + for (NSString *filePath in kmxFiles) { + NSString *packageFolder = [self packageFolderFromPath:filePath]; + NSInteger index = [self indexForPackageFolder:packageFolder]; + if ([packageFolder isEqualToString:@"Others"]) { + if (others == nil) + others = [NSMutableArray arrayWithCapacity:0]; + [others addObject:filePath]; + } + else { + if (index >= 0) { + [[_kmxFileList objectAtIndex:index] addObject:filePath]; } - - if (others != nil) - [_kmxFileList addObject:others]; + else { + NSMutableArray *pArray = [[NSMutableArray alloc] initWithObjects:filePath, nil]; + [_kmxFileList addObject:pArray]; + } + } } - - return _kmxFileList; + + if (others != nil) + [_kmxFileList addObject:others]; + } + + return _kmxFileList; } - (NSString *)kmxFilePathAtIndex:(NSUInteger)index { - NSUInteger x = 0; - NSUInteger len = _kmxFileList.count; - for (int i = 0; i < len; i++) { - x++; - NSArray *pArray = (NSArray *)[_kmxFileList objectAtIndex:i]; - for (NSString *path in pArray) { - if (index == x) - return path; - x++; - } + NSUInteger x = 0; + NSUInteger len = _kmxFileList.count; + for (int i = 0; i < len; i++) { + x++; + NSArray *pArray = (NSArray *)[_kmxFileList objectAtIndex:i]; + for (NSString *path in pArray) { + if (index == x) + return path; + x++; } - - return nil; + } + + return nil; } - (NSString *)packagePathAtIndex:(NSUInteger)index { - NSString *packagePath = nil; - NSUInteger x = 0; - NSUInteger len = _kmxFileList.count; - for (int i = 0; i < len; i++) { - NSArray *pArray = (NSArray *)[_kmxFileList objectAtIndex:i]; - if (!pArray.count) { - i++; - x++; - continue; - } - - if (index >= x && index <= (x+pArray.count)) { - packagePath = [[pArray objectAtIndex:0] stringByDeletingLastPathComponent]; - break; - } - - x += (pArray.count+1); + NSString *packagePath = nil; + NSUInteger x = 0; + NSUInteger len = _kmxFileList.count; + for (int i = 0; i < len; i++) { + NSArray *pArray = (NSArray *)[_kmxFileList objectAtIndex:i]; + if (!pArray.count) { + i++; + x++; + continue; } - - return packagePath; + + if (index >= x && index <= (x+pArray.count)) { + packagePath = [[pArray objectAtIndex:0] stringByDeletingLastPathComponent]; + break; + } + + x += (pArray.count+1); + } + + return packagePath; } - (NSInteger)indexForPackageFolder:(NSString *)packageFolder { - NSInteger index = -1; - NSUInteger len = _kmxFileList.count; - for (int i = 0; i < len; i++) { - NSArray *pArray = (NSArray *)[_kmxFileList objectAtIndex:i]; - if (pArray.count > 0) { - NSString *packageFolder2 = [self packageFolderFromPath:[pArray objectAtIndex:0]]; - if ([packageFolder isEqualToString:packageFolder2]) { - index = i; - break; - } - } + NSInteger index = -1; + NSUInteger len = _kmxFileList.count; + for (int i = 0; i < len; i++) { + NSArray *pArray = (NSArray *)[_kmxFileList objectAtIndex:i]; + if (pArray.count > 0) { + NSString *packageFolder2 = [self packageFolderFromPath:[pArray objectAtIndex:0]]; + if ([packageFolder isEqualToString:packageFolder2]) { + index = i; + break; + } } - - return index; + } + + return index; } - (NSString *)packageFolderFromPath:(NSString *)path { - NSString *packageFolder = nil; - NSString *sourcePath = [self keyboardsPath]; - NSString *mPath = [NSString stringWithString:[path stringByDeletingLastPathComponent]]; - if ([mPath isEqualToString:sourcePath]) - return @"Others"; - - while (![mPath isEqualToString:sourcePath]) { - packageFolder = [mPath lastPathComponent]; - mPath = [mPath stringByDeletingLastPathComponent]; - } - - return packageFolder; + NSString *packageFolder = nil; + NSString *sourcePath = [self keyboardsPath]; + NSString *mPath = [NSString stringWithString:[path stringByDeletingLastPathComponent]]; + if ([mPath isEqualToString:sourcePath]) + return @"Others"; + + while (![mPath isEqualToString:sourcePath]) { + packageFolder = [mPath lastPathComponent]; + mPath = [mPath stringByDeletingLastPathComponent]; + } + + return packageFolder; } - (KMPackageInfo *)loadPackageInfo:(NSString *)path { - return [self.packageReader loadPackageInfo:path]; + return [self.packageReader loadPackageInfo:path]; } - (NSString *)packageNameFromPackageInfo:(NSString *)packageFolder { - NSString *packageName = nil; - - NSString *path = [[self keymanDataPath] stringByAppendingPathComponent:packageFolder]; - KMPackageInfo *packageInfo = [self.packageReader loadPackageInfo:path]; - - if (packageInfo) { - packageName = packageInfo.packageName; - } - - return packageName; + NSString *packageName = nil; + + NSString *path = [[self keymanDataPath] stringByAppendingPathComponent:packageFolder]; + KMPackageInfo *packageInfo = [self.packageReader loadPackageInfo:path]; + + if (packageInfo) { + packageName = packageInfo.packageName; + } + + return packageName; } - (NSArray *)keyboardNamesFromFolder:(NSString *)packageFolder { - NSMutableArray *kbNames = [[NSMutableArray alloc] initWithCapacity:0];; - for (NSString *kmxFile in [self KMXFilesAtPath:packageFolder]) { - NSDictionary * infoDict = [KMXFile keyboardInfoFromKmxFile:kmxFile]; - if (infoDict != nil) { - NSString *name = [infoDict objectForKey:kKMKeyboardNameKey]; - if (name != nil && [name length]) { - if (self.debugMode) - NSLog(@"Adding keyboard name: %@", name); - [kbNames addObject:name]; - } - } + NSMutableArray *kbNames = [[NSMutableArray alloc] initWithCapacity:0];; + for (NSString *kmxFile in [self KMXFilesAtPath:packageFolder]) { + NSDictionary * infoDict = [KMXFile keyboardInfoFromKmxFile:kmxFile]; + if (infoDict != nil) { + NSString *name = [infoDict objectForKey:kKMKeyboardNameKey]; + if (name != nil && [name length]) { + if (self.debugMode) + NSLog(@"Adding keyboard name: %@", name); + [kbNames addObject:name]; + } } - return kbNames; + } + return kbNames; } - (NSString *)selectedKeyboard { - if (_selectedKeyboard == nil) { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - _selectedKeyboard = [userData objectForKey:kKMSelectedKeyboardKey]; - } - - return _selectedKeyboard; + if (_selectedKeyboard == nil) { + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + _selectedKeyboard = [userData objectForKey:kKMSelectedKeyboardKey]; + } + + return _selectedKeyboard; } - (void)setSelectedKeyboard:(NSString *)selectedKeyboard { - _selectedKeyboard = selectedKeyboard; - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setObject:_selectedKeyboard forKey:kKMSelectedKeyboardKey]; - [userData synchronize]; + _selectedKeyboard = selectedKeyboard; + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setObject:_selectedKeyboard forKey:kKMSelectedKeyboardKey]; + [userData synchronize]; } - (NSMutableArray *)activeKeyboards { - if (!_activeKeyboards) { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - _activeKeyboards = [[userData arrayForKey:kKMActiveKeyboardsKey] mutableCopy]; - if (!_activeKeyboards) - _activeKeyboards = [[NSMutableArray alloc] initWithCapacity:0]; - } - - return _activeKeyboards; + if (!_activeKeyboards) { + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + _activeKeyboards = [[userData arrayForKey:kKMActiveKeyboardsKey] mutableCopy]; + if (!_activeKeyboards) + _activeKeyboards = [[NSMutableArray alloc] initWithCapacity:0]; + } + + return _activeKeyboards; } - (void)saveActiveKeyboards { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setObject:_activeKeyboards forKey:kKMActiveKeyboardsKey]; - [userData synchronize]; - [self resetActiveKeyboards]; - [self updateKeyboardMenuItems]; + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setObject:_activeKeyboards forKey:kKMActiveKeyboardsKey]; + [userData synchronize]; + [self resetActiveKeyboards]; + [self updateKeyboardMenuItems]; } - (void)clearActiveKeyboards { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setObject:nil forKey:kKMActiveKeyboardsKey]; - [userData synchronize]; - [self updateKeyboardMenuItems]; + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setObject:nil forKey:kKMActiveKeyboardsKey]; + [userData synchronize]; + [self updateKeyboardMenuItems]; } - (void)resetActiveKeyboards { - // Remove entries with missing files - NSMutableArray *pathsToRemove = [[NSMutableArray alloc] initWithCapacity:0]; - for (NSString *path in self.activeKeyboards) { - if (![[NSFileManager defaultManager] fileExistsAtPath:path]) - [pathsToRemove addObject:path]; - } - - BOOL found = FALSE; - if (pathsToRemove.count > 0) { - [self.activeKeyboards removeObjectsInArray:pathsToRemove]; - found = TRUE; - } - - // Remove duplicate entries - NSUInteger i = 0; - while(i < [self.activeKeyboards count]) { - NSString *item = self.activeKeyboards[i]; - NSUInteger n = [self.activeKeyboards indexOfObject:item inRange: NSMakeRange(i+1, [self.activeKeyboards count]-i-1)]; - if(n != NSNotFound) { - [self.activeKeyboards removeObjectAtIndex:n]; - found = TRUE; - } else { - i++; - } - } - - if (found) { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - [userData setObject:_activeKeyboards forKey:kKMActiveKeyboardsKey]; - [userData synchronize]; + // Remove entries with missing files + NSMutableArray *pathsToRemove = [[NSMutableArray alloc] initWithCapacity:0]; + for (NSString *path in self.activeKeyboards) { + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) + [pathsToRemove addObject:path]; + } + + BOOL found = FALSE; + if (pathsToRemove.count > 0) { + [self.activeKeyboards removeObjectsInArray:pathsToRemove]; + found = TRUE; + } + + // Remove duplicate entries + NSUInteger i = 0; + while(i < [self.activeKeyboards count]) { + NSString *item = self.activeKeyboards[i]; + NSUInteger n = [self.activeKeyboards indexOfObject:item inRange: NSMakeRange(i+1, [self.activeKeyboards count]-i-1)]; + if(n != NSNotFound) { + [self.activeKeyboards removeObjectAtIndex:n]; + found = TRUE; + } else { + i++; } + } + + if (found) { + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + [userData setObject:_activeKeyboards forKey:kKMActiveKeyboardsKey]; + [userData synchronize]; + } } - (NSMutableString *)contextBuffer { - if (_contextBuffer == nil) { - _contextBuffer = [[NSMutableString alloc] initWithString:@""]; - } - - return _contextBuffer; + if (_contextBuffer == nil) { + _contextBuffer = [[NSMutableString alloc] initWithString:@""]; + } + + return _contextBuffer; } - (void)setContextBuffer:(NSMutableString *)contextBuffer { - _contextBuffer = [contextBuffer mutableCopy]; - if (_contextBuffer.length) - [_contextBuffer replaceOccurrencesOfString:@"\0" withString:[NSString nullChar] options:0 range:NSMakeRange(0, 1)]; - [self.kme setCoreContextIfNeeded:self.contextBuffer]; + _contextBuffer = [contextBuffer mutableCopy]; + if (_contextBuffer.length) + [_contextBuffer replaceOccurrencesOfString:@"\0" withString:[NSString nullChar] options:0 range:NSMakeRange(0, 1)]; + [self.kme setCoreContextIfNeeded:self.contextBuffer]; } - (void)awakeFromNib { - [self setDefaultKeymanMenuItems]; - [self updateKeyboardMenuItems]; + [self setDefaultKeymanMenuItems]; + [self updateKeyboardMenuItems]; } - (void)setDefaultKeymanMenuItems { @@ -826,197 +826,197 @@ - (void)removeDynamicKeyboardMenuItems { } - (void)addDynamicKeyboardMenuItems { - BOOL didSetSelectedKeyboard = NO; - NSInteger itag = KEYMAN_FIRST_KEYBOARD_MENUITEM_TAG; - NSString *keyboardMenuName = @""; - int menuItemIndex = KEYMAN_FIRST_KEYBOARD_MENUITEM_INDEX; + BOOL didSetSelectedKeyboard = NO; + NSInteger itag = KEYMAN_FIRST_KEYBOARD_MENUITEM_TAG; + NSString *keyboardMenuName = @""; + int menuItemIndex = KEYMAN_FIRST_KEYBOARD_MENUITEM_INDEX; - if (self.debugMode) { - NSLog(@"*** populateKeyboardMenuItems, number of active keyboards=%lu", self.activeKeyboards.count); - } + if (self.debugMode) { + NSLog(@"*** populateKeyboardMenuItems, number of active keyboards=%lu", self.activeKeyboards.count); + } - // loop through the active keyboards list and add them to the menu - for (NSString *path in self.activeKeyboards) { - NSDictionary *infoDict = [KMXFile keyboardInfoFromKmxFile:path]; - if (!infoDict) { - continue; - } - keyboardMenuName = [infoDict objectForKey:kKMKeyboardNameKey]; - NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:keyboardMenuName action:@selector(menuAction:) keyEquivalent:@""]; - [item setTag:itag++]; - - // if this is the selected keyboard, then configure it as selected - if ([path isEqualToString:self.selectedKeyboard]) { - [self setSelectedKeyboard:path inMenuItem:item]; - didSetSelectedKeyboard = YES; - } - else { - [item setState:NSOffState]; - } - - [self.menu insertItem:item atIndex:menuItemIndex++]; + // loop through the active keyboards list and add them to the menu + for (NSString *path in self.activeKeyboards) { + NSDictionary *infoDict = [KMXFile keyboardInfoFromKmxFile:path]; + if (!infoDict) { + continue; + } + keyboardMenuName = [infoDict objectForKey:kKMKeyboardNameKey]; + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:keyboardMenuName action:@selector(menuAction:) keyEquivalent:@""]; + [item setTag:itag++]; + + // if this is the selected keyboard, then configure it as selected + if ([path isEqualToString:self.selectedKeyboard]) { + [self setSelectedKeyboard:path inMenuItem:item]; + didSetSelectedKeyboard = YES; } - - if (self.activeKeyboards.count == 0) { - [self addKeyboardPlaceholderMenuItem]; - } else if (!didSetSelectedKeyboard) { - [self setDefaultSelectedKeyboard]; + else { + [item setState:NSOffState]; } + + [self.menu insertItem:item atIndex:menuItemIndex++]; + } + + if (self.activeKeyboards.count == 0) { + [self addKeyboardPlaceholderMenuItem]; + } else if (!didSetSelectedKeyboard) { + [self setDefaultSelectedKeyboard]; + } } - (void) setSelectedKeyboard:(NSString*)keyboardName inMenuItem:(NSMenuItem*) menuItem { - KVKFile *kvk = nil; - - [menuItem setState:NSOnState]; - KMXFile *kmx = [[KMXFile alloc] initWithFilePath:keyboardName]; - [self setKmx:kmx]; - NSDictionary *kmxInfo = [KMXFile keyboardInfoFromKmxFile:keyboardName]; - NSString *kvkFilename = [kmxInfo objectForKey:kKMVisualKeyboardKey]; - if (kvkFilename != nil) { - NSString *kvkFilePath = [self kvkFilePathFromFilename:kvkFilename]; - if (kvkFilePath != nil) { - kvk = [[KVKFile alloc] initWithFilePath:kvkFilePath]; - } + KVKFile *kvk = nil; + + [menuItem setState:NSOnState]; + KMXFile *kmx = [[KMXFile alloc] initWithFilePath:keyboardName]; + [self setKmx:kmx]; + NSDictionary *kmxInfo = [KMXFile keyboardInfoFromKmxFile:keyboardName]; + NSString *kvkFilename = [kmxInfo objectForKey:kKMVisualKeyboardKey]; + if (kvkFilename != nil) { + NSString *kvkFilePath = [self kvkFilePathFromFilename:kvkFilename]; + if (kvkFilePath != nil) { + kvk = [[KVKFile alloc] initWithFilePath:kvkFilePath]; } - [self setKvk:kvk]; - [self setKeyboardName:[kmxInfo objectForKey:kKMKeyboardNameKey]]; - [self setKeyboardIcon:[kmxInfo objectForKey:kKMKeyboardIconKey]]; - [self readPersistedOptions]; + } + [self setKvk:kvk]; + [self setKeyboardName:[kmxInfo objectForKey:kKMKeyboardNameKey]]; + [self setKeyboardIcon:[kmxInfo objectForKey:kKMKeyboardIconKey]]; + [self readPersistedOptions]; } // defaults to the whatever keyboard happens to be first in the list - (void) setDefaultSelectedKeyboard { - NSMenuItem* menuItem = [self.menu itemAtIndex:KEYMAN_FIRST_KEYBOARD_MENUITEM_INDEX]; - NSString *keyboardName = [self.activeKeyboards objectAtIndex:0]; - [self setSelectedKeyboard:keyboardName inMenuItem:menuItem]; - [self setSelectedKeyboard:keyboardName]; - [self setContextBuffer:nil]; + NSMenuItem* menuItem = [self.menu itemAtIndex:KEYMAN_FIRST_KEYBOARD_MENUITEM_INDEX]; + NSString *keyboardName = [self.activeKeyboards objectAtIndex:0]; + [self setSelectedKeyboard:keyboardName inMenuItem:menuItem]; + [self setSelectedKeyboard:keyboardName]; + [self setContextBuffer:nil]; } - (void) addKeyboardPlaceholderMenuItem { - NSString* placeholder = NSLocalizedString(@"no-keyboard-configured-menu-placeholder", nil); - NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:placeholder action:NULL keyEquivalent:@""]; - [self.menu insertItem:item atIndex:KEYMAN_FIRST_KEYBOARD_MENUITEM_INDEX]; - [self setKmx:nil]; - [self setKvk:nil]; - [self setKeyboardName:nil]; - [self setKeyboardIcon:nil]; - [self setContextBuffer:nil]; - [self setSelectedKeyboard:nil]; + NSString* placeholder = NSLocalizedString(@"no-keyboard-configured-menu-placeholder", nil); + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:placeholder action:NULL keyEquivalent:@""]; + [self.menu insertItem:item atIndex:KEYMAN_FIRST_KEYBOARD_MENUITEM_INDEX]; + [self setKmx:nil]; + [self setKvk:nil]; + [self setKeyboardName:nil]; + [self setKeyboardIcon:nil]; + [self setContextBuffer:nil]; + [self setSelectedKeyboard:nil]; } - (void)selectKeyboardFromMenu:(NSInteger)tag { - NSMenuItem *menuItem = [self.menu itemWithTag:tag]; - NSString *title = menuItem.title; - NSLog(@"Input Menu, selected Keyboards menu, itag: %lu, title: %@", tag, title); - for (NSMenuItem *item in self.menu.itemArray) { - // set the state of the keyboard items in the Keyman menu based on the new selection - if (item.tag >= KEYMAN_FIRST_KEYBOARD_MENUITEM_TAG) { - if (item.tag == tag) { - [item setState:NSOnState]; - } - else { - [item setState:NSOffState]; - } - } - } - - NSString *path = [self.activeKeyboards objectAtIndex:tag-KEYMAN_FIRST_KEYBOARD_MENUITEM_TAG]; - KMXFile *kmx = [[KMXFile alloc] initWithFilePath:path]; - [self setKmx:kmx]; - KVKFile *kvk = nil; - NSDictionary *kmxInfo = [KMXFile keyboardInfoFromKmxFile:path]; - NSString *kvkFilename = [kmxInfo objectForKey:kKMVisualKeyboardKey]; - if (kvkFilename != nil) { - NSString *kvkFilePath = [self kvkFilePathFromFilename:kvkFilename]; - if (kvkFilePath != nil) - kvk = [[KVKFile alloc] initWithFilePath:kvkFilePath]; + NSMenuItem *menuItem = [self.menu itemWithTag:tag]; + NSString *title = menuItem.title; + NSLog(@"Input Menu, selected Keyboards menu, itag: %lu, title: %@", tag, title); + for (NSMenuItem *item in self.menu.itemArray) { + // set the state of the keyboard items in the Keyman menu based on the new selection + if (item.tag >= KEYMAN_FIRST_KEYBOARD_MENUITEM_TAG) { + if (item.tag == tag) { + [item setState:NSOnState]; + } + else { + [item setState:NSOffState]; + } } - [self setKvk:kvk]; - NSString *keyboardName = [kmxInfo objectForKey:kKMKeyboardNameKey]; - if ([self debugMode]) - NSLog(@"Selected keyboard from menu: %@", keyboardName); - [self setKeyboardName:keyboardName]; - [self setKeyboardIcon:[kmxInfo objectForKey:kKMKeyboardIconKey]]; - [self setContextBuffer:nil]; - [self setSelectedKeyboard:path]; - [self readPersistedOptions]; - if (kvk != nil && self.alwaysShowOSK) - [self showOSK]; + } + + NSString *path = [self.activeKeyboards objectAtIndex:tag-KEYMAN_FIRST_KEYBOARD_MENUITEM_TAG]; + KMXFile *kmx = [[KMXFile alloc] initWithFilePath:path]; + [self setKmx:kmx]; + KVKFile *kvk = nil; + NSDictionary *kmxInfo = [KMXFile keyboardInfoFromKmxFile:path]; + NSString *kvkFilename = [kmxInfo objectForKey:kKMVisualKeyboardKey]; + if (kvkFilename != nil) { + NSString *kvkFilePath = [self kvkFilePathFromFilename:kvkFilename]; + if (kvkFilePath != nil) + kvk = [[KVKFile alloc] initWithFilePath:kvkFilePath]; + } + [self setKvk:kvk]; + NSString *keyboardName = [kmxInfo objectForKey:kKMKeyboardNameKey]; + if ([self debugMode]) + NSLog(@"Selected keyboard from menu: %@", keyboardName); + [self setKeyboardName:keyboardName]; + [self setKeyboardIcon:[kmxInfo objectForKey:kKMKeyboardIconKey]]; + [self setContextBuffer:nil]; + [self setSelectedKeyboard:path]; + [self readPersistedOptions]; + if (kvk != nil && self.alwaysShowOSK) + [self showOSK]; } - (NSArray *)KMXFiles { - return [self KMXFilesAtPath:self.keyboardsPath]; + return [self KMXFilesAtPath:self.keyboardsPath]; } - (NSArray *)KMXFilesAtPath:(NSString *)path { - NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:path]; - NSMutableArray *kmxFiles = [[NSMutableArray alloc] initWithCapacity:0]; - NSString *filePath; - while (filePath = (NSString *)[dirEnum nextObject]) { - NSString *extension = [[filePath pathExtension] lowercaseString]; - if ([extension isEqualToString:@"kmx"]) - [kmxFiles addObject:[path stringByAppendingPathComponent:filePath]]; - } - - return kmxFiles; + NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:path]; + NSMutableArray *kmxFiles = [[NSMutableArray alloc] initWithCapacity:0]; + NSString *filePath; + while (filePath = (NSString *)[dirEnum nextObject]) { + NSString *extension = [[filePath pathExtension] lowercaseString]; + if ([extension isEqualToString:@"kmx"]) + [kmxFiles addObject:[path stringByAppendingPathComponent:filePath]]; + } + + return kmxFiles; } - (NSArray *)KVKFiles { - NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:self.keyboardsPath]; - NSMutableArray *kvkFiles = [[NSMutableArray alloc] initWithCapacity:0]; - NSString *filePath; - while (filePath = (NSString *)[dirEnum nextObject]) { - NSString *extension = [[filePath pathExtension] lowercaseString]; - if ([extension isEqualToString:@"kvk"]) - [kvkFiles addObject:[self.keyboardsPath stringByAppendingPathComponent:filePath]]; - } - - return kvkFiles; + NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:self.keyboardsPath]; + NSMutableArray *kvkFiles = [[NSMutableArray alloc] initWithCapacity:0]; + NSString *filePath; + while (filePath = (NSString *)[dirEnum nextObject]) { + NSString *extension = [[filePath pathExtension] lowercaseString]; + if ([extension isEqualToString:@"kvk"]) + [kvkFiles addObject:[self.keyboardsPath stringByAppendingPathComponent:filePath]]; + } + + return kvkFiles; } - (NSString *)kvkFilePathFromFilename:(NSString *)kvkFilename { - NSString *kvkFilePath = nil; - NSArray *kvkFiles = [self KVKFiles]; - for (NSString *filePath in kvkFiles) { - if ([[filePath lastPathComponent] isEqualToString:kvkFilename]) { - kvkFilePath = filePath; - break; - } + NSString *kvkFilePath = nil; + NSArray *kvkFiles = [self KVKFiles]; + for (NSString *filePath in kvkFiles) { + if ([[filePath lastPathComponent] isEqualToString:kvkFilename]) { + kvkFilePath = filePath; + break; } - - return kvkFilePath; + } + + return kvkFilePath; } - (NSWindowController *)oskWindow { - if (!_oskWindow) - _oskWindow = [[OSKWindowController alloc] initWithWindowNibName:@"OSKWindowController"]; - - return _oskWindow; + if (!_oskWindow) + _oskWindow = [[OSKWindowController alloc] initWithWindowNibName:@"OSKWindowController"]; + + return _oskWindow; } - (void)showConfigurationWindow { - if (self.debugMode) - NSLog(@"Showing config window..."); - [self.configWindow.window centerInParent]; - [self.configWindow.window makeKeyAndOrderFront:nil]; - [self.configWindow.window setLevel:NSFloatingWindowLevel]; + if (self.debugMode) + NSLog(@"Showing config window..."); + [self.configWindow.window centerInParent]; + [self.configWindow.window makeKeyAndOrderFront:nil]; + [self.configWindow.window setLevel:NSFloatingWindowLevel]; } - (void)registerConfigurationWindow:(NSWindowController *)window { - _configWindow = window; + _configWindow = window; } - (void)showOSK { - [[self.oskWindow window] makeKeyAndOrderFront:nil]; - [[self.oskWindow window] setLevel:NSStatusWindowLevel]; - [[self.oskWindow window] setTitle:self.oskWindowTitle]; + [[self.oskWindow window] makeKeyAndOrderFront:nil]; + [[self.oskWindow window] setLevel:NSStatusWindowLevel]; + [[self.oskWindow window] setTitle:self.oskWindowTitle]; } - (void)showAboutWindow { - [self.aboutWindow.window centerInParent]; - [self.aboutWindow.window makeKeyAndOrderFront:nil]; - [self.aboutWindow.window setLevel:NSFloatingWindowLevel]; + [self.aboutWindow.window centerInParent]; + [self.aboutWindow.window makeKeyAndOrderFront:nil]; + [self.aboutWindow.window setLevel:NSFloatingWindowLevel]; } /* @@ -1026,66 +1026,66 @@ - (void)showAboutWindow { */ - (NSWindowController *)configWindow { - if (_configWindow.window == nil) { - if (self.debugMode) - NSLog(@"Creating config window..."); - _configWindow = [[KMConfigurationWindowController alloc] initWithWindowNibName:@"preferences"]; - [self observeCloseFor:_configWindow.window]; - } - - return _configWindow; + if (_configWindow.window == nil) { + if (self.debugMode) + NSLog(@"Creating config window..."); + _configWindow = [[KMConfigurationWindowController alloc] initWithWindowNibName:@"preferences"]; + [self observeCloseFor:_configWindow.window]; + } + + return _configWindow; } - (NSWindowController *)aboutWindow_ { - return _aboutWindow; + return _aboutWindow; } - (NSWindowController *)aboutWindow { - if (_aboutWindow.window == nil) { - _aboutWindow = [[KMAboutWindowController alloc] initWithWindowNibName:@"KMAboutWindowController"]; - [self observeCloseFor:_aboutWindow.window]; - } - - return _aboutWindow; + if (_aboutWindow.window == nil) { + _aboutWindow = [[KMAboutWindowController alloc] initWithWindowNibName:@"KMAboutWindowController"]; + [self observeCloseFor:_aboutWindow.window]; + } + + return _aboutWindow; } - (NSWindowController *)infoWindow_ { - return _infoWindow; + return _infoWindow; } - (NSWindowController *)infoWindow { - if (_infoWindow.window == nil) { - _infoWindow = [[KMInfoWindowController alloc] initWithWindowNibName:@"KMInfoWindowController"]; - [self observeCloseFor:_infoWindow.window]; - } - - return _infoWindow; + if (_infoWindow.window == nil) { + _infoWindow = [[KMInfoWindowController alloc] initWithWindowNibName:@"KMInfoWindowController"]; + [self observeCloseFor:_infoWindow.window]; + } + + return _infoWindow; } - (NSWindowController *)kbHelpWindow_ { - return _kbHelpWindow; + return _kbHelpWindow; } - (NSWindowController *)kbHelpWindow { - if (_kbHelpWindow.window == nil) { - _kbHelpWindow = [[KMKeyboardHelpWindowController alloc] initWithWindowNibName:@"KMKeyboardHelpWindowController"]; - [self observeCloseFor:_kbHelpWindow.window]; - } - - return _kbHelpWindow; + if (_kbHelpWindow.window == nil) { + _kbHelpWindow = [[KMKeyboardHelpWindowController alloc] initWithWindowNibName:@"KMKeyboardHelpWindowController"]; + [self observeCloseFor:_kbHelpWindow.window]; + } + + return _kbHelpWindow; } - (NSWindowController *)downloadKBWindow_ { - return _downloadKBWindow; + return _downloadKBWindow; } - (NSWindowController *)downloadKBWindow { - if (_downloadKBWindow.window == nil) { - _downloadKBWindow = [[KMDownloadKBWindowController alloc] initWithWindowNibName:@"KMDownloadKBWindowController"]; - [self observeCloseFor:_downloadKBWindow.window]; - } - - return _downloadKBWindow; + if (_downloadKBWindow.window == nil) { + _downloadKBWindow = [[KMDownloadKBWindowController alloc] initWithWindowNibName:@"KMDownloadKBWindowController"]; + [self observeCloseFor:_downloadKBWindow.window]; + } + + return _downloadKBWindow; } /* @@ -1093,24 +1093,24 @@ - (NSWindowController *)downloadKBWindow { */ - (void)observeCloseFor:(NSWindow *)window { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(windowWillClose:) - name:NSWindowWillCloseNotification - object:window]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification + object:window]; } - (void)windowWillClose:(NSNotification *)notification { - NSWindow* window = notification.object; - if (window == _downloadKBWindow.window) { - _downloadKBWindow.window = nil; - } else if(window == _kbHelpWindow.window) { - _kbHelpWindow.window = nil; - } else if(window == _infoWindow.window) { - _infoWindow.window = nil; - } else if(window == _configWindow.window) { - _configWindow.window = nil; - } - [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:window]; + NSWindow* window = notification.object; + if (window == _downloadKBWindow.window) { + _downloadKBWindow.window = nil; + } else if(window == _kbHelpWindow.window) { + _kbHelpWindow.window = nil; + } else if(window == _infoWindow.window) { + _infoWindow.window = nil; + } else if(window == _configWindow.window) { + _configWindow.window = nil; + } + [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:window]; } /* @@ -1119,165 +1119,165 @@ - (void)windowWillClose:(NSNotification *)notification { */ - (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { - NSButton *button = (NSButton *)[alert.buttons objectAtIndex:0]; - if (button.tag == -1) { - [_connection cancel]; + NSButton *button = (NSButton *)[alert.buttons objectAtIndex:0]; + if (button.tag == -1) { + [_connection cancel]; + } + else if (button.tag == 1) { + [_downloadKBWindow close]; + if (self.configWindow.window != nil) { + [self.configWindow.window makeKeyAndOrderFront:nil]; + if (![[self.configWindow.window childWindows] containsObject:self.infoWindow.window]) { + [self.configWindow.window addChildWindow:self.infoWindow.window ordered:NSWindowAbove]; + } + [self.infoWindow.window centerInParent]; + [self.infoWindow.window makeKeyAndOrderFront:nil]; } - else if (button.tag == 1) { - [_downloadKBWindow close]; - if (self.configWindow.window != nil) { - [self.configWindow.window makeKeyAndOrderFront:nil]; - if (![[self.configWindow.window childWindows] containsObject:self.infoWindow.window]) { - [self.configWindow.window addChildWindow:self.infoWindow.window ordered:NSWindowAbove]; - } - [self.infoWindow.window centerInParent]; - [self.infoWindow.window makeKeyAndOrderFront:nil]; - } - else { - [self.infoWindow.window centerInParent]; - [self.infoWindow.window makeKeyAndOrderFront:nil]; - [self.infoWindow.window setLevel:NSFloatingWindowLevel]; - } - - NSString *packagePath = [self.keyboardsPath stringByAppendingPathComponent:[self.downloadFilename stringByDeletingPathExtension]]; - [self.infoWindow setPackagePath:packagePath]; + else { + [self.infoWindow.window centerInParent]; + [self.infoWindow.window makeKeyAndOrderFront:nil]; + [self.infoWindow.window setLevel:NSFloatingWindowLevel]; } - - _downloadInfoView = nil; - _connection = nil; - _downloadFilename = nil; - _receivedData = nil; - _expectedBytes = 0; + + NSString *packagePath = [self.keyboardsPath stringByAppendingPathComponent:[self.downloadFilename stringByDeletingPathExtension]]; + [self.infoWindow setPackagePath:packagePath]; + } + + _downloadInfoView = nil; + _connection = nil; + _downloadFilename = nil; + _receivedData = nil; + _expectedBytes = 0; } - (NSAlert *)downloadInfoView { - if (_downloadInfoView == nil) { - _downloadInfoView = [[NSAlert alloc] init]; - [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)]; - [_downloadInfoView setInformativeText:@""]; - [_downloadInfoView addButtonWithTitle:NSLocalizedString(@"button-cancel-downloading", nil)]; - [_downloadInfoView setAlertStyle:NSAlertStyleInformational]; - [_downloadInfoView setAccessoryView:self.progressIndicator]; - } - - return _downloadInfoView; + if (_downloadInfoView == nil) { + _downloadInfoView = [[NSAlert alloc] init]; + [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)]; + [_downloadInfoView setInformativeText:@""]; + [_downloadInfoView addButtonWithTitle:NSLocalizedString(@"button-cancel-downloading", nil)]; + [_downloadInfoView setAlertStyle:NSAlertStyleInformational]; + [_downloadInfoView setAccessoryView:self.progressIndicator]; + } + + return _downloadInfoView; } - (NSProgressIndicator *)progressIndicator { - if (_progressIndicator == nil) { - _progressIndicator = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0, 0, 300, 20)]; - [_progressIndicator setIndeterminate:NO]; - [_progressIndicator setMinValue:0]; - [_progressIndicator setMaxValue:100]; - [_progressIndicator setDoubleValue:0]; - } - - return _progressIndicator; + if (_progressIndicator == nil) { + _progressIndicator = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0, 0, 300, 20)]; + [_progressIndicator setIndeterminate:NO]; + [_progressIndicator setMinValue:0]; + [_progressIndicator setMaxValue:100]; + [_progressIndicator setDoubleValue:0]; + } + + return _progressIndicator; } - (void)downloadKeyboardFromKeyboardId:(NSString *)keyboardId { - KeymanVersionInfo keymanVersionInfo = [self versionInfo]; - NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@/go/package/download/%@?platform=macos&tier=%@", - keymanVersionInfo.keymanCom, keyboardId, keymanVersionInfo.tier]]; //&bcp47=%@&update=0 - _downloadFilename = [NSString stringWithFormat:@"%@.kmp", keyboardId]; - [self downloadKeyboardFromURL:url]; + KeymanVersionInfo keymanVersionInfo = [self versionInfo]; + NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@/go/package/download/%@?platform=macos&tier=%@", + keymanVersionInfo.keymanCom, keyboardId, keymanVersionInfo.tier]]; //&bcp47=%@&update=0 + _downloadFilename = [NSString stringWithFormat:@"%@.kmp", keyboardId]; + [self downloadKeyboardFromURL:url]; } - (void)downloadKeyboardFromURL:(NSURL *)url { - NSURL* downloadUrl = url; - - if (downloadUrl && _downloadFilename) { - if (_infoWindow.window != nil) - [_infoWindow close]; - - [self.downloadInfoView setInformativeText:self.downloadFilename]; - if (self.configWindow.window != nil) { - [self.configWindow.window makeKeyAndOrderFront:nil]; - if (![[self.configWindow.window childWindows] containsObject:self.downloadKBWindow.window]) { - [self.configWindow.window addChildWindow:self.downloadKBWindow.window ordered:NSWindowAbove]; - } - [self.downloadKBWindow.window centerInParent]; - [self.downloadKBWindow.window makeKeyAndOrderFront:nil]; - [self.downloadInfoView beginSheetModalForWindow:self.downloadKBWindow.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; - } - else { - [self.downloadKBWindow.window centerInParent]; - [self.downloadKBWindow.window makeKeyAndOrderFront:nil]; - [self.downloadKBWindow.window setLevel:NSFloatingWindowLevel]; - [self.downloadInfoView beginSheetModalForWindow:self.downloadKBWindow.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; - } - - if (_connection == nil) { - [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)]; - NSButton *button = (NSButton *)[_downloadInfoView.buttons objectAtIndex:0]; - [button setTitle:NSLocalizedString(@"button-cancel-downloading", nil)]; - [button setTag:-1]; - [self.progressIndicator setDoubleValue:0]; - NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60]; - _receivedData = [[NSMutableData alloc] initWithLength:0]; - _connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; - } - + NSURL* downloadUrl = url; + + if (downloadUrl && _downloadFilename) { + if (_infoWindow.window != nil) + [_infoWindow close]; + + [self.downloadInfoView setInformativeText:self.downloadFilename]; + if (self.configWindow.window != nil) { + [self.configWindow.window makeKeyAndOrderFront:nil]; + if (![[self.configWindow.window childWindows] containsObject:self.downloadKBWindow.window]) { + [self.configWindow.window addChildWindow:self.downloadKBWindow.window ordered:NSWindowAbove]; + } + [self.downloadKBWindow.window centerInParent]; + [self.downloadKBWindow.window makeKeyAndOrderFront:nil]; + [self.downloadInfoView beginSheetModalForWindow:self.downloadKBWindow.window + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; + } + else { + [self.downloadKBWindow.window centerInParent]; + [self.downloadKBWindow.window makeKeyAndOrderFront:nil]; + [self.downloadKBWindow.window setLevel:NSFloatingWindowLevel]; + [self.downloadInfoView beginSheetModalForWindow:self.downloadKBWindow.window + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; } + + if (_connection == nil) { + [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)]; + NSButton *button = (NSButton *)[_downloadInfoView.buttons objectAtIndex:0]; + [button setTitle:NSLocalizedString(@"button-cancel-downloading", nil)]; + [button setTag:-1]; + [self.progressIndicator setDoubleValue:0]; + NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60]; + _receivedData = [[NSMutableData alloc] initWithLength:0]; + _connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; + } + + } } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { - [self.receivedData setLength:0]; - self.expectedBytes = [response expectedContentLength]; + [self.receivedData setLength:0]; + self.expectedBytes = [response expectedContentLength]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { - [self.receivedData appendData:data]; - float progress = ((float)[self.receivedData length]/(float)self.expectedBytes)*100; - [self.progressIndicator setDoubleValue:progress]; + [self.receivedData appendData:data]; + float progress = ((float)[self.receivedData length]/(float)self.expectedBytes)*100; + [self.progressIndicator setDoubleValue:progress]; } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - _connection = nil; - _downloadFilename = nil; - _receivedData = nil; - _expectedBytes = 0; + _connection = nil; + _downloadFilename = nil; + _receivedData = nil; + _expectedBytes = 0; } - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(nonnull NSURLRequest *)request redirectResponse:(nullable NSURLResponse *)response { - return request; + return request; } - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { - return nil; + return nil; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { - NSString *filePath = [self.keyboardsPath stringByAppendingPathComponent:self.downloadFilename]; - [self.receivedData writeToFile:filePath atomically:YES]; - [self unzipFile:filePath]; - [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil]; - - [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-download-complete", nil)]; - NSButton *button = (NSButton *)[_downloadInfoView.buttons objectAtIndex:0]; - [button setTitle:NSLocalizedString(@"button-download-complete", nil)]; - [button setTag:1]; - [[NSNotificationCenter defaultCenter] postNotificationName:kKeymanKeyboardDownloadCompletedNotification - object:self - userInfo:nil]; - _connection = nil; - _receivedData = nil; - _expectedBytes = 0; + NSString *filePath = [self.keyboardsPath stringByAppendingPathComponent:self.downloadFilename]; + [self.receivedData writeToFile:filePath atomically:YES]; + [self unzipFile:filePath]; + [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil]; + + [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-download-complete", nil)]; + NSButton *button = (NSButton *)[_downloadInfoView.buttons objectAtIndex:0]; + [button setTitle:NSLocalizedString(@"button-download-complete", nil)]; + [button setTag:1]; + [[NSNotificationCenter defaultCenter] postNotificationName:kKeymanKeyboardDownloadCompletedNotification + object:self + userInfo:nil]; + _connection = nil; + _receivedData = nil; + _expectedBytes = 0; } - (void)handleKeyEvent:(NSEvent *)event { - if (_oskWindow == nil) - return; - - [_oskWindow.oskView handleKeyEvent:event]; + if (_oskWindow == nil) + return; + + [_oskWindow.oskView handleKeyEvent:event]; } extern const CGKeyCode kProcessPendingBuffer; @@ -1286,177 +1286,177 @@ - (void)handleKeyEvent:(NSEvent *)event { // allows us to override the norma behavior for unit testing, where there is no // active event loop to post to. - (void)postKeyboardEventWithSource: (CGEventSourceRef)source code:(CGKeyCode) virtualKey postCallback:(PostEventCallback)postEvent{ - - CGEventRef ev = CGEventCreateKeyboardEvent (source, virtualKey, true); //down - if (postEvent) { - NSLog(@"postKeyboardEventWithSource, keycode: %d", virtualKey); + + CGEventRef ev = CGEventCreateKeyboardEvent (source, virtualKey, true); //down + if (postEvent) { + NSLog(@"postKeyboardEventWithSource, keycode: %d", virtualKey); + postEvent(ev); + } + CFRelease(ev); + if (virtualKey != kProcessPendingBuffer) { // special 0xFF code is not a real key-press, so no "up" is needed + ev = CGEventCreateKeyboardEvent (source, virtualKey, false); //up + if (postEvent) postEvent(ev); - } CFRelease(ev); - if (virtualKey != kProcessPendingBuffer) { // special 0xFF code is not a real key-press, so no "up" is needed - ev = CGEventCreateKeyboardEvent (source, virtualKey, false); //up - if (postEvent) - postEvent(ev); - CFRelease(ev); - } + } } // Check the package info to ensure that we support this version // (e.g. Keyman 15 does not support a 16.0 version package) - (BOOL)verifyPackageVersionInTempFolder: (NSString *)tempDestFolder filePath:(NSString *)filePath { - KMPackageInfo *packageInfo = [self loadPackageInfo:tempDestFolder]; - if(packageInfo == nil) { - NSLog(@"Could not find kmp.json in %@", filePath); + KMPackageInfo *packageInfo = [self loadPackageInfo:tempDestFolder]; + if(packageInfo == nil) { + NSLog(@"Could not find kmp.json in %@", filePath); + } else { + NSString* requiredVersion = [packageInfo.fileVersion minimalVersionNumberString]; + KeymanVersionInfo keymanVersionInfo = [self versionInfo]; + NSString *currentVersion = [keymanVersionInfo.versionRelease minimalVersionNumberString]; + + if ([requiredVersion compare:currentVersion options:NSNumericSearch] == NSOrderedDescending) { + // currentVersion is lower than the requiredVersion + NSLog(@"Package %@ requires a newer version of Keyman: %@", filePath, requiredVersion); } else { - NSString* requiredVersion = [packageInfo.fileVersion minimalVersionNumberString]; - KeymanVersionInfo keymanVersionInfo = [self versionInfo]; - NSString *currentVersion = [keymanVersionInfo.versionRelease minimalVersionNumberString]; - - if ([requiredVersion compare:currentVersion options:NSNumericSearch] == NSOrderedDescending) { - // currentVersion is lower than the requiredVersion - NSLog(@"Package %@ requires a newer version of Keyman: %@", filePath, requiredVersion); - } else { - return YES; - } + return YES; } + } return NO; } // TODO: This seriously needs to be refactored out of the app delegate and into // a keyboard install module - (BOOL)unzipFile:(NSString *)filePath { - BOOL didUnzip = NO; - NSError *error = nil; - NSString *fileName = filePath.lastPathComponent; - NSString *folderName = [fileName stringByDeletingPathExtension]; - - // First we unzip into a temp folder, and check kmp.json for the fileVersion - // before we continue installation. We don't want to overwrite existing - // package if it is there if the files are not compatible with the installed - // version of Keyman. - - NSString *tempFolderName = [folderName stringByAppendingString:@".tmp.install"]; - NSString *tempDestFolder = [self.keyboardsPath stringByAppendingPathComponent:tempFolderName]; - - ZipArchive *za = [[ZipArchive alloc] init]; - if ([za UnzipOpenFile:filePath]) { - if (self.debugMode) { - NSLog(@"Unzipping %@ to %@", filePath, tempDestFolder); - if ([[NSFileManager defaultManager] fileExistsAtPath:tempDestFolder]) - NSLog(@"The temp destination folder already exists. Overwriting..."); - } - - didUnzip = [za UnzipFileTo:tempDestFolder overWrite:YES]; - [za UnzipCloseFile]; - } - - if (!didUnzip) { - NSLog(@"Failed to unzip file: %@", filePath); - return NO; + BOOL didUnzip = NO; + NSError *error = nil; + NSString *fileName = filePath.lastPathComponent; + NSString *folderName = [fileName stringByDeletingPathExtension]; + + // First we unzip into a temp folder, and check kmp.json for the fileVersion + // before we continue installation. We don't want to overwrite existing + // package if it is there if the files are not compatible with the installed + // version of Keyman. + + NSString *tempFolderName = [folderName stringByAppendingString:@".tmp.install"]; + NSString *tempDestFolder = [self.keyboardsPath stringByAppendingPathComponent:tempFolderName]; + + ZipArchive *za = [[ZipArchive alloc] init]; + if ([za UnzipOpenFile:filePath]) { + if (self.debugMode) { + NSLog(@"Unzipping %@ to %@", filePath, tempDestFolder); + if ([[NSFileManager defaultManager] fileExistsAtPath:tempDestFolder]) + NSLog(@"The temp destination folder already exists. Overwriting..."); } - - if (self.debugMode) - NSLog(@"Unzipped file: %@", filePath); - - BOOL didInstall = [self verifyPackageVersionInTempFolder:tempDestFolder filePath:filePath]; - - NSString *destFolder = [self.keyboardsPath stringByAppendingPathComponent:folderName]; - - // Remove existing package if it exists - if (didInstall && [[NSFileManager defaultManager] fileExistsAtPath:destFolder]) { - if(self.debugMode) { - NSLog(@"The destination folder already exists. Overwriting..."); - } - [[NSFileManager defaultManager] removeItemAtPath:destFolder error:&error]; - if (error != nil) { - NSLog(@"Unable to remove destination folder %@", destFolder); - didInstall = NO; - } + + didUnzip = [za UnzipFileTo:tempDestFolder overWrite:YES]; + [za UnzipCloseFile]; + } + + if (!didUnzip) { + NSLog(@"Failed to unzip file: %@", filePath); + return NO; + } + + if (self.debugMode) + NSLog(@"Unzipped file: %@", filePath); + + BOOL didInstall = [self verifyPackageVersionInTempFolder:tempDestFolder filePath:filePath]; + + NSString *destFolder = [self.keyboardsPath stringByAppendingPathComponent:folderName]; + + // Remove existing package if it exists + if (didInstall && [[NSFileManager defaultManager] fileExistsAtPath:destFolder]) { + if(self.debugMode) { + NSLog(@"The destination folder already exists. Overwriting..."); } - - // - // We believe this package is valid, let's go ahead and install it - // - - // Rename the temp folder to the desired dest folder. removing existing folder first - if(didInstall) { - [[NSFileManager defaultManager] moveItemAtPath:tempDestFolder toPath:destFolder error:&error]; - if (error != nil) { - NSLog(@"Unable to move temp folder %@ to dest folder %@", tempDestFolder, destFolder); - didInstall = NO; - } + [[NSFileManager defaultManager] removeItemAtPath:destFolder error:&error]; + if (error != nil) { + NSLog(@"Unable to remove destination folder %@", destFolder); + didInstall = NO; } - - if(!didInstall) { - [[NSFileManager defaultManager] removeItemAtPath:tempDestFolder error:&error]; - if (error != nil) { - NSLog(@"Unable to remove temp folder %@", tempDestFolder); - } - - return NO; + } + + // + // We believe this package is valid, let's go ahead and install it + // + + // Rename the temp folder to the desired dest folder. removing existing folder first + if(didInstall) { + [[NSFileManager defaultManager] moveItemAtPath:tempDestFolder toPath:destFolder error:&error]; + if (error != nil) { + NSLog(@"Unable to move temp folder %@ to dest folder %@", tempDestFolder, destFolder); + didInstall = NO; } - - // Package has installed, now scan for keyboards and fonts - // TODO: we need to be reading the kmp.json data to determine keyboards to install - NSString * keyboardFolderPath = [self.keyboardsPath stringByAppendingPathComponent:folderName]; - [self installFontsAtPath:keyboardFolderPath]; - for (NSString *kmxFile in [self KMXFilesAtPath:keyboardFolderPath]) { - if (self.debugMode) - NSLog(@"Adding keyboard to list of active keyboards: %@", kmxFile); - if (![self.activeKeyboards containsObject:kmxFile]) - [self.activeKeyboards addObject:kmxFile]; + } + + if(!didInstall) { + [[NSFileManager defaultManager] removeItemAtPath:tempDestFolder error:&error]; + if (error != nil) { + NSLog(@"Unable to remove temp folder %@", tempDestFolder); } - [self saveActiveKeyboards]; - - return YES; + + return NO; + } + + // Package has installed, now scan for keyboards and fonts + // TODO: we need to be reading the kmp.json data to determine keyboards to install + NSString * keyboardFolderPath = [self.keyboardsPath stringByAppendingPathComponent:folderName]; + [self installFontsAtPath:keyboardFolderPath]; + for (NSString *kmxFile in [self KMXFilesAtPath:keyboardFolderPath]) { + if (self.debugMode) + NSLog(@"Adding keyboard to list of active keyboards: %@", kmxFile); + if (![self.activeKeyboards containsObject:kmxFile]) + [self.activeKeyboards addObject:kmxFile]; + } + [self saveActiveKeyboards]; + + return YES; } - (NSString *)fontsPath { - if (_fontsPath == nil) { - BOOL isDir; - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); - - if (paths.count == 1) { - NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Fonts"]; - if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir] && isDir) - _fontsPath = [NSString stringWithString:path]; - } + if (_fontsPath == nil) { + BOOL isDir; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); + + if (paths.count == 1) { + NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Fonts"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir] && isDir) + _fontsPath = [NSString stringWithString:path]; } - - return _fontsPath; + } + + return _fontsPath; } - (void)installFontsAtPath:(NSString *)path { - NSString *fontsPath = self.fontsPath; - if (fontsPath == nil) - return; - - NSArray *fonts = [self FontFilesAtPath:path]; - for (NSString *srcPath in fonts) { - NSString *destPath = [fontsPath stringByAppendingPathComponent:[srcPath lastPathComponent]]; - NSError *error; - if ([[NSFileManager defaultManager] fileExistsAtPath:destPath]) - [[NSFileManager defaultManager] removeItemAtPath:destPath error:&error]; - - if (error == nil) - [[NSFileManager defaultManager] copyItemAtPath:srcPath toPath:destPath error:&error]; - - if (error != nil) - NSLog(@"Error = %@", error); - } + NSString *fontsPath = self.fontsPath; + if (fontsPath == nil) + return; + + NSArray *fonts = [self FontFilesAtPath:path]; + for (NSString *srcPath in fonts) { + NSString *destPath = [fontsPath stringByAppendingPathComponent:[srcPath lastPathComponent]]; + NSError *error; + if ([[NSFileManager defaultManager] fileExistsAtPath:destPath]) + [[NSFileManager defaultManager] removeItemAtPath:destPath error:&error]; + + if (error == nil) + [[NSFileManager defaultManager] copyItemAtPath:srcPath toPath:destPath error:&error]; + + if (error != nil) + NSLog(@"Error = %@", error); + } } - (NSArray *)FontFilesAtPath:(NSString *)path { - NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:path]; - NSMutableArray *fontFiles = [[NSMutableArray alloc] initWithCapacity:0]; - NSString *filePath; - while (filePath = (NSString *)[dirEnum nextObject]) { - NSString *extension = [[filePath pathExtension] lowercaseString]; - if ([extension isEqualToString:@"ttf"] || [extension isEqualToString:@"otf"]) - [fontFiles addObject:[path stringByAppendingPathComponent:filePath]]; - } - - return fontFiles; + NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:path]; + NSMutableArray *fontFiles = [[NSMutableArray alloc] initWithCapacity:0]; + NSString *filePath; + while (filePath = (NSString *)[dirEnum nextObject]) { + NSString *extension = [[filePath pathExtension] lowercaseString]; + if ([extension isEqualToString:@"ttf"] || [extension isEqualToString:@"otf"]) + [fontFiles addObject:[path stringByAppendingPathComponent:filePath]]; + } + + return fontFiles; } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m index f41120f0d03..b7c4cb98954 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m @@ -37,46 +37,46 @@ @implementation KMInputMethodEventHandler // This is the public initializer. - (instancetype)initWithClient:(NSString *)clientAppId client:(id) sender { - _keySender = [[KeySender alloc] init]; - _clientApplicationId = clientAppId; - _generatedBackspaceCount = 0; - _lowLevelBackspaceCount = 0; - _queuedText = nil; - - // In Xcode, if Keyman is the active IM and is in "debugMode" and "English plus Spanish" is - // the current keyboard and you type "Sentry force now", it will force a simulated crash to - // test reporting to sentry.keyman.com - if ([self.appDelegate debugMode] && [clientAppId isEqual: @"com.apple.dt.Xcode"]) { - NSLog(@"Sentry - Preparing to detect Easter egg."); - _easterEggForSentry = [[NSMutableString alloc] init]; - } - else - _easterEggForSentry = nil; - + _keySender = [[KeySender alloc] init]; + _clientApplicationId = clientAppId; + _generatedBackspaceCount = 0; + _lowLevelBackspaceCount = 0; + _queuedText = nil; + + // In Xcode, if Keyman is the active IM and is in "debugMode" and "English plus Spanish" is + // the current keyboard and you type "Sentry force now", it will force a simulated crash to + // test reporting to sentry.keyman.com + if ([self.appDelegate debugMode] && [clientAppId isEqual: @"com.apple.dt.Xcode"]) { + NSLog(@"Sentry - Preparing to detect Easter egg."); + _easterEggForSentry = [[NSMutableString alloc] init]; + } + else + _easterEggForSentry = nil; + return self; } - (void)deactivate { - if (_generatedBackspaceCount > 0 || (_queuedText != nil && _queuedText.length > 0) || - _keyCodeOfOriginalEvent != 0 || _sourceFromOriginalEvent != nil) - { - if ([self.appDelegate debugMode]) { - NSLog(@"ERROR: new app activated before previous app finished processing pending events!"); - NSLog(@" _generatedBackspaceCount = %lu", _generatedBackspaceCount); - NSLog(@" _queuedText = \"%@\"", _queuedText == nil ? @"(NIL)" : (NSString*)[self queuedText]); - NSLog(@" _keyCodeOfOriginalEvent = %hu", _keyCodeOfOriginalEvent); - } - _keyCodeOfOriginalEvent = 0; - _generatedBackspaceCount = 0; - _queuedText = nil; + if (_generatedBackspaceCount > 0 || (_queuedText != nil && _queuedText.length > 0) || + _keyCodeOfOriginalEvent != 0 || _sourceFromOriginalEvent != nil) + { + if ([self.appDelegate debugMode]) { + NSLog(@"ERROR: new app activated before previous app finished processing pending events!"); + NSLog(@" _generatedBackspaceCount = %lu", _generatedBackspaceCount); + NSLog(@" _queuedText = \"%@\"", _queuedText == nil ? @"(NIL)" : (NSString*)[self queuedText]); + NSLog(@" _keyCodeOfOriginalEvent = %hu", _keyCodeOfOriginalEvent); } + _keyCodeOfOriginalEvent = 0; + _generatedBackspaceCount = 0; + _queuedText = nil; + } } - (void)dealloc { - if (_sourceFromOriginalEvent != nil) { - CFRelease(_sourceFromOriginalEvent); - _sourceFromOriginalEvent = nil; - } + if (_sourceFromOriginalEvent != nil) { + CFRelease(_sourceFromOriginalEvent); + _sourceFromOriginalEvent = nil; + } if (_sourceForGeneratedEvent != nil) { CFRelease(_sourceForGeneratedEvent); _sourceForGeneratedEvent = nil; @@ -84,33 +84,33 @@ - (void)dealloc { } - (void)handleCommand:(NSEvent *)event { - // There are a bunch of common navigation/selection command-key combinations, but individual - // apps may implement specific commands that also change the selection. There is probably no - // situation where a user could reasonably hope that any dead-keys typed before using a - // command shortcut would be remembered, so other than an insignificant performance penalty, - // the only downside to treating all commands as having the potential to change the selection - // is that some non-compliant apps can't get their context at all. This can be overridden so that - // non-compliant apps can mitigate this problem as appropriate. - [self.appDelegate logDebugMessage:@"KMInputMethodEventHandler handleCommand, event type=%@, must refresh context", event.type]; - self.contextChanged = YES; + // There are a bunch of common navigation/selection command-key combinations, but individual + // apps may implement specific commands that also change the selection. There is probably no + // situation where a user could reasonably hope that any dead-keys typed before using a + // command shortcut would be remembered, so other than an insignificant performance penalty, + // the only downside to treating all commands as having the potential to change the selection + // is that some non-compliant apps can't get their context at all. This can be overridden so that + // non-compliant apps can mitigate this problem as appropriate. + [self.appDelegate logDebugMessage:@"KMInputMethodEventHandler handleCommand, event type=%@, must refresh context", event.type]; + self.contextChanged = YES; } - (KMInputMethodAppDelegate *)appDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; + return (KMInputMethodAppDelegate *)[NSApp delegate]; } - (KMEngine *)kme { - return self.appDelegate.kme; + return self.appDelegate.kme; } - (BOOL) handleEventWithKeymanEngine:(NSEvent *)event in:(id) sender { [self.appDelegate logDebugMessage:@"handleEventWithKeymanEngine, event = %@", event]; CoreKeyOutput *output = nil; - + output = [self processEventWithKeymanEngine:event in:sender]; if (output == nil) { - [self checkEventForSentryEasterEgg:event]; - return NO; + [self checkEventForSentryEasterEgg:event]; + return NO; } return [self applyKeymanCoreActions:output event:event client:sender]; @@ -119,15 +119,15 @@ - (BOOL) handleEventWithKeymanEngine:(NSEvent *)event in:(id) sender { - (CoreKeyOutput*) processEventWithKeymanEngine:(NSEvent *)event in:(id) sender { CoreKeyOutput* coreKeyOutput = nil; if (self.appDelegate.lowLevelEventTap != nil) { - NSEvent *eventWithOriginalModifierFlags = [NSEvent keyEventWithType:event.type location:event.locationInWindow modifierFlags:self.appDelegate.currentModifierFlags timestamp:event.timestamp windowNumber:event.windowNumber context:[NSGraphicsContext currentContext] characters:event.characters charactersIgnoringModifiers:event.charactersIgnoringModifiers isARepeat:event.isARepeat keyCode:event.keyCode]; - coreKeyOutput = [self.kme processEvent:eventWithOriginalModifierFlags]; - [self.appDelegate logDebugMessage:@"processEventWithKeymanEngine, using AppDelegate.currentModifierFlags %lu, instead of event.modifiers = %lu", (unsigned long)self.appDelegate.currentModifierFlags, (unsigned long)event.modifierFlags]; + NSEvent *eventWithOriginalModifierFlags = [NSEvent keyEventWithType:event.type location:event.locationInWindow modifierFlags:self.appDelegate.currentModifierFlags timestamp:event.timestamp windowNumber:event.windowNumber context:[NSGraphicsContext currentContext] characters:event.characters charactersIgnoringModifiers:event.charactersIgnoringModifiers isARepeat:event.isARepeat keyCode:event.keyCode]; + coreKeyOutput = [self.kme processEvent:eventWithOriginalModifierFlags]; + [self.appDelegate logDebugMessage:@"processEventWithKeymanEngine, using AppDelegate.currentModifierFlags %lu, instead of event.modifiers = %lu", (unsigned long)self.appDelegate.currentModifierFlags, (unsigned long)event.modifierFlags]; } else { - // Depending on the client app and the keyboard, using the passed-in event as it is should work okay. - // Keyboards that depend on chirality support will not work. And command-key actions that change the - // context might go undetected in some apps, resulting in errant behavior for subsequent typing. - coreKeyOutput = [self.kme processEvent:event]; + // Depending on the client app and the keyboard, using the passed-in event as it is should work okay. + // Keyboards that depend on chirality support will not work. And command-key actions that change the + // context might go undetected in some apps, resulting in errant behavior for subsequent typing. + coreKeyOutput = [self.kme processEvent:event]; } [self.appDelegate logDebugMessage:@"processEventWithKeymanEngine, coreKeyOutput = %@", coreKeyOutput]; return coreKeyOutput; @@ -135,25 +135,25 @@ - (CoreKeyOutput*) processEventWithKeymanEngine:(NSEvent *)event in:(id) sender - (void)checkEventForSentryEasterEgg:(NSEvent *)event { if (_easterEggForSentry != nil) { - NSString * kmxName = [[self.kme.kmx filePath] lastPathComponent]; - NSLog(@"Sentry - KMX name: %@", kmxName); - if ([kmxName isEqualToString:kEasterEggKmxName]) { - NSUInteger len = [_easterEggForSentry length]; - NSLog(@"Sentry - Processing character(s): %@", [event characters]); - if ([[event characters] characterAtIndex:0] == [kEasterEggText characterAtIndex:len]) { - NSString *characterToAdd = [kEasterEggText substringWithRange:NSMakeRange(len, 1)]; - NSLog(@"Sentry - Adding character to Easter Egg code string: %@", characterToAdd); - [_easterEggForSentry appendString:characterToAdd]; - if ([_easterEggForSentry isEqualToString:kEasterEggText]) { - NSLog(@"Sentry - Forcing crash now"); - [SentrySDK crash]; - } - } - else if (len > 0) { - NSLog(@"Sentry - Clearing Easter Egg code string."); - [_easterEggForSentry setString:@""]; - } + NSString * kmxName = [[self.kme.kmx filePath] lastPathComponent]; + NSLog(@"Sentry - KMX name: %@", kmxName); + if ([kmxName isEqualToString:kEasterEggKmxName]) { + NSUInteger len = [_easterEggForSentry length]; + NSLog(@"Sentry - Processing character(s): %@", [event characters]); + if ([[event characters] characterAtIndex:0] == [kEasterEggText characterAtIndex:len]) { + NSString *characterToAdd = [kEasterEggText substringWithRange:NSMakeRange(len, 1)]; + NSLog(@"Sentry - Adding character to Easter Egg code string: %@", characterToAdd); + [_easterEggForSentry appendString:characterToAdd]; + if ([_easterEggForSentry isEqualToString:kEasterEggText]) { + NSLog(@"Sentry - Forcing crash now"); + [SentrySDK crash]; + } } + else if (len > 0) { + NSLog(@"Sentry - Clearing Easter Egg code string."); + [_easterEggForSentry setString:@""]; + } + } } } @@ -165,7 +165,7 @@ - (void)checkEventForSentryEasterEgg:(NSEvent *)event { processing a backspace here so that we do not process it again in handleEvent. Note that a backspace that we handle here should never be passed on to Keyman Core for processing, as it is already the result of processing. -*/ + */ - (void)handleBackspace:(NSEvent *)event { [self.appDelegate logDebugMessage:@"KMInputMethodEventHandler handleBackspace, event = %@", event]; @@ -175,7 +175,7 @@ - (void)handleBackspace:(NSEvent *)event { // if we just encountered the last backspace, then send event to insert queued text if ((self.generatedBackspaceCount == 0) && (self.queuedText.length > 0)) { - [self performSelector:@selector(triggerInsertQueuedText:) withObject:event afterDelay:kQueuedTextEventDelayInSeconds]; + [self performSelector:@selector(triggerInsertQueuedText:) withObject:event afterDelay:kQueuedTextEventDelayInSeconds]; } } } @@ -217,17 +217,17 @@ - (void) handleContextChangedByLowLevelEvent { - (BOOL)handleEvent:(NSEvent *)event client:(id)sender { BOOL handled = NO; [self.appDelegate logDebugMessage:@"handleEvent event = %@", event]; - + [self checkTextApiCompliance:sender]; // mouse movement requires that the context be invalidated [self handleContextChangedByLowLevelEvent]; - + if (event.type == NSEventTypeKeyDown) { // indicates that our generated backspace event(s) are consumed // and we can insert text that followed the backspace(s) if (event.keyCode == kKeymanEventKeyCode) { - [self.appDelegate logDebugMessage:@"handleEvent, handling kKeymanEventKeyCode"]; + [self.appDelegate logDebugMessage:@"handleEvent, handling kKeymanEventKeyCode"]; [self insertQueuedText: event client:sender]; return YES; } @@ -247,17 +247,17 @@ - (BOOL)handleEvent:(NSEvent *)event client:(id)sender { [self handleFlagsChangedEvent:[event keyCode]]; return NO; } - + if ((event.modifierFlags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand) { [self handleCommand:event]; return NO; // let the client app handle all Command-key events. } - + if (event.type == NSEventTypeKeyDown) { [self reportContext:event forClient:sender]; handled = [self handleEventWithKeymanEngine:event in: sender]; } - + [self.appDelegate logDebugMessage:@"event, keycode: %u, characters='%@' handled = %@", event.keyCode, event.characters, handled?@"yes":@"no"]; return handled; } @@ -288,7 +288,7 @@ -(void)handleFlagsChangedEvent:(short)keyCode { */ -(void)reportContext:(NSEvent *)event forClient:(id) client { NSString *contextString = nil; - + // if we can read the text, then get the context and send it to Core // we do this whether the context has changed or not if (self.apiCompliance.canReadText) { @@ -296,7 +296,7 @@ -(void)reportContext:(NSEvent *)event forClient:(id) client { [self.appDelegate logDebugMessage:@"reportContext, setting new context='%@' for compliant app (if needed)", contextString]; [self.kme setCoreContextIfNeeded:contextString]; } else if (self.contextChanged) { - // we cannot read the text but know the context has changed, so we must clear it + // we cannot read the text but know the context has changed, so we must clear it [self.appDelegate logDebugMessage:@"reportContext, clearing context for non-compliant app"]; [self.kme clearCoreContext]; } @@ -319,7 +319,7 @@ -(NSString*)readContext:(NSEvent *)event forClient:(id) client { [self.appDelegate logDebugMessage:@" *** InputMethodEventHandler readContext, %d characters", contextLength]; NSRange contextRange = NSMakeRange(contextStart, contextLength); attributedString = [client attributedSubstringFromRange:contextRange]; - + // adjust string in case that we receive half of a surrogate pair at context start // the API appears to always return a full code point, but this could vary by app if (attributedString.length > 0) { @@ -340,19 +340,19 @@ -(NSString*)readContext:(NSEvent *)event forClient:(id) client { * Returns NO if we have not applied an event to the client or if Keyman Core determines that we should emit the keystroke */ -(BOOL)applyKeymanCoreActions:(CoreKeyOutput*)output event: (NSEvent*)event client:(id) client { - [self.appDelegate logDebugMessage:@" *** InputMethodEventHandler applyKeymanCoreActions: output = %@ ", output]; - - BOOL handledEvent = [self applyKeyOutputToTextInputClient:output keyDownEvent:event client:client]; - [self applyNonTextualOutput:output]; - - // if output from Keyman Core indicates to emit the keystroke, - // then return NO, so that the OS still handles the event - if (handledEvent && output.emitKeystroke) { - [self.appDelegate logDebugMessage:@" *** InputMethodEventHandler applyKeymanCoreActions: emit keystroke true, returning false for handledEvent"]; - handledEvent = NO; - } - - return handledEvent; + [self.appDelegate logDebugMessage:@" *** InputMethodEventHandler applyKeymanCoreActions: output = %@ ", output]; + + BOOL handledEvent = [self applyKeyOutputToTextInputClient:output keyDownEvent:event client:client]; + [self applyNonTextualOutput:output]; + + // if output from Keyman Core indicates to emit the keystroke, + // then return NO, so that the OS still handles the event + if (handledEvent && output.emitKeystroke) { + [self.appDelegate logDebugMessage:@" *** InputMethodEventHandler applyKeymanCoreActions: emit keystroke true, returning false for handledEvent"]; + handledEvent = NO; + } + + return handledEvent; } -(BOOL)applyKeyOutputToTextInputClient:(CoreKeyOutput*)output keyDownEvent:(nonnull NSEvent *)event client:(id) client { @@ -373,26 +373,26 @@ -(BOOL)applyKeyOutputToTextInputClient:(CoreKeyOutput*)output keyDownEvent:(nonn } else if (output.isDeleteAndInsertScenario) { // TODO: fix issue #10246 /* - // needs further testing to fix backspace bug in google docs (without breaking other apps) - // assume that all non-compliant apps which require backspaces apply an extra backspace if the original event is a backspace - if ((self.apiCompliance.mustBackspaceUsingEvents) && (event.keyCode == kVK_Delete)) { - output.codePointsToDeleteBeforeInsert--; - os_log_with_type(keymanLog, OS_LOG_TYPE_INFO, "isDeleteAndInsertScenario, after delete pressed subtracting one backspace to reach %d and insert text '%{public}@'", output.codePointsToDeleteBeforeInsert, output.textToInsert); - if (output.codePointsToDeleteBeforeInsert == 0) { - // no backspace events needed - [self insertAndReplaceTextForOutput:output client:client]; - } else { - // still need at least one backspace event - [self sendEvents:event forOutput:output]; - } - } + // needs further testing to fix backspace bug in google docs (without breaking other apps) + // assume that all non-compliant apps which require backspaces apply an extra backspace if the original event is a backspace + if ((self.apiCompliance.mustBackspaceUsingEvents) && (event.keyCode == kVK_Delete)) { + output.codePointsToDeleteBeforeInsert--; + os_log_with_type(keymanLog, OS_LOG_TYPE_INFO, "isDeleteAndInsertScenario, after delete pressed subtracting one backspace to reach %d and insert text '%{public}@'", output.codePointsToDeleteBeforeInsert, output.textToInsert); + if (output.codePointsToDeleteBeforeInsert == 0) { + // no backspace events needed + [self insertAndReplaceTextForOutput:output client:client]; + } else { + // still need at least one backspace event + [self sendEvents:event forOutput:output]; + } + } */ - + if (self.apiCompliance.mustBackspaceUsingEvents) { [self.appDelegate logDebugMessage:@"KXMInputMethodHandler applyOutputToTextInputClient, delete and insert scenario with events"]; [self sendEvents:event forOutput:output]; } else { - [self.appDelegate logDebugMessage:@"KXMInputMethodHandler applyOutputToTextInputClient, delete and insert scenario with insert API"]; + [self.appDelegate logDebugMessage:@"KXMInputMethodHandler applyOutputToTextInputClient, delete and insert scenario with insert API"]; // directly insert text and handle backspaces by using replace [self insertAndReplaceTextForOutput:output client:client]; } @@ -476,18 +476,18 @@ -(NSRange) calculateInsertRangeForDeletedText:(NSString*)textToDelete selectionR resultingReplacementRange.length = textToDelete.length + selection.length; resultingReplacementRange.location = selection.location - textToDelete.length; } - + return resultingReplacementRange; } -(void)sendEvents:(NSEvent *)event forOutput:(CoreKeyOutput*)output { [self.appDelegate logDebugMessage:@"sendEvents called, output = %@", output]; - + _sourceForGeneratedEvent = CGEventCreateSourceFromEvent([event CGEvent]); - + self.generatedBackspaceCount = output.codePointsToDeleteBeforeInsert; - + if (output.hasCodePointsToDelete) { for (int i = 0; i < output.codePointsToDeleteBeforeInsert; i++) { [self.appDelegate logDebugMessage:@"sendEvents sending backspace key event"]; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/KMKeyboardHelpWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/KMKeyboardHelpWindowController.m index b77243aac0c..359ddaa8803 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/KMKeyboardHelpWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardHelpWindow/KMKeyboardHelpWindowController.m @@ -19,70 +19,70 @@ @interface KMKeyboardHelpWindowController () @implementation KMKeyboardHelpWindowController - (KMInputMethodAppDelegate *)AppDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; + return (KMInputMethodAppDelegate *)[NSApp delegate]; } - (void)windowDidLoad { - [super windowDidLoad]; - [self.window setTitle:@"Keyman"]; - [self.welcomeView setFrameLoadDelegate:(id)self]; - [self.welcomeView setPolicyDelegate:(id)self]; + [super windowDidLoad]; + [self.window setTitle:@"Keyman"]; + [self.welcomeView setFrameLoadDelegate:(id)self]; + [self.welcomeView setPolicyDelegate:(id)self]; } - (void)setPackagePath:(NSString *)packagePath { - _packagePath = packagePath; - _packageInfo = nil; - if (packagePath != nil && packagePath.length) { - @try { - NSString *title = self.packageInfo.packageName; - if (title.length) - [self.window setTitle:title]; - } - @catch (NSException *e) { - NSLog(@"Error = %@", e.description); - } - - NSString *welcomeFile = [packagePath stringByAppendingPathComponent:@"welcome.htm"]; - if ([[NSFileManager defaultManager] fileExistsAtPath:welcomeFile]) - [self.welcomeView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:welcomeFile]]]; - else - [self.welcomeView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]]; + _packagePath = packagePath; + _packageInfo = nil; + if (packagePath != nil && packagePath.length) { + @try { + NSString *title = self.packageInfo.packageName; + if (title.length) + [self.window setTitle:title]; } + @catch (NSException *e) { + NSLog(@"Error = %@", e.description); + } + + NSString *welcomeFile = [packagePath stringByAppendingPathComponent:@"welcome.htm"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:welcomeFile]) + [self.welcomeView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:welcomeFile]]]; + else + [self.welcomeView.mainFrame loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]]; + } } - (KMPackageInfo*)packageInfo { - if(_packageInfo == nil) { - _packageInfo = [self.AppDelegate loadPackageInfo:self.packagePath]; - } - - return _packageInfo; + if(_packageInfo == nil) { + _packageInfo = [self.AppDelegate loadPackageInfo:self.packagePath]; + } + + return _packageInfo; } - (IBAction)okAction:(id)sender { - [self close]; + [self close]; } - (IBAction)printAction:(id)sender { - NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo]; - [printInfo setOrientation:NSPaperOrientationPortrait]; - NSPrintOperation *printOperation = [[self.welcomeView.mainFrame frameView] printOperationWithPrintInfo:printInfo]; - [printOperation runOperationModalForWindow:self.window - delegate:nil - didRunSelector:nil - contextInfo:nil]; + NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo]; + [printInfo setOrientation:NSPaperOrientationPortrait]; + NSPrintOperation *printOperation = [[self.welcomeView.mainFrame frameView] printOperationWithPrintInfo:printInfo]; + [printOperation runOperationModalForWindow:self.window + delegate:nil + didRunSelector:nil + contextInfo:nil]; } - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { - NSNumber *navType = [actionInformation objectForKey:WebActionNavigationTypeKey]; - if (navType.integerValue == WebNavigationTypeLinkClicked && ![request.URL isFileURL]) { - NSString *urlStr = [[request URL] absoluteString]; - if ([urlStr startsWith:@"link:"]) - urlStr = [urlStr substringFromIndex:5]; - - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlStr]]; - } - else - [listener use]; + NSNumber *navType = [actionInformation objectForKey:WebActionNavigationTypeKey]; + if (navType.integerValue == WebNavigationTypeLinkClicked && ![request.URL isFileURL]) { + NSString *urlStr = [[request URL] absoluteString]; + if ([urlStr startsWith:@"link:"]) + urlStr = [urlStr substringFromIndex:5]; + + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlStr]]; + } + else + [listener use]; } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardInfo.h b/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardInfo.h index 96adc5ff243..1ebf86dacac 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardInfo.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardInfo.h @@ -46,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithName:(NSString*)name identifier:(NSString*)identifier version:(NSString*)version - oskFont:(NSString*)oskFont + oskFont:(NSString*)oskFont displayFont:(NSString*)displayFont languages:(NSArray*)languages; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardInfo.m b/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardInfo.m index e9cad434b79..b642c1e45a2 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardInfo.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMKeyboardInfo.m @@ -30,7 +30,7 @@ - (instancetype)init { @implementation KMLanguageInfo - (instancetype)initWithName:(NSString*)name - identifier:(NSString*)identifier + identifier:(NSString*)identifier { self = [super init]; if (self) { @@ -59,8 +59,8 @@ - (instancetype)initWithBuilder:(KMKeyboardInfoBuilder *)builder { - (instancetype)initWithName:(NSString*)name identifier:(NSString*)identifier - version:(NSString*)version - oskFont:(NSString*)oskFont + version:(NSString*)version + oskFont:(NSString*)oskFont displayFont:(NSString*)displayFont languages:(NSArray*)languages { diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMOSVersion.m b/mac/Keyman4MacIM/Keyman4MacIM/KMOSVersion.m index bd068a3a4f1..8668e881dde 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMOSVersion.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMOSVersion.m @@ -13,49 +13,49 @@ @implementation KMOSVersion +(u_int16_t)SystemVersion { - NSDictionary *systemVersionDict = [NSDictionary dictionaryWithContentsOfFile:(__bridge NSString*)sSystemVersionPath]; - if (NULL ==systemVersionDict) - { - NSLog(@"could not read system version dictionary file: %@", sSystemVersionPath); - return 0; - } - NSString *systemVersionString = [systemVersionDict objectForKey:@"ProductVersion"]; - if (NULL ==systemVersionString) - { - NSLog(@"could not retrieve system version from dictionary at %@ with %d keys", sSystemVersionPath, (int)systemVersionDict.count); - return 0; - } - NSArray *systemVersionStringParts = [systemVersionString componentsSeparatedByString:@"."]; - if (systemVersionStringParts.count < 2) - { - NSLog(@"Too few parts to the system version (probably): %@", systemVersionString); - return [systemVersionString intValue]; // hopefully this will at least be the major OS version, e.g., 10 (all versions so far!) - } - - NSString *majVersionStr = systemVersionStringParts[0]; - u_int16_t systemVersion = majVersionStr.intValue << 8; - NSString *minVersionStr = systemVersionStringParts[1]; - systemVersion |= minVersionStr.intValue << 4; - if (systemVersionStringParts.count > 2) - { - NSString *bugVersionStr = systemVersionStringParts[2]; - systemVersion |= bugVersionStr.intValue; - } - if (systemVersionStringParts.count > 3) - { - NSLog(@"Portions of System Version string after third part unused: %@", systemVersionString); - } - return systemVersion; + NSDictionary *systemVersionDict = [NSDictionary dictionaryWithContentsOfFile:(__bridge NSString*)sSystemVersionPath]; + if (NULL ==systemVersionDict) + { + NSLog(@"could not read system version dictionary file: %@", sSystemVersionPath); + return 0; + } + NSString *systemVersionString = [systemVersionDict objectForKey:@"ProductVersion"]; + if (NULL ==systemVersionString) + { + NSLog(@"could not retrieve system version from dictionary at %@ with %d keys", sSystemVersionPath, (int)systemVersionDict.count); + return 0; + } + NSArray *systemVersionStringParts = [systemVersionString componentsSeparatedByString:@"."]; + if (systemVersionStringParts.count < 2) + { + NSLog(@"Too few parts to the system version (probably): %@", systemVersionString); + return [systemVersionString intValue]; // hopefully this will at least be the major OS version, e.g., 10 (all versions so far!) + } + + NSString *majVersionStr = systemVersionStringParts[0]; + u_int16_t systemVersion = majVersionStr.intValue << 8; + NSString *minVersionStr = systemVersionStringParts[1]; + systemVersion |= minVersionStr.intValue << 4; + if (systemVersionStringParts.count > 2) + { + NSString *bugVersionStr = systemVersionStringParts[2]; + systemVersion |= bugVersionStr.intValue; + } + if (systemVersionStringParts.count > 3) + { + NSLog(@"Portions of System Version string after third part unused: %@", systemVersionString); + } + return systemVersion; } +(u_int16_t)Version_10_13_1 { - return 0x0AD1; // 10.13.1 in hex by nibbles, the way the old Gestalt call used to do it + return 0x0AD1; // 10.13.1 in hex by nibbles, the way the old Gestalt call used to do it } +(u_int16_t)Version_10_13_3 { - return 0x0AD3; // 10.13.3 in hex by nibbles, the way the old Gestalt call used to do it + return 0x0AD3; // 10.13.3 in hex by nibbles, the way the old Gestalt call used to do it } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.m b/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.m index e5f041a9170..4a54e445c02 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMPackage.m @@ -18,96 +18,96 @@ @implementation KMPackage -(NSString *) getOrigKmpFilename { - return filename; + return filename; } -(NSString *) getTempKmpFilename { - return filenameTempKMP; + return filenameTempKMP; } + (BOOL)autosavesInPlace { - return NO; + return NO; } // This method gets called whenever a user double-clicks a KMP file, regardless of whether // they decide to install it or cancel the installation. It also gets called one time up-front // when Keyman first loads. - (void)makeWindowControllers { - if ([self.AppDelegate debugMode]) - NSLog(@"KMP - in KMPackage.makeWindowControllers"); - - if (filename != nil) { // Should be true every time except maybe the very first time (when loading). - filename = nil; - [self closeIfFilesAreReleased]; - } + if ([self.AppDelegate debugMode]) + NSLog(@"KMP - in KMPackage.makeWindowControllers"); + + if (filename != nil) { // Should be true every time except maybe the very first time (when loading). + filename = nil; + [self closeIfFilesAreReleased]; + } } -(void) closeIfFilesAreReleased { - // Since we aren't really opening this file as a document, after reading it (or deciding not to) - // we need to close this document so the controller doesn't hold onto it. Otherwise, if the user - // double-clicks the same KMP file a second time it will just assume we want to open the window - // to display the already open document, rather than attempting to read it again. - if ([self.AppDelegate debugMode]) - NSLog(@"Closing document to release presenter..."); - if (filename == nil && filenameTempKMP == nil) - [self close]; + // Since we aren't really opening this file as a document, after reading it (or deciding not to) + // we need to close this document so the controller doesn't hold onto it. Otherwise, if the user + // double-clicks the same KMP file a second time it will just assume we want to open the window + // to display the already open document, rather than attempting to read it again. + if ([self.AppDelegate debugMode]) + NSLog(@"Closing document to release presenter..."); + if (filename == nil && filenameTempKMP == nil) + [self close]; } - (KMInputMethodAppDelegate *)AppDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; + return (KMInputMethodAppDelegate *)[NSApp delegate]; } -(BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError * _Nullable __autoreleasing *)outError { - - filename = [fileWrapper filename]; - - if ([self.AppDelegate debugMode]) - NSLog(@"readFromFileWrapper called with file: %@", filename); - - if (![typeName isEqualToString: @"Keyman Package"]) { - if (outError != NULL) { - NSString *description = [@"Unexpected file association for type " stringByAppendingString:typeName]; - NSDictionary *errorDictionary = @{ NSLocalizedDescriptionKey : description, - NSFilePathErrorKey : filename - }; - *outError = [[NSError alloc] initWithDomain:@"Keyman" code:kUnexpectedFileAsscociationType userInfo:errorDictionary]; - } - return NO; - } - - // Strip out any browser-appended number, e.g. khmer_angkor (1).kmp - // We work on a copy of the file, so this is safe to do -- the fileWrapper - // saves to the filename we give it. - NSError *error = nil; - NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@" \\(\\d+\\)\\.kmp$" options:NSRegularExpressionCaseInsensitive error:&error]; - filename = [regex stringByReplacingMatchesInString:filename - options:0 - range:NSMakeRange(0, [filename length]) - withTemplate:@".kmp"]; - - filenameTempKMP = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; - assert(filenameTempKMP != nil); - NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:filenameTempKMP]; - if (![fileWrapper writeToURL:fileURL options:NSFileWrapperWritingAtomic originalContentsURL:nil error:outError]) { - filenameTempKMP = nil; - return NO; + + filename = [fileWrapper filename]; + + if ([self.AppDelegate debugMode]) + NSLog(@"readFromFileWrapper called with file: %@", filename); + + if (![typeName isEqualToString: @"Keyman Package"]) { + if (outError != NULL) { + NSString *description = [@"Unexpected file association for type " stringByAppendingString:typeName]; + NSDictionary *errorDictionary = @{ NSLocalizedDescriptionKey : description, + NSFilePathErrorKey : filename + }; + *outError = [[NSError alloc] initWithDomain:@"Keyman" code:kUnexpectedFileAsscociationType userInfo:errorDictionary]; } - - KMConfigurationWindowController *configWindowController = (KMConfigurationWindowController *)[self.AppDelegate configWindow]; - [configWindowController handleRequestToInstallPackage:self]; - - return YES; // Even if the user decides not to, we need to return Yes to prevent displaying an error message. + return NO; + } + + // Strip out any browser-appended number, e.g. khmer_angkor (1).kmp + // We work on a copy of the file, so this is safe to do -- the fileWrapper + // saves to the filename we give it. + NSError *error = nil; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@" \\(\\d+\\)\\.kmp$" options:NSRegularExpressionCaseInsensitive error:&error]; + filename = [regex stringByReplacingMatchesInString:filename + options:0 + range:NSMakeRange(0, [filename length]) + withTemplate:@".kmp"]; + + filenameTempKMP = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + assert(filenameTempKMP != nil); + NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:filenameTempKMP]; + if (![fileWrapper writeToURL:fileURL options:NSFileWrapperWritingAtomic originalContentsURL:nil error:outError]) { + filenameTempKMP = nil; + return NO; + } + + KMConfigurationWindowController *configWindowController = (KMConfigurationWindowController *)[self.AppDelegate configWindow]; + [configWindowController handleRequestToInstallPackage:self]; + + return YES; // Even if the user decides not to, we need to return Yes to prevent displaying an error message. } -(void) releaseTempKMPFile { - assert(filenameTempKMP != nil); - [[NSFileManager defaultManager] removeItemAtPath:filenameTempKMP error:nil]; - filenameTempKMP = nil; - [self closeIfFilesAreReleased]; + assert(filenameTempKMP != nil); + [[NSFileManager defaultManager] removeItemAtPath:filenameTempKMP error:nil]; + filenameTempKMP = nil; + [self closeIfFilesAreReleased]; } // This tells the system that we aren't reading the Keyman Package file lazily. -(BOOL) isEntireFileLoaded { - return YES; + return YES; } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageInfo.h b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageInfo.h index 1d466b439d2..76d007c31d2 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageInfo.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageInfo.h @@ -54,11 +54,11 @@ NS_ASSUME_NONNULL_BEGIN packageVersion:(NSString*)packageVersion readmeFilename:(NSString*)readmeFilename graphicFilename:(NSString*)graphicFilename - fileVersion:(NSString*)fileVersion + fileVersion:(NSString*)fileVersion keymanDeveloperVersion:(NSString*)keymanDeveloperVersion copyright:(NSString*)copyright authorName:(NSString*)authorName - authorUrl:(NSString*)authorUrl + authorUrl:(NSString*)authorUrl website:(NSString*)website keyboards:(NSArray*)keyboards fonts:(NSArray*)fonts diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageInfo.m b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageInfo.m index cbec2199b54..6ea942cce88 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageInfo.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageInfo.m @@ -58,12 +58,12 @@ - (instancetype)initWithBuilder:(KMPackageInfoBuilder *)builder { - (instancetype)initWithName:(NSString*)packageName packageVersion:(NSString*)packageVersion readmeFilename:(NSString*)readmeFilename - graphicFilename:(NSString*)graphicFilename + graphicFilename:(NSString*)graphicFilename fileVersion:(NSString*)fileVersion keymanDeveloperVersion:(NSString*)keymanDeveloperVersion copyright:(NSString*)copyright authorName:(NSString*)authorName - authorUrl:(NSString*)authorUrl + authorUrl:(NSString*)authorUrl website:(NSString*)website keyboards:(NSArray*)keyboards fonts:(NSArray*)fonts diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m index 103430c2f53..dc882276720 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m @@ -36,7 +36,7 @@ static NSString *const kWelcome = @"Welcome"; typedef enum { - ctPackage, ctButtons, ctStartMenu, ctStartMenuEntries, ctInfo, ctFiles, ctUnknown + ctPackage, ctButtons, ctStartMenu, ctStartMenuEntries, ctInfo, ctFiles, ctUnknown } ContentType; @implementation KMPackageReader @@ -50,14 +50,14 @@ - (instancetype)init { } /** - * Attempt to load Keyman Package Information from kmp.json. - * If kmp.json file is not found or not readable, load from legacy kmp.inf file. - * @param the full path of the package folder. + * Attempt to load Keyman Package Information from kmp.json. + * If kmp.json file is not found or not readable, load from legacy kmp.inf file. + * @param the full path of the package folder. */ - (KMPackageInfo *)loadPackageInfo:(NSString *)path { KMPackageInfo *packageInfo = nil; NSString *jsonFilename = [path stringByAppendingPathComponent:kPackageJsonFile]; - + packageInfo = [self loadPackageInfoFromJsonFile:jsonFilename]; if (packageInfo == nil) { @@ -70,17 +70,17 @@ - (KMPackageInfo *)loadPackageInfo:(NSString *)path { - (NSString *)packageNameFromPackageInfo:(NSString *)path { NSString *packageName = nil; - + KMPackageInfo *packageInfo = [self loadPackageInfo:path]; packageName = packageInfo.packageName; - + return packageName; } - /** - * read JSON file and load it into KMPackageInfo object - * returns nil if the file does not exist or it cannot be parsed as JSON - */ +/** + * read JSON file and load it into KMPackageInfo object + * returns nil if the file does not exist or it cannot be parsed as JSON + */ - (KMPackageInfo *) loadPackageInfoFromJsonFile:(NSString *)path { KMPackageInfo * packageInfo = nil; @@ -89,20 +89,20 @@ - (KMPackageInfo *) loadPackageInfoFromJsonFile:(NSString *)path { NSError *readError = nil; NSData *data = [NSData dataWithContentsOfFile:path options:kNilOptions error:&readError]; NSDictionary *parsedData = nil; - + if (data == nil) { NSLog(@"Error reading JSON file at path : %@, error: %@ ", path, readError); } else { NSError *parseError = nil; parsedData = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&parseError]; - + if (parsedData == nil) { NSLog(@"Error parsing JSON file at path : %@, error: %@ ", path, parseError); } else { packageInfo = [self createPackageInfoFromJsonData:parsedData]; } } - + return packageInfo; } @@ -112,36 +112,36 @@ - (KMPackageInfo *) loadPackageInfoFromJsonFile:(NSString *)path { * @return the corresponding KeyboardInfo value object */ - (KMKeyboardInfo *) createKeyboardInfoFromJsonKeyboard:(NSDictionary *) keyboard { - + KMKeyboardInfoBuilder *builder = [[KMKeyboardInfoBuilder alloc] init]; - + NSArray *languages = keyboard[@"languages"]; NSMutableArray *languageInfoArray = [NSMutableArray arrayWithCapacity:0]; - + for (NSDictionary *language in languages) { KMLanguageInfo *languageInfo = [[KMLanguageInfo alloc] initWithName:language[@"name"] - identifier:language[@"id"]]; - + identifier:language[@"id"]]; + [languageInfoArray addObject:languageInfo]; } - + builder.name = keyboard[@"name"]; builder.identifier = keyboard[@"id"]; builder.version = keyboard[@"version"]; builder.oskFont = keyboard[@"oskFont"]; builder.displayFont = keyboard[@"displayFont"]; builder.languages = [languageInfoArray copy]; - + KMKeyboardInfo *keyboardInfo = [[KMKeyboardInfo alloc] initWithBuilder:builder]; return keyboardInfo; } - (KMPackageInfo *) createPackageInfoFromJsonData:(NSDictionary *) jsonData { - + NSMutableArray *keyboardInfoArray = [NSMutableArray arrayWithCapacity:0]; NSMutableArray *fontArray = [NSMutableArray arrayWithCapacity:0]; NSArray *keyboards = jsonData[@"keyboards"]; - + // loop through keyboards array to add keyboards, // then loop through each keyboard's languages array to add languages @@ -158,29 +158,29 @@ - (KMPackageInfo *) createPackageInfoFromJsonData:(NSDictionary *) jsonData { ![keyboardInfo.displayFont isEqualToString:keyboardInfo.displayFont]) { [fontArray addObject:keyboardInfo.displayFont]; } - + [keyboardInfoArray addObject:keyboardInfo]; } - + KMPackageInfoBuilder *builder = - [[KMPackageInfoBuilder alloc] init]; + [[KMPackageInfoBuilder alloc] init]; - builder.packageName = jsonData[@"info"][@"name"][@"description"]; - builder.packageVersion = jsonData[@"info"][@"version"][@"description"]; - builder.readmeFilename = jsonData[@"options"][@"readmeFile"]; - builder.graphicFilename = jsonData[@"options"][@"graphicFile"]; - builder.fileVersion = jsonData[@"system"][@"fileVersion"]; - builder.keymanDeveloperVersion = jsonData[@"system"][@"keymanDeveloperVersion"]; - builder.copyright = jsonData[@"info"][@"copyright"][@"description"]; - builder.authorName = jsonData[@"info"][@"author"][@"description"]; - builder.authorUrl = jsonData[@"info"][@"author"][@"url"]; - builder.website = jsonData[@"info"][@"website"][@"url"]; - builder.keyboards = [keyboardInfoArray copy]; - builder.fonts = [fontArray copy]; - - KMPackageInfo *packageInfo = [[KMPackageInfo alloc] initWithBuilder:builder]; - - return packageInfo; + builder.packageName = jsonData[@"info"][@"name"][@"description"]; + builder.packageVersion = jsonData[@"info"][@"version"][@"description"]; + builder.readmeFilename = jsonData[@"options"][@"readmeFile"]; + builder.graphicFilename = jsonData[@"options"][@"graphicFile"]; + builder.fileVersion = jsonData[@"system"][@"fileVersion"]; + builder.keymanDeveloperVersion = jsonData[@"system"][@"keymanDeveloperVersion"]; + builder.copyright = jsonData[@"info"][@"copyright"][@"description"]; + builder.authorName = jsonData[@"info"][@"author"][@"description"]; + builder.authorUrl = jsonData[@"info"][@"author"][@"url"]; + builder.website = jsonData[@"info"][@"website"][@"url"]; + builder.keyboards = [keyboardInfoArray copy]; + builder.fonts = [fontArray copy]; + + KMPackageInfo *packageInfo = [[KMPackageInfo alloc] initWithBuilder:builder]; + + return packageInfo; } // TODO: refactor, break up and eliminate duplicate code @@ -190,16 +190,16 @@ - (KMPackageInfo *) createPackageInfoFromJsonData:(NSDictionary *) jsonData { * * @param path the full path to the kmp.inf file * @return the corresponding PackageInfo value object or nil if the file cannot be found or parsed -*/ + */ - (KMPackageInfo *) loadPackageInfoFromInfFile:(NSString *)path { if (self.debugMode) NSLog(@"Loading inf package info from path: %@", path); - + NSMutableArray *files = [NSMutableArray arrayWithCapacity:0]; NSMutableArray *keyboardInfoArray = [NSMutableArray arrayWithCapacity:0]; NSMutableArray *fontArray = [NSMutableArray arrayWithCapacity:0]; KMPackageInfoBuilder *builder = [[KMPackageInfoBuilder alloc] init]; - + @try { NSString *fileContents = [[NSString stringWithContentsOfFile:path encoding:NSWindowsCP1252StringEncoding error:NULL] stringByReplacingOccurrencesOfString:@"\r" withString:@""]; NSArray *lines = [fileContents componentsSeparatedByString:@"\n"]; @@ -207,7 +207,7 @@ - (KMPackageInfo *) loadPackageInfoFromInfFile:(NSString *)path { for (NSString *line in lines) { if (!line.length) continue; - + if ([[line lowercaseString] hasPrefix:[kPackage lowercaseString]]) { contentType = ctPackage; continue; @@ -232,7 +232,7 @@ - (KMPackageInfo *) loadPackageInfoFromInfFile:(NSString *)path { contentType = ctFiles; continue; } - + switch (contentType) { case ctPackage: { if ([[line lowercaseString] hasPrefix:[kReadMeFile lowercaseString]]) @@ -254,44 +254,44 @@ - (KMPackageInfo *) loadPackageInfoFromInfFile:(NSString *)path { NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; builder.packageName = v1; - } - else if ([[line lowercaseString] hasPrefix:[kVersion lowercaseString]]) { - NSString *s = [line substringFromIndex:kVersion.length+1]; - NSArray *vs = [s componentsSeparatedByString:@"\","]; - NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - builder.packageVersion = v1; - } - else if ([[line lowercaseString] hasPrefix:[kAuthor lowercaseString]]) { - NSString *s = [line substringFromIndex:kAuthor.length+1]; - NSArray *vs = [s componentsSeparatedByString:@"\","]; - NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - builder.authorName = v1; - builder.authorUrl = v2; - } - else if ([[line lowercaseString] hasPrefix:[kCopyright lowercaseString]]) { - NSString *s = [line substringFromIndex:kCopyright.length+1]; - NSArray *vs = [s componentsSeparatedByString:@"\","]; - NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - builder.copyright = v1; - } - else if ([[line lowercaseString] hasPrefix:[kWebSite lowercaseString]]) { - NSString *s = [line substringFromIndex:kWebSite.length+1]; - NSArray *vs = [s componentsSeparatedByString:@"\","]; - NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - builder.website = v1; - } - + } + else if ([[line lowercaseString] hasPrefix:[kVersion lowercaseString]]) { + NSString *s = [line substringFromIndex:kVersion.length+1]; + NSArray *vs = [s componentsSeparatedByString:@"\","]; + NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; + NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; + builder.packageVersion = v1; + } + else if ([[line lowercaseString] hasPrefix:[kAuthor lowercaseString]]) { + NSString *s = [line substringFromIndex:kAuthor.length+1]; + NSArray *vs = [s componentsSeparatedByString:@"\","]; + NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; + NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; + builder.authorName = v1; + builder.authorUrl = v2; + } + else if ([[line lowercaseString] hasPrefix:[kCopyright lowercaseString]]) { + NSString *s = [line substringFromIndex:kCopyright.length+1]; + NSArray *vs = [s componentsSeparatedByString:@"\","]; + NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; + NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; + builder.copyright = v1; + } + else if ([[line lowercaseString] hasPrefix:[kWebSite lowercaseString]]) { + NSString *s = [line substringFromIndex:kWebSite.length+1]; + NSArray *vs = [s componentsSeparatedByString:@"\","]; + NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; + NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; + builder.website = v1; + } + break; } case ctFiles: { NSUInteger x = [line rangeOfString:@"="].location; if (x == NSNotFound) continue; - + NSString *s = [line substringFromIndex:x+2]; if ([[s lowercaseString] hasPrefix:[kFile lowercaseString]]) { NSArray *vs = [s componentsSeparatedByString:@"\","]; @@ -315,7 +315,7 @@ - (KMPackageInfo *) loadPackageInfoFromInfFile:(NSString *)path { KMKeyboardInfo *keyboardInfo = [[KMKeyboardInfo alloc] initWithBuilder:builder]; [keyboardInfoArray addObject:keyboardInfo]; } - + break; } default: @@ -324,10 +324,10 @@ - (KMPackageInfo *) loadPackageInfoFromInfFile:(NSString *)path { } } @catch (NSException *e) { - NSLog(@"Error = %@", e.description); - return nil; + NSLog(@"Error = %@", e.description); + return nil; } - + builder.keyboards = keyboardInfoArray; builder.fonts = fontArray; KMPackageInfo *packageInfo = [[KMPackageInfo alloc] initWithBuilder:builder]; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m b/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m index c957c8664dc..8bc1954d150 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m @@ -31,21 +31,21 @@ -(instancetype)init { - (void)sendBackspaceforEventSource:(CGEventSourceRef)eventSource { [self.appDelegate logDebugMessage:@"KeySender sendBackspaceforEventSource"]; - + [self postKeyboardEventWithSource:eventSource code:kVK_Delete postCallback:^(CGEventRef eventToPost) { - CGEventPost(kCGHIDEventTap, eventToPost); + CGEventPost(kCGHIDEventTap, eventToPost); }]; } - (void)postKeyboardEventWithSource: (CGEventSourceRef)source code:(CGKeyCode) virtualKey postCallback:(PostEventCallback)postEvent{ - + if (!postEvent) { [self.appDelegate logDebugMessage:@"KeySender postKeyboardEventWithSource callback not specified", virtualKey]; return; } [self.appDelegate logDebugMessage:@"KeySender postKeyboardEventWithSource for virtualKey: @%", virtualKey]; - + CGEventRef ev = CGEventCreateKeyboardEvent (source, virtualKey, true); //down postEvent(ev); CFRelease(ev); @@ -64,7 +64,7 @@ - (void)sendKeymanKeyCodeForEvent:(NSEvent *)event { [self.appDelegate logDebugMessage:@"KeySender sendKeymanKeyCodeForEvent"]; ProcessSerialNumber psn; - + // Returns the frontmost app, which is the app that receives key events. NSRunningApplication *app = NSWorkspace.sharedWorkspace.frontmostApplication; pid_t processId = app.processIdentifier; @@ -74,7 +74,7 @@ - (void)sendKeymanKeyCodeForEvent:(NSEvent *)event { // use nil as source, as this generated event is not directly tied to the originating event CGEventRef keyDownEvent = CGEventCreateKeyboardEvent(nil, kKeymanEventKeyCode, true); - + CGEventPostToPid(processId, keyDownEvent); CFRelease(keyDownEvent); diff --git a/mac/Keyman4MacIM/Keyman4MacIM/OnScreenKeyboard/OSKWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/OnScreenKeyboard/OSKWindowController.m index d2ee927c02a..b8c699583de 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/OnScreenKeyboard/OSKWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/OnScreenKeyboard/OSKWindowController.m @@ -21,149 +21,149 @@ @interface OSKWindowController () @implementation OSKWindowController - (KMInputMethodAppDelegate *)AppDelegate { - return (KMInputMethodAppDelegate *)[NSApp delegate]; + return (KMInputMethodAppDelegate *)[NSApp delegate]; } - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [self stopTimer]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self stopTimer]; } - (void)awakeFromNib { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC awakeFromNib"); - // Keep the aspect ratio constant at its current value - [self.window setAspectRatio:self.window.frame.size]; - NSSize size = self.window.frame.size; - [self.window setMaxSize:NSMakeSize(size.width*1.6, size.height*1.6)]; - [self.window setMinSize:NSMakeSize(size.width*0.8, size.height*0.8)]; - [self.window setBackgroundColor:[NSColor colorWithSRGBRed:241.0/255.0 green:242.0/255.0 blue:242.0/255.0 alpha:1.0]]; - - // # 1079: Versions of macOS prior to 10.10 do not support setting control size. - // Safest to just not add the help button at all on the OSK. - NSButton *helpBtn = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 17, 17)]; - if (helpBtn && [helpBtn respondsToSelector:@selector(setControlSize:)]) { - _helpButton = helpBtn; - [_helpButton setTitle:@""]; - [_helpButton setBezelStyle:NSHelpButtonBezelStyle]; - [_helpButton setControlSize:NSControlSizeMini]; - [_helpButton setAction:@selector(helpAction:)]; - [_helpButton setEnabled:[self hasHelpDocumentation]]; - [self.window addViewToTitleBar:_helpButton positionX:NSWidth(self.window.frame) - NSWidth(_helpButton.frame) -10]; - } + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC awakeFromNib"); + // Keep the aspect ratio constant at its current value + [self.window setAspectRatio:self.window.frame.size]; + NSSize size = self.window.frame.size; + [self.window setMaxSize:NSMakeSize(size.width*1.6, size.height*1.6)]; + [self.window setMinSize:NSMakeSize(size.width*0.8, size.height*0.8)]; + [self.window setBackgroundColor:[NSColor colorWithSRGBRed:241.0/255.0 green:242.0/255.0 blue:242.0/255.0 alpha:1.0]]; + + // # 1079: Versions of macOS prior to 10.10 do not support setting control size. + // Safest to just not add the help button at all on the OSK. + NSButton *helpBtn = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 17, 17)]; + if (helpBtn && [helpBtn respondsToSelector:@selector(setControlSize:)]) { + _helpButton = helpBtn; + [_helpButton setTitle:@""]; + [_helpButton setBezelStyle:NSHelpButtonBezelStyle]; + [_helpButton setControlSize:NSControlSizeMini]; + [_helpButton setAction:@selector(helpAction:)]; + [_helpButton setEnabled:[self hasHelpDocumentation]]; + [self.window addViewToTitleBar:_helpButton positionX:NSWidth(self.window.frame) - NSWidth(_helpButton.frame) -10]; + } } - (void)windowDidLoad { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC windowDidLoad"); - [super windowDidLoad]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:self.window]; - [self.oskView setKvk:[self.AppDelegate kvk]]; - [self startTimerWithTimeInterval:0.1]; - // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC windowDidLoad"); + [super windowDidLoad]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:self.window]; + [self.oskView setKvk:[self.AppDelegate kvk]]; + [self startTimerWithTimeInterval:0.1]; + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. } - (void)windowDidResize:(NSNotification *)notification { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC windowDidResize"); - [self.oskView resizeOSKLayout]; + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC windowDidResize"); + [self.oskView resizeOSKLayout]; } - (void)helpAction:(id)sender { - NSString *kvkPath = [self AppDelegate].kvk.filePath; - if (!kvkPath) - return; + NSString *kvkPath = [self AppDelegate].kvk.filePath; + if (!kvkPath) + return; + + NSString *packagePath = [kvkPath stringByDeletingLastPathComponent]; + if (packagePath != nil) { + if (self.AppDelegate.kbHelpWindow_.window != nil) + [self.AppDelegate.kbHelpWindow_ close]; - NSString *packagePath = [kvkPath stringByDeletingLastPathComponent]; - if (packagePath != nil) { - if (self.AppDelegate.kbHelpWindow_.window != nil) - [self.AppDelegate.kbHelpWindow_ close]; - - [self.AppDelegate.kbHelpWindow.window centerInParent]; - [self.AppDelegate.kbHelpWindow.window makeKeyAndOrderFront:nil]; - [self.AppDelegate.kbHelpWindow.window setLevel:NSFloatingWindowLevel]; - [self.AppDelegate.kbHelpWindow setPackagePath:packagePath]; - } + [self.AppDelegate.kbHelpWindow.window centerInParent]; + [self.AppDelegate.kbHelpWindow.window makeKeyAndOrderFront:nil]; + [self.AppDelegate.kbHelpWindow.window setLevel:NSFloatingWindowLevel]; + [self.AppDelegate.kbHelpWindow setPackagePath:packagePath]; + } } - (void)resetOSK { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC windowDidLoad"); - [self.oskView setKvk:[self.AppDelegate kvk]]; - [self.oskView resetOSK]; - if (_helpButton) { - [_helpButton setEnabled:[self hasHelpDocumentation]]; - } + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKWC windowDidLoad"); + [self.oskView setKvk:[self.AppDelegate kvk]]; + [self.oskView resetOSK]; + if (_helpButton) { + [_helpButton setEnabled:[self hasHelpDocumentation]]; + } } - (void)startTimerWithTimeInterval:(NSTimeInterval)interval { - if (_modFlagsTimer == nil) { - TimerTarget *timerTarget = [[TimerTarget alloc] init]; - timerTarget.target = self; - _modFlagsTimer = [NSTimer scheduledTimerWithTimeInterval:interval - target:timerTarget - selector:@selector(timerAction:) - userInfo:nil - repeats:YES]; - } + if (_modFlagsTimer == nil) { + TimerTarget *timerTarget = [[TimerTarget alloc] init]; + timerTarget.target = self; + _modFlagsTimer = [NSTimer scheduledTimerWithTimeInterval:interval + target:timerTarget + selector:@selector(timerAction:) + userInfo:nil + repeats:YES]; + } } - (void)stopTimer { - if (_modFlagsTimer != nil) { - [_modFlagsTimer invalidate]; - _modFlagsTimer = nil; - } + if (_modFlagsTimer != nil) { + [_modFlagsTimer invalidate]; + _modFlagsTimer = nil; + } } - (void)timerAction:(NSTimer *)timer { - UInt32 modifiers = GetCurrentKeyModifiers(); - if ((modifiers & shiftKey) == shiftKey) { - [self.oskView setShiftState:YES]; - self.xShiftState = YES; - } - else { - [self.oskView setShiftState:NO]; - if (self.xShiftState) - [self.oskView setOskShiftState:NO]; - self.xShiftState = NO; - } - - if ((modifiers & optionKey) == optionKey) { - [self.oskView setAltState:YES]; - self.xAltState = YES; - } - else { - [self.oskView setAltState:NO]; - if (self.xAltState) - [self.oskView setOskAltState:NO]; - self.xAltState = NO; - } - - if ((modifiers & controlKey) == controlKey) { - [self.oskView setCtrlState:YES]; - self.xCtrlState = YES; - } - else { - [self.oskView setCtrlState:NO]; - if (self.xCtrlState) - [self.oskView setOskCtrlState:NO]; - self.xCtrlState = NO; - } + UInt32 modifiers = GetCurrentKeyModifiers(); + if ((modifiers & shiftKey) == shiftKey) { + [self.oskView setShiftState:YES]; + self.xShiftState = YES; + } + else { + [self.oskView setShiftState:NO]; + if (self.xShiftState) + [self.oskView setOskShiftState:NO]; + self.xShiftState = NO; + } + + if ((modifiers & optionKey) == optionKey) { + [self.oskView setAltState:YES]; + self.xAltState = YES; + } + else { + [self.oskView setAltState:NO]; + if (self.xAltState) + [self.oskView setOskAltState:NO]; + self.xAltState = NO; + } + + if ((modifiers & controlKey) == controlKey) { + [self.oskView setCtrlState:YES]; + self.xCtrlState = YES; + } + else { + [self.oskView setCtrlState:NO]; + if (self.xCtrlState) + [self.oskView setOskCtrlState:NO]; + self.xCtrlState = NO; + } } - (BOOL)hasHelpDocumentation { - NSString *kvkPath = [self AppDelegate].kvk.filePath; - if (!kvkPath) - return NO; - - NSString *packagePath = [kvkPath stringByDeletingLastPathComponent]; - if (packagePath != nil) { - NSString *welcomeFile = [packagePath stringByAppendingPathComponent:@"welcome.htm"]; - if ([[NSFileManager defaultManager] fileExistsAtPath:welcomeFile]) - return YES; - } - + NSString *kvkPath = [self AppDelegate].kvk.filePath; + if (!kvkPath) return NO; + + NSString *packagePath = [kvkPath stringByDeletingLastPathComponent]; + if (packagePath != nil) { + NSString *welcomeFile = [packagePath stringByAppendingPathComponent:@"welcome.htm"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:welcomeFile]) + return YES; + } + + return NO; } @end diff --git a/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m b/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m index 7e3fffdb0aa..18047dccf3f 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m @@ -33,12 +33,12 @@ @implementation PrivacyConsent + (PrivacyConsent *)shared { - static PrivacyConsent *shared = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - shared = [[PrivacyConsent alloc] init]; - }); - return shared; + static PrivacyConsent *shared = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + shared = [[PrivacyConsent alloc] init]; + }); + return shared; } /** @@ -99,11 +99,11 @@ - (void)requestAccessibility */ - (NSWindowController *)privacyDialog { if (!_privacyDialog) { - _privacyDialog = [[PrivacyWindowController alloc] initWithWindowNibName:@"PrivacyWindowController"]; + _privacyDialog = [[PrivacyWindowController alloc] initWithWindowNibName:@"PrivacyWindowController"]; NSLog(@"privacyDialog created"); [self configureDialogForOsVersion]; } - + return _privacyDialog; } @@ -111,7 +111,7 @@ - (NSWindowController *)privacyDialog { * Initialize privacy alert appropriately as determined by macOS version. */ - (void)configureDialogForOsVersion { - + if (@available(macOS 10.15, *)) { [self configureDialogForCatalinaAndLater]; } else { @@ -153,8 +153,8 @@ - (void)configureDialogForCatalinaAndLater { * Present the PrivacyDialog alert to the user. */ - (void)showPrivacyDialog { - [[self.privacyDialog window] setLevel:NSModalPanelWindowLevel]; - [[self.privacyDialog window] makeKeyAndOrderFront:nil]; + [[self.privacyDialog window] setLevel:NSModalPanelWindowLevel]; + [[self.privacyDialog window] makeKeyAndOrderFront:nil]; } /** diff --git a/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyWindowController.m index 1a6bef3ef42..3b6de585cde 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyWindowController.m @@ -23,7 +23,7 @@ - (void)windowDidLoad { [super windowDidLoad]; NSString *bundleDisplayName = [[[NSBundle mainBundle] localizedInfoDictionary] - objectForKey:@"CFBundleDisplayName"]; + objectForKey:@"CFBundleDisplayName"]; [self.window setTitle:bundleDisplayName]; [_alertText setStringValue:NSLocalizedString(@"privacy-alert-text", nil)]; @@ -36,11 +36,11 @@ - (void)windowDidLoad { - (IBAction)closeAction:(id)sender { [self close]; - + // jump to System Preferences Security and Privacy settings NSString *urlString = @"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"; [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlString]]; - + // if callback to check for user consent has been set, execute it if (self.completionHandler) { self.completionHandler(); diff --git a/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.m b/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.m index 38cc99dba2e..6150efae563 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/TextApiCompliance.m @@ -72,7 +72,7 @@ -(instancetype)initWithClient:(id) client applicationId:(NSString *)appId { -(NSString *)description { -return [NSString stringWithFormat:@"complianceUncertain: %d, hasCompliantSelectionApi: %d, canReadText: %d, canReplaceText: %d, mustBackspaceUsingEvents: %d, clientAppId: %@, client: %@", self.complianceUncertain, self.hasCompliantSelectionApi, [self canReadText], [self canReplaceText], [self mustBackspaceUsingEvents], _clientApplicationId, _client]; + return [NSString stringWithFormat:@"complianceUncertain: %d, hasCompliantSelectionApi: %d, canReadText: %d, canReplaceText: %d, mustBackspaceUsingEvents: %d, clientAppId: %@, client: %@", self.complianceUncertain, self.hasCompliantSelectionApi, [self canReadText], [self canReplaceText], [self mustBackspaceUsingEvents], _clientApplicationId, _client]; } /** test to see if the API selectedRange functions properly for the text input client */ @@ -132,7 +132,7 @@ -(void) checkComplianceAfterInsert:(id) client delete:(NSString *)textToDelete i BOOL locationChanged = [self hasLocationChanged:selectionRange]; [self validateLocationChange:changeExpected hasLocationChanged:locationChanged]; } - + [self.appDelegate logDebugMessage:@"TextApiCompliance checkComplianceAfterInsert, self.hasWorkingSelectionApi = %@ for app %@", self.hasCompliantSelectionApi?@"YES":@"NO", self.clientApplicationId]; } @@ -158,7 +158,7 @@ - (BOOL)validateNewLocation:(NSUInteger)location delete:(NSString *)textToDelete } - (void) validateLocationChange:(BOOL) changeExpected hasLocationChanged:(BOOL) locationChanged { - + if (changeExpected == locationChanged) { // YES for certain, the location is where we expect it self.hasCompliantSelectionApi = YES; @@ -175,7 +175,7 @@ - (void) validateLocationChange:(BOOL) changeExpected hasLocationChanged:(BOOL) - (BOOL)isLocationChangeExpectedOnInsert:(NSString *)textToDelete insert:(NSString *)textToInsert { BOOL changeExpected = textToInsert.length != textToDelete.length; [self.appDelegate logDebugMessage:@"TextApiCompliance isLocationChangeExpected, changeExpected = %@", changeExpected?@"YES":@"NO"]; - + return changeExpected; } @@ -184,7 +184,7 @@ - (BOOL)hasLocationChanged:(NSRange)newSelection { NSUInteger oldLocation = self.initialSelection.location; BOOL locationChanged = newLocation != oldLocation; [self.appDelegate logDebugMessage:@"TextApiCompliance hasLocationChanged, currentSelection = %lu, length = %lu", newSelection.location, newSelection.length]; - + return locationChanged; } @@ -209,35 +209,35 @@ - (BOOL)applyNoncompliantAppLists:(NSString *)clientAppId { } /** Check this hard-coded list to see if the application ID is among those -* that are known to not implement selectionRange correctly. -* This was formerly called the legacy app list, renamed to improve clarity. -*/ + * that are known to not implement selectionRange correctly. + * This was formerly called the legacy app list, renamed to improve clarity. + */ - (BOOL)containedInHardCodedNoncompliantAppList:(NSString *)clientAppId { - BOOL isAppNonCompliant = (//[clientAppId isEqual: @"com.github.atom"] || - // 2023-12-19[sgs] Atom is now automatically detected as non-compliant - [clientAppId isEqual: @"com.collabora.libreoffice-free"] || - [clientAppId isEqual: @"org.libreoffice.script"] || - [clientAppId isEqual: @"org.vim.MacVim"] || - [clientAppId isEqual: @"io.brackets.appshell"] || - [clientAppId isEqual: @"com.axosoft.gitkraken"] || - [clientAppId isEqual: @"org.sil.app.builder.scripture.ScriptureAppBuilder"] || - [clientAppId isEqual: @"org.sil.app.builder.reading.ReadingAppBuilder"] || - [clientAppId isEqual: @"org.sil.app.builder.dictionary.DictionaryAppBuilder"] || - //[clientAppId isEqual: @"com.microsoft.Word"] || // 2020-11-24[mcd]: Appears to work well in Word 16.43, disable legacy by default - [clientAppId isEqual: @"org.openoffice.script"] || - // 2023-12-13[sgs]: Adobe apps automatically detected as non-compliant - //[clientAppId isEqual: @"com.adobe.illustrator"] || - //[clientAppId isEqual: @"com.adobe.InDesign"] || - //[clientAppId isEqual: @"com.adobe.Photoshop"] || - //[clientAppId isEqual: @"com.adobe.AfterEffects"] || - //[clientAppId isEqual: @"com.microsoft.VSCode"] || // 2023-05-29[sgs]: Works with 1.78.2, disable legacy by default - [clientAppId isEqual: @"com.google.Chrome"] || - // 2023-12-13[sgs]: must hard-code for Chrome because Google Docs returns relative but incorrect location so no way to auto-detect - [clientAppId hasPrefix: @"net.java"] || - [clientAppId isEqual: @"com.Keyman.test.legacyInput"] - /*||[clientAppId isEqual: @"ro.sync.exml.Oxygen"] - Oxygen has worse problems */ - ); - + BOOL isAppNonCompliant = (//[clientAppId isEqual: @"com.github.atom"] || + // 2023-12-19[sgs] Atom is now automatically detected as non-compliant + [clientAppId isEqual: @"com.collabora.libreoffice-free"] || + [clientAppId isEqual: @"org.libreoffice.script"] || + [clientAppId isEqual: @"org.vim.MacVim"] || + [clientAppId isEqual: @"io.brackets.appshell"] || + [clientAppId isEqual: @"com.axosoft.gitkraken"] || + [clientAppId isEqual: @"org.sil.app.builder.scripture.ScriptureAppBuilder"] || + [clientAppId isEqual: @"org.sil.app.builder.reading.ReadingAppBuilder"] || + [clientAppId isEqual: @"org.sil.app.builder.dictionary.DictionaryAppBuilder"] || + //[clientAppId isEqual: @"com.microsoft.Word"] || // 2020-11-24[mcd]: Appears to work well in Word 16.43, disable legacy by default + [clientAppId isEqual: @"org.openoffice.script"] || + // 2023-12-13[sgs]: Adobe apps automatically detected as non-compliant + //[clientAppId isEqual: @"com.adobe.illustrator"] || + //[clientAppId isEqual: @"com.adobe.InDesign"] || + //[clientAppId isEqual: @"com.adobe.Photoshop"] || + //[clientAppId isEqual: @"com.adobe.AfterEffects"] || + //[clientAppId isEqual: @"com.microsoft.VSCode"] || // 2023-05-29[sgs]: Works with 1.78.2, disable legacy by default + [clientAppId isEqual: @"com.google.Chrome"] || + // 2023-12-13[sgs]: must hard-code for Chrome because Google Docs returns relative but incorrect location so no way to auto-detect + [clientAppId hasPrefix: @"net.java"] || + [clientAppId isEqual: @"com.Keyman.test.legacyInput"] + /*||[clientAppId isEqual: @"ro.sync.exml.Oxygen"] - Oxygen has worse problems */ + ); + [self.appDelegate logDebugMessage:@"containedInHardCodedNoncompliantAppList: for app %@: %@", clientAppId, isAppNonCompliant?@"yes":@"no"]; return isAppNonCompliant; } @@ -246,17 +246,17 @@ - (BOOL)containedInHardCodedNoncompliantAppList:(NSString *)clientAppId { * Returns the list of application IDs for non-compliant apps */ - (NSArray *)noncompliantAppsUserDefaults { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; - return [userData arrayForKey:kKMLegacyApps]; + NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; + return [userData arrayForKey:kKMLegacyApps]; } /** -* Check this user-managed list to see if the application ID is among those known to be non-compliant. -*/ + * Check this user-managed list to see if the application ID is among those known to be non-compliant. + */ - (BOOL)containedInUserManagedNoncompliantAppList:(NSString *)clientAppId { BOOL isAppNonCompliant = NO; NSArray *legacyAppsUserDefaults = [self noncompliantAppsUserDefaults]; - + if(legacyAppsUserDefaults != nil) { isAppNonCompliant = [self arrayContainsApplicationId:clientAppId fromArray:legacyAppsUserDefaults]; } @@ -268,24 +268,24 @@ - (BOOL)containedInUserManagedNoncompliantAppList:(NSString *)clientAppId { * Checks array for a list of possible regexes to match a client app id */ - (BOOL)arrayContainsApplicationId:(NSString *)applicationId fromArray:(NSArray *)applicationArray { - for(id appId in applicationArray) { - if(![appId isKindOfClass:[NSString class]]) { - // always log this: bad data in UserDefaults - NSLog(@"arrayContainsApplicationId:fromArray: LegacyApps user defaults array should contain only strings"); - } else { - NSError *error = nil; - NSRange range = NSMakeRange(0, applicationId.length); - - NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern: (NSString *) appId options: 0 error: &error]; - NSArray *matchesArray = [regex matchesInString:applicationId options:0 range:range]; - if(matchesArray.count>0) { - [self.appDelegate logDebugMessage:@"arrayContainsApplicationId: found match for application ID %@: ", applicationId]; - return YES; - } - } + for(id appId in applicationArray) { + if(![appId isKindOfClass:[NSString class]]) { + // always log this: bad data in UserDefaults + NSLog(@"arrayContainsApplicationId:fromArray: LegacyApps user defaults array should contain only strings"); + } else { + NSError *error = nil; + NSRange range = NSMakeRange(0, applicationId.length); + + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern: (NSString *) appId options: 0 error: &error]; + NSArray *matchesArray = [regex matchesInString:applicationId options:0 range:range]; + if(matchesArray.count>0) { + [self.appDelegate logDebugMessage:@"arrayContainsApplicationId: found match for application ID %@: ", applicationId]; + return YES; + } } - - return NO; + } + + return NO; } -(BOOL) isComplianceUncertain { diff --git a/mac/Keyman4MacIM/Keyman4MacIM/main.m b/mac/Keyman4MacIM/Keyman4MacIM/main.m index 48e89243507..04388ae1aaa 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/main.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/main.m @@ -14,18 +14,18 @@ IMKServer *server; int main(int argc, const char * argv[]) { - NSString *identifier; - os_log_t configLog = os_log_create("org.sil.keyman", "startup"); + NSString *identifier; + os_log_t configLog = os_log_create("org.sil.keyman", "startup"); - @autoreleasepool { - identifier = [[NSBundle mainBundle] bundleIdentifier]; - server = [[IMKServer alloc] initWithName:(NSString *)kConnectionName bundleIdentifier:identifier]; - - BOOL didLoadNib = [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:[NSApplication sharedApplication] topLevelObjects: nil]; - - os_log_with_type(configLog, OS_LOG_TYPE_DEBUG, "main Did load MainMenu nib: %@", didLoadNib?@"YES":@"NO"); - - [[NSApplication sharedApplication] run]; - } - return 0; + @autoreleasepool { + identifier = [[NSBundle mainBundle] bundleIdentifier]; + server = [[IMKServer alloc] initWithName:(NSString *)kConnectionName bundleIdentifier:identifier]; + + BOOL didLoadNib = [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:[NSApplication sharedApplication] topLevelObjects: nil]; + + os_log_with_type(configLog, OS_LOG_TYPE_DEBUG, "main Did load MainMenu nib: %@", didLoadNib?@"YES":@"NO"); + + [[NSApplication sharedApplication] run]; + } + return 0; } diff --git a/mac/Keyman4MacIM/KeymanTests/AppleCompliantTestClient.m b/mac/Keyman4MacIM/KeymanTests/AppleCompliantTestClient.m index 53881a3115f..9dc1b51eb43 100644 --- a/mac/Keyman4MacIM/KeymanTests/AppleCompliantTestClient.m +++ b/mac/Keyman4MacIM/KeymanTests/AppleCompliantTestClient.m @@ -12,7 +12,7 @@ @implementation AppleCompliantTestClient - (NSAttributedString*)attributedSubstringFromRange:(NSRange)range { - return [[NSAttributedString alloc] initWithString:[super substringFromRangeProtected:range]]; + return [[NSAttributedString alloc] initWithString:[super substringFromRangeProtected:range]]; } @end diff --git a/mac/Keyman4MacIM/KeymanTests/InputMethodTests.m b/mac/Keyman4MacIM/KeymanTests/InputMethodTests.m index 0b06b99fee2..8eb9d974ceb 100644 --- a/mac/Keyman4MacIM/KeymanTests/InputMethodTests.m +++ b/mac/Keyman4MacIM/KeymanTests/InputMethodTests.m @@ -35,7 +35,7 @@ - (void)setUp { } - (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. + // Put teardown code here. This method is called after the invocation of each test method in the class. } - (void)testCalculateInsertRange_noDelete_returnsCurrentLocation { diff --git a/mac/Keyman4MacIM/KeymanTests/LegacyTestClient.m b/mac/Keyman4MacIM/KeymanTests/LegacyTestClient.m index c33055ebb68..a9b85ec3741 100644 --- a/mac/Keyman4MacIM/KeymanTests/LegacyTestClient.m +++ b/mac/Keyman4MacIM/KeymanTests/LegacyTestClient.m @@ -15,55 +15,55 @@ @implementation LegacyTestClient NSMutableString * _contents; - (instancetype)init{ - return [self initWithString:@""]; + return [self initWithString:@""]; } - (instancetype)initWithString:(NSString *)contents { - self = [super init]; - if (self) { - _contents = [[NSMutableString alloc] initWithString:contents]; - _selection = NSMakeRange(self.length, 0); - } - return self; + self = [super init]; + if (self) { + _contents = [[NSMutableString alloc] initWithString:contents]; + _selection = NSMakeRange(self.length, 0); + } + return self; } - (void)handleEventIfNotHandledBy: (KMInputMethodEventHandler *) im event:(NSEvent *)event { - if (![im handleEvent:event client:self]) { - if (event.keyCode == kVK_Delete) { - if (_selection.length == 0 && _selection.location > 0) - _selection = NSMakeRange(_selection.location - 1, 1); - if (_selection.length) { - [_contents deleteCharactersInRange:_selection]; - _selection = NSMakeRange(_selection.location, 0); - } - } - else { - [self insertTextProtected:event.characters replacementRange:_selection]; - } + if (![im handleEvent:event client:self]) { + if (event.keyCode == kVK_Delete) { + if (_selection.length == 0 && _selection.location > 0) + _selection = NSMakeRange(_selection.location - 1, 1); + if (_selection.length) { + [_contents deleteCharactersInRange:_selection]; + _selection = NSMakeRange(_selection.location, 0); + } + } + else { + [self insertTextProtected:event.characters replacementRange:_selection]; } + } } - (void)insertTextProtected:(id)string replacementRange:(NSRange)replacementRange { - [_contents deleteCharactersInRange:replacementRange]; - [_contents insertString:string atIndex:replacementRange.location]; - _selection = NSMakeRange(replacementRange.location + [string length], 0); + [_contents deleteCharactersInRange:replacementRange]; + [_contents insertString:string atIndex:replacementRange.location]; + _selection = NSMakeRange(replacementRange.location + [string length], 0); } - (NSString *)substringFromRangeProtected:(NSRange)range { - assert(range.location >= 0); - assert(range.location + range.length <= [self length]); - return [_contents substringWithRange:range]; + assert(range.location >= 0); + assert(range.location + range.length <= [self length]); + return [_contents substringWithRange:range]; } - (NSRange)selectedRange { - return _selection; + return _selection; } - (NSInteger)length { - return (NSInteger)_contents.length; + return (NSInteger)_contents.length; } - (NSString *) getResult { - return _contents; + return _contents; } @end diff --git a/mac/Keyman4MacIM/KeymanTests/NoContextTestClient.m b/mac/Keyman4MacIM/KeymanTests/NoContextTestClient.m index b0e2836d8d4..a6ff0f4f45f 100644 --- a/mac/Keyman4MacIM/KeymanTests/NoContextTestClient.m +++ b/mac/Keyman4MacIM/KeymanTests/NoContextTestClient.m @@ -12,11 +12,11 @@ @implementation NoContextTestClient - (void)insertText:(id)string replacementRange:(NSRange)replacementRange { - [super insertTextProtected: string replacementRange:replacementRange]; + [super insertTextProtected: string replacementRange:replacementRange]; } - (NSAttributedString*)attributedSubstringFromRange:(NSRange)range { - return nil; + return nil; } @end diff --git a/mac/Keyman4MacIM/KeymanTests/TestAppDelegate.m b/mac/Keyman4MacIM/KeymanTests/TestAppDelegate.m index e646e339054..4b247056af2 100644 --- a/mac/Keyman4MacIM/KeymanTests/TestAppDelegate.m +++ b/mac/Keyman4MacIM/KeymanTests/TestAppDelegate.m @@ -15,42 +15,42 @@ @implementation TestAppDelegate @synthesize contextBuffer = _contextBuffer; - (KMEngine *)kme { - if (_kme == nil) { - _kme = [[KMEngine alloc] initWithKMX:nil context:self.contextBuffer verboseLogging:self.debugMode]; - } - - return _kme; + if (_kme == nil) { + _kme = [[KMEngine alloc] initWithKMX:nil context:self.contextBuffer verboseLogging:self.debugMode]; + } + + return _kme; } - (void)setKmx:(KMXFile *)kmx { - _kmx = kmx; - [self.kme setKmx:_kmx]; + _kmx = kmx; + [self.kme setKmx:_kmx]; } - (NSMutableString *)contextBuffer { - if (_contextBuffer == nil) { - _contextBuffer = [[NSMutableString alloc] initWithString:@""]; - } - - return _contextBuffer; + if (_contextBuffer == nil) { + _contextBuffer = [[NSMutableString alloc] initWithString:@""]; + } + + return _contextBuffer; } - (void)setContextBuffer:(NSMutableString *)contextBuffer { - _contextBuffer = [contextBuffer mutableCopy]; - if (_contextBuffer.length) - [_contextBuffer replaceOccurrencesOfString:@"\0" withString:[NSString nullChar] options:0 range:NSMakeRange(0, 1)]; - [self.kme setCoreContextIfNeeded:self.contextBuffer]; + _contextBuffer = [contextBuffer mutableCopy]; + if (_contextBuffer.length) + [_contextBuffer replaceOccurrencesOfString:@"\0" withString:[NSString nullChar] options:0 range:NSMakeRange(0, 1)]; + [self.kme setCoreContextIfNeeded:self.contextBuffer]; } - (BOOL)debugMode { - return YES; + return YES; } -(NSEvent *)keyStrokeEventForCharacter:(NSString *)character keyCode:(unsigned short) keyCode { - return [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSZeroPoint modifierFlags:0 timestamp:NSTimeIntervalSince1970 windowNumber:0 context:nil characters:character charactersIgnoringModifiers:character isARepeat:NO keyCode:keyCode]; + return [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSZeroPoint modifierFlags:0 timestamp:NSTimeIntervalSince1970 windowNumber:0 context:nil characters:character charactersIgnoringModifiers:character isARepeat:NO keyCode:keyCode]; } - (void)postKeyboardEventWithSource: (CGEventSourceRef)source code:(CGKeyCode) virtualKey postCallback:(PostEventCallback)postEvent { - _virtualKeyPosted = virtualKey; + _virtualKeyPosted = virtualKey; } @end diff --git a/mac/Keyman4MacIM/KeymanTests/TextApiComplianceTests.m b/mac/Keyman4MacIM/KeymanTests/TextApiComplianceTests.m index 8b1c3be94df..2b3cce1a4d4 100644 --- a/mac/Keyman4MacIM/KeymanTests/TextApiComplianceTests.m +++ b/mac/Keyman4MacIM/KeymanTests/TextApiComplianceTests.m @@ -1,11 +1,11 @@ /** * Keyman is copyright (C) SIL International. MIT License. - * + * * TextApiComplianceTests.m * KeymanTests - * + * * Created by Shawn Schantz on 2024-04-08. - * + * * Unit tests of TextApiCompliance class */ @@ -29,11 +29,11 @@ - (BOOL)arrayContainsApplicationId:(NSString *)clientAppId fromArray:(NSArray *) @implementation TextApiComplianceTests - (void)setUp { - // Put setup code here. This method is called before the invocation of each test method in the class. + // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. + // Put teardown code here. This method is called after the invocation of each test method in the class. } - (void)testValidateNewLocation_locationNotFound_returnsNo { @@ -149,21 +149,21 @@ - (void)testIsClientAppLegacy_unlistedClientAppId_returnsNo { id client = [[AppleCompliantTestClient alloc] init]; NSString *clientAppId = @"com.compliant.app"; TextApiCompliance *apiCompliance = [[TextApiCompliance alloc]initWithClient:client applicationId:clientAppId]; - + NSArray *legacyAppsArray = [NSArray arrayWithObjects:@"com.microsoft.VSCode",@"com.adobe.Photoshop",nil]; - + BOOL isLegacy = [apiCompliance arrayContainsApplicationId:clientAppId fromArray:legacyAppsArray]; NSLog(@"isLegacy = %@", isLegacy?@"yes":@"no"); - XCTAssertFalse(isLegacy, @"App not expected to be in legacy list"); + XCTAssertFalse(isLegacy, @"App not expected to be in legacy list"); } - (void)testIsClientAppLegacy_listedClientAppId_returnsYes { id client = [[AppleCompliantTestClient alloc] init]; NSString *clientAppId = @"com.microsoft.VSCode"; TextApiCompliance *apiCompliance = [[TextApiCompliance alloc]initWithClient:client applicationId:clientAppId]; - + NSArray *legacyAppsArray = [NSArray arrayWithObjects:@"com.adobe.Photoshop",@"com.microsoft.VSCode",nil]; - + BOOL isLegacy = [apiCompliance arrayContainsApplicationId:clientAppId fromArray:legacyAppsArray]; XCTAssertTrue(isLegacy, @"App expected to be in legacy list"); } diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreHelper.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreHelper.m index b1c0a65fa27..8aa02433766 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreHelper.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreHelper.m @@ -1,11 +1,11 @@ /** * Keyman is copyright (C) SIL International. MIT License. - * + * * CoreHelper.m * Keyman - * + * * Created by Shawn Schantz on 2023-02-14. - * + * * A class to encapsulate type conversions between Keyman Core C++ code and * Keyman Engine for Mac Objective C code. * @@ -45,13 +45,13 @@ -(NSString *) createNSStringFromUnicharString:(unichar const *)string { } -(unsigned long long) unicharStringLength:(unichar const *)string { - unsigned long long length = 0llu; - if(NULL == string) return length; - - while('\0' != string[length]) - length++; - - return length; + unsigned long long length = 0llu; + if(NULL == string) return length; + + while('\0' != string[length]) + length++; + + return length; } /** @@ -107,7 +107,7 @@ -(UTF32Char)macToKeymanModifier:(NSEventModifierFlags)modifiers { } else if ([self isOptionKey:modifiers]) { keymanModifiers |= KM_CORE_MODIFIER_ALT; } - + if ([self isLeftControlKey:modifiers]) { keymanModifiers |= KM_CORE_MODIFIER_LCTRL; } else if ([self isRightControlKey:modifiers]) { @@ -122,8 +122,8 @@ -(UTF32Char)macToKeymanModifier:(NSEventModifierFlags)modifiers { // setting NOCAPS in Core breaks keyboards like EuroLatin and Amharic // apparently better to simply leave the CAPS bit clear /*else { - keymanModifiers |= KM_CORE_MODIFIER_NOCAPS; - }*/ + keymanModifiers |= KM_CORE_MODIFIER_NOCAPS; + }*/ [self logDebugMessage:@"macToKeymanModifier result = %u", (unsigned int)keymanModifiers]; return keymanModifiers; @@ -167,7 +167,7 @@ -(BOOL)isOptionKey:(NSEventModifierFlags) modifiers { */ -(NSString*)utf32ValueToString:(UTF32Char)scalarValue { NSData * characterData = [[NSData alloc] initWithBytes:&scalarValue length:sizeof(scalarValue)]; - + NSString *characterString=[[NSString alloc] initWithBytes:[characterData bytes] length:[characterData length] encoding:NSUTF32LittleEndianStringEncoding]; [self logDebugMessage:@"utf32ValueToString data: '%@', string: %@", characterData, characterString]; return characterString; @@ -183,7 +183,7 @@ -(NSString*)utf32CStringToString:(UTF32Char*)utf32CString { if (utf32StringLength > 0) { characterString=[[NSString alloc] initWithBytes:utf32CString length:utf32StringLength*4 encoding:NSUTF32LittleEndianStringEncoding]; } - + return characterString; } @@ -192,79 +192,79 @@ -(NSString*)utf32CStringToString:(UTF32Char*)utf32CString { // Creates a VK map to convert Mac VK codes to Windows VK codes - (void)initVirtualKeyMapping { - VirtualKeyMap[MVK_A] = VK_KEY_A; // A - VirtualKeyMap[MVK_S] = VK_KEY_S; // S - VirtualKeyMap[MVK_D] = VK_KEY_D; // D - VirtualKeyMap[MVK_F] = VK_KEY_F; // F - VirtualKeyMap[MVK_H] = VK_KEY_H; // H - VirtualKeyMap[MVK_G] = VK_KEY_G; // G - VirtualKeyMap[MVK_Z] = VK_KEY_Z; // Z - VirtualKeyMap[MVK_X] = VK_KEY_X; // X - VirtualKeyMap[MVK_C] = VK_KEY_C; // C - VirtualKeyMap[MVK_V] = VK_KEY_V; // V - // 0x0A = nil - VirtualKeyMap[MVK_B] = VK_KEY_B; // B - VirtualKeyMap[MVK_Q] = VK_KEY_Q; // Q - VirtualKeyMap[MVK_W] = VK_KEY_W; // W - VirtualKeyMap[MVK_E] = VK_KEY_E; // E - VirtualKeyMap[MVK_R] = VK_KEY_R; // R - VirtualKeyMap[MVK_Y] = VK_KEY_Y; // Y - VirtualKeyMap[MVK_T] = VK_KEY_T; // T - VirtualKeyMap[MVK_1] = VK_KEY_1; // 1 - VirtualKeyMap[MVK_2] = VK_KEY_2; // 2 - VirtualKeyMap[MVK_3] = VK_KEY_3; // 3 - VirtualKeyMap[MVK_4] = VK_KEY_4; // 4 - VirtualKeyMap[MVK_6] = VK_KEY_6; // 6 - VirtualKeyMap[MVK_5] = VK_KEY_5; // 5 - VirtualKeyMap[MVK_EQUAL] = VK_EQUAL; // = - VirtualKeyMap[MVK_9] = VK_KEY_9; // 9 - VirtualKeyMap[MVK_7] = VK_KEY_7; // 7 - VirtualKeyMap[MVK_MINUS] = VK_MINUS; // - - VirtualKeyMap[MVK_8] = VK_KEY_8; // 8 - VirtualKeyMap[MVK_0] = VK_KEY_0; // 0 - VirtualKeyMap[MVK_RIGHT_BRACKET] = VK_RIGHT_BRACKET; // ] - VirtualKeyMap[MVK_O] = VK_KEY_O; // O - VirtualKeyMap[MVK_U] = VK_KEY_U; // U - VirtualKeyMap[MVK_LEFT_BRACKET] = VK_LEFT_BRACKET; // [ - VirtualKeyMap[MVK_I] = VK_KEY_I; // I - VirtualKeyMap[MVK_P] = VK_KEY_P; // P - VirtualKeyMap[MVK_ENTER] = VK_ENTER; // - VirtualKeyMap[MVK_L] = VK_KEY_L; // L - VirtualKeyMap[MVK_J] = VK_KEY_J; // J - VirtualKeyMap[MVK_QUOTE] = VK_QUOTE; // ' - VirtualKeyMap[MVK_K] = VK_KEY_K; // K - VirtualKeyMap[MVK_SEMICOLON] = VK_SEMICOLON; // ; - VirtualKeyMap[MVK_BACKSLASH] = VK_BACKSLASH; // '\' - VirtualKeyMap[MVK_COMMA] = VK_COMMA; // , - VirtualKeyMap[MVK_SLASH] = VK_SLASH; // '/' - VirtualKeyMap[MVK_N] = VK_KEY_N; // N - VirtualKeyMap[MVK_M] = VK_KEY_M; // M - VirtualKeyMap[MVK_PERIOD] = VK_PERIOD; // . - VirtualKeyMap[MVK_TAB] = VK_TAB; // - VirtualKeyMap[MVK_SPACE] = VK_SPACE; // - VirtualKeyMap[MVK_GRAVE] = VK_GRAVE; // ` - VirtualKeyMap[MVK_BACKSPACE] = VK_BACKSPACE; // - VirtualKeyMap[MVK_OEM102] = VK_OEM_102; // 102nd key (ISO keyboards) - - // Num Pad - VirtualKeyMap[0x41] = VK_NUMPAD_DECIMAL; // Decimal . - VirtualKeyMap[0x43] = VK_NUMPAD_MULTIPLY; // Multiply * - VirtualKeyMap[0x45] = VK_NUMPAD_ADD; // Add + - VirtualKeyMap[0x47] = 0x00; // *** Undefined *** - VirtualKeyMap[0x4B] = VK_NUMPAD_DIVIDE; // Divide / - VirtualKeyMap[0x4C] = 0x00; // *** Undefined *** - VirtualKeyMap[0x4E] = VK_NUMPAD_SUBTRACT; // Subtract - - VirtualKeyMap[0x51] = 0x00; // Equal = *** Undefined *** - VirtualKeyMap[0x52] = VK_NUMPAD0; // 0 - VirtualKeyMap[0x53] = VK_NUMPAD1; // 1 - VirtualKeyMap[0x54] = VK_NUMPAD2; // 2 - VirtualKeyMap[0x55] = VK_NUMPAD3; // 3 - VirtualKeyMap[0x56] = VK_NUMPAD4; // 4 - VirtualKeyMap[0x57] = VK_NUMPAD5; // 5 - VirtualKeyMap[0x58] = VK_NUMPAD6; // 6 - VirtualKeyMap[0x59] = VK_NUMPAD7; // 7 - VirtualKeyMap[0x5B] = VK_NUMPAD8; // 8 - VirtualKeyMap[0x5C] = VK_NUMPAD9; // 9 + VirtualKeyMap[MVK_A] = VK_KEY_A; // A + VirtualKeyMap[MVK_S] = VK_KEY_S; // S + VirtualKeyMap[MVK_D] = VK_KEY_D; // D + VirtualKeyMap[MVK_F] = VK_KEY_F; // F + VirtualKeyMap[MVK_H] = VK_KEY_H; // H + VirtualKeyMap[MVK_G] = VK_KEY_G; // G + VirtualKeyMap[MVK_Z] = VK_KEY_Z; // Z + VirtualKeyMap[MVK_X] = VK_KEY_X; // X + VirtualKeyMap[MVK_C] = VK_KEY_C; // C + VirtualKeyMap[MVK_V] = VK_KEY_V; // V + // 0x0A = nil + VirtualKeyMap[MVK_B] = VK_KEY_B; // B + VirtualKeyMap[MVK_Q] = VK_KEY_Q; // Q + VirtualKeyMap[MVK_W] = VK_KEY_W; // W + VirtualKeyMap[MVK_E] = VK_KEY_E; // E + VirtualKeyMap[MVK_R] = VK_KEY_R; // R + VirtualKeyMap[MVK_Y] = VK_KEY_Y; // Y + VirtualKeyMap[MVK_T] = VK_KEY_T; // T + VirtualKeyMap[MVK_1] = VK_KEY_1; // 1 + VirtualKeyMap[MVK_2] = VK_KEY_2; // 2 + VirtualKeyMap[MVK_3] = VK_KEY_3; // 3 + VirtualKeyMap[MVK_4] = VK_KEY_4; // 4 + VirtualKeyMap[MVK_6] = VK_KEY_6; // 6 + VirtualKeyMap[MVK_5] = VK_KEY_5; // 5 + VirtualKeyMap[MVK_EQUAL] = VK_EQUAL; // = + VirtualKeyMap[MVK_9] = VK_KEY_9; // 9 + VirtualKeyMap[MVK_7] = VK_KEY_7; // 7 + VirtualKeyMap[MVK_MINUS] = VK_MINUS; // - + VirtualKeyMap[MVK_8] = VK_KEY_8; // 8 + VirtualKeyMap[MVK_0] = VK_KEY_0; // 0 + VirtualKeyMap[MVK_RIGHT_BRACKET] = VK_RIGHT_BRACKET; // ] + VirtualKeyMap[MVK_O] = VK_KEY_O; // O + VirtualKeyMap[MVK_U] = VK_KEY_U; // U + VirtualKeyMap[MVK_LEFT_BRACKET] = VK_LEFT_BRACKET; // [ + VirtualKeyMap[MVK_I] = VK_KEY_I; // I + VirtualKeyMap[MVK_P] = VK_KEY_P; // P + VirtualKeyMap[MVK_ENTER] = VK_ENTER; // + VirtualKeyMap[MVK_L] = VK_KEY_L; // L + VirtualKeyMap[MVK_J] = VK_KEY_J; // J + VirtualKeyMap[MVK_QUOTE] = VK_QUOTE; // ' + VirtualKeyMap[MVK_K] = VK_KEY_K; // K + VirtualKeyMap[MVK_SEMICOLON] = VK_SEMICOLON; // ; + VirtualKeyMap[MVK_BACKSLASH] = VK_BACKSLASH; // '\' + VirtualKeyMap[MVK_COMMA] = VK_COMMA; // , + VirtualKeyMap[MVK_SLASH] = VK_SLASH; // '/' + VirtualKeyMap[MVK_N] = VK_KEY_N; // N + VirtualKeyMap[MVK_M] = VK_KEY_M; // M + VirtualKeyMap[MVK_PERIOD] = VK_PERIOD; // . + VirtualKeyMap[MVK_TAB] = VK_TAB; // + VirtualKeyMap[MVK_SPACE] = VK_SPACE; // + VirtualKeyMap[MVK_GRAVE] = VK_GRAVE; // ` + VirtualKeyMap[MVK_BACKSPACE] = VK_BACKSPACE; // + VirtualKeyMap[MVK_OEM102] = VK_OEM_102; // 102nd key (ISO keyboards) + + // Num Pad + VirtualKeyMap[0x41] = VK_NUMPAD_DECIMAL; // Decimal . + VirtualKeyMap[0x43] = VK_NUMPAD_MULTIPLY; // Multiply * + VirtualKeyMap[0x45] = VK_NUMPAD_ADD; // Add + + VirtualKeyMap[0x47] = 0x00; // *** Undefined *** + VirtualKeyMap[0x4B] = VK_NUMPAD_DIVIDE; // Divide / + VirtualKeyMap[0x4C] = 0x00; // *** Undefined *** + VirtualKeyMap[0x4E] = VK_NUMPAD_SUBTRACT; // Subtract - + VirtualKeyMap[0x51] = 0x00; // Equal = *** Undefined *** + VirtualKeyMap[0x52] = VK_NUMPAD0; // 0 + VirtualKeyMap[0x53] = VK_NUMPAD1; // 1 + VirtualKeyMap[0x54] = VK_NUMPAD2; // 2 + VirtualKeyMap[0x55] = VK_NUMPAD3; // 3 + VirtualKeyMap[0x56] = VK_NUMPAD4; // 4 + VirtualKeyMap[0x57] = VK_NUMPAD5; // 5 + VirtualKeyMap[0x58] = VK_NUMPAD6; // 6 + VirtualKeyMap[0x59] = VK_NUMPAD7; // 7 + VirtualKeyMap[0x5B] = VK_NUMPAD8; // 8 + VirtualKeyMap[0x5C] = VK_NUMPAD9; // 9 } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreKeyOutput.h b/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreKeyOutput.h index 026354ecc31..73d264ba156 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreKeyOutput.h +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreKeyOutput.h @@ -1,9 +1,9 @@ /** * Keyman is copyright (C) SIL International. MIT License. - * + * * CoreKeyOutput.h * Keyman - * + * * Created by Shawn Schantz on 2023-10-31. */ diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreKeyOutput.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreKeyOutput.m index 4dd92aca1dc..7ab8fdfd6b2 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreKeyOutput.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreKeyOutput.m @@ -33,7 +33,7 @@ -(instancetype)init:(NSUInteger)codePointsToDelete textToDelete:(NSString*)delet -(NSString *)description { NSData* data = [self.textToInsert dataUsingEncoding:NSUTF16LittleEndianStringEncoding]; - + return [[NSString alloc] initWithFormat: @"codePointsToDeleteBeforeInsert: %li, textToInsert: '%@', optionsToPersist: %@, alert: %d, emitKeystroke: %d, capsLockState: %d ", self.codePointsToDeleteBeforeInsert, data, self.optionsToPersist, self.alert, self.emitKeystroke, self.capsLockState]; } diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreWrapper.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreWrapper.m index 065096528ad..4c8b2884141 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreWrapper.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/CoreWrapper/CoreWrapper.m @@ -32,7 +32,7 @@ -(instancetype)initWithHelper:(CoreHelper*)helper kmxFilePath:(nullable NSString self = [super init]; if (self) { _coreHelper = helper; - + // if the kmxFilePath has been provided, then load the keyboard now if (path != nil) { [self changeKeyboardWithKmxFilePath: path]; @@ -79,7 +79,7 @@ -(void) dealloc{ -(void)loadKeyboardUsingCore:(NSString*) path { km_core_path_name keyboardPath = [path UTF8String]; km_core_status result = km_core_keyboard_load(keyboardPath, &_coreKeyboard); - + if (result != KM_CORE_STATUS_OK) { NSString *message = [NSString stringWithFormat:@"Unexpected Keyman Core result: %u", result]; [NSException raise:@"LoadKeyboardException" format:@"%@", message]; @@ -90,7 +90,7 @@ -(void)readKeyboardAttributesUsingCore { if (self.coreKeyboard != nil) { const km_core_keyboard_attrs * keyboardAttributes; km_core_status result = km_core_keyboard_get_attrs(self.coreKeyboard, &keyboardAttributes); - + if (result==KM_CORE_STATUS_OK) { _keyboardVersion = [self.coreHelper createNSStringFromUnicharString:keyboardAttributes->version_string]; _keyboardId = [self.coreHelper createNSStringFromUnicharString:keyboardAttributes->id]; @@ -103,50 +103,50 @@ -(void)readKeyboardAttributesUsingCore { -(void)createKeyboardStateUsingCore { km_core_status result = KM_CORE_STATUS_OK; - + // TODO: create once // create option list km_core_option_item coreEnvironment[CORE_ENVIRONMENT_ARRAY_LENGTH] = {0}; - + if([CoreWrapper setupCoreEnvironment:coreEnvironment]) { // create state using keyboard and option list result = km_core_state_create(self.coreKeyboard, coreEnvironment, &_coreState); - + if (result != KM_CORE_STATUS_OK) { NSString *message = [NSString stringWithFormat:@"Unexpected Keyman Core result: %u", result]; [NSException raise:@"CreateKeyboardStateException" format:@"%@", message]; } } else { - NSLog(@"CoreWrapper, Unable to set environment options for keyboard" ); + NSLog(@"CoreWrapper, Unable to set environment options for keyboard" ); } } -(CoreKeyOutput*)processEvent:(nonnull NSEvent *)event { NSEventModifierFlags modifiers = event.modifierFlags; - + // process key down events only if (event.type != NSEventTypeKeyDown) { - return nil; + return nil; } // do not process command keys if (modifiers & NSEventModifierFlagCommand) { - return nil; + return nil; } - + return [self processMacVirtualKey:event.keyCode withModifiers:modifiers withKeyDown:YES]; } -(CoreKeyOutput*)processMacVirtualKey:(unsigned short)macKeyCode - withModifiers:(NSEventModifierFlags)modifiers - withKeyDown:(BOOL) isKeyDown { + withModifiers:(NSEventModifierFlags)modifiers + withKeyDown:(BOOL) isKeyDown { CoreKeyOutput *output = nil; uint16_t windowsKeyCode = [self.coreHelper macVirtualKeyToWindowsVirtualKey:macKeyCode]; uint32_t modifierState = [self.coreHelper macToKeymanModifier:modifiers]; uint8_t keyDown = (isKeyDown) ? 1 : 0; - + if ([self processVirtualKey:windowsKeyCode - withModifier:modifierState + withModifier:modifierState withKeyDown:keyDown]) { output = [self loadOutputForLastKeyProcessed]; } @@ -156,13 +156,13 @@ -(CoreKeyOutput*)processMacVirtualKey:(unsigned short)macKeyCode -(BOOL)processVirtualKey:(uint16_t)keyCode withModifier:(uint16_t)modifierState withKeyDown:(uint8_t) isKeyDown { - + km_core_status result = km_core_process_event(self.coreState, keyCode, modifierState, isKeyDown, KM_CORE_EVENT_FLAG_DEFAULT); - + if (result!=KM_CORE_STATUS_OK) { [self.coreHelper logDebugMessage:@"km_core_process_event() result = %u\n", result]; } - + return (result==KM_CORE_STATUS_OK); } @@ -182,9 +182,9 @@ -(CoreKeyOutput*) createCoreKeyOutputForActionsStruct:(km_core_actions*)actions NSDictionary* options = [self convertOptionsArray:actions->persist_options]; CapsLockState capsLock = [self convertCapsLockState:actions->new_caps_lock_state]; NSString* deletedText = [self.coreHelper utf32CStringToString:actions->deleted_context]; - + CoreKeyOutput* coreKeyOutput = [[CoreKeyOutput alloc] init: actions->code_points_to_delete textToDelete:deletedText textToInsert:text optionsToPersist:options alert:actions->do_alert emitKeystroke:actions->emit_keystroke capsLockState:capsLock]; - + return coreKeyOutput; } @@ -195,7 +195,7 @@ -(NSDictionary*)convertOptionsArray:(km_core_option_item*)options { for (; options->key != 0; ++options) { unichar const * optionsKey = options->key; unichar const * valueKey = options->value; - + NSString *key = [self.coreHelper createNSStringFromUnicharString:optionsKey]; NSString *value = [self.coreHelper createNSStringFromUnicharString:valueKey]; [optionsDictionary setObject:value forKey:key]; @@ -238,7 +238,7 @@ -(NSString*)contextDebug { km_core_cu * context = km_core_state_context_debug(self.coreState, KM_CORE_DEBUG_CONTEXT_CACHED); NSString *debugString = [self.coreHelper createNSStringFromUnicharString:context]; km_core_cu_dispose(context); - + [self.coreHelper logDebugMessage:@"CoreWrapper contextDebug = %@", debugString]; return debugString; } @@ -248,40 +248,40 @@ +(BOOL)setupCoreEnvironment:(km_core_option_item *) coreOptionArray { coreOptionArray[0].scope = KM_CORE_OPT_ENVIRONMENT; coreOptionArray[0].key = KM_CORE_KMX_ENV_BASELAYOUT; coreOptionArray[0].value = u"kbdus.dll"; // const char16_t*, encoded as UTF-16 - + coreOptionArray[1].scope = KM_CORE_OPT_ENVIRONMENT; coreOptionArray[1].key = KM_CORE_KMX_ENV_BASELAYOUTALT; coreOptionArray[1].value = u"en-US"; // const char16_t*, encoded as UTF-16 - + coreOptionArray[2].scope = KM_CORE_OPT_ENVIRONMENT; coreOptionArray[2].key = KM_CORE_KMX_ENV_SIMULATEALTGR; coreOptionArray[2].value = u"0"; // const char16_t*, encoded as UTF-16 - + coreOptionArray[3].scope = KM_CORE_OPT_ENVIRONMENT; coreOptionArray[3].key = KM_CORE_KMX_ENV_BASELAYOUTGIVESCTRLRALTFORRALT; coreOptionArray[3].value = u"0"; // const char16_t*, encoded as UTF-16 - + coreOptionArray[4].scope = KM_CORE_OPT_ENVIRONMENT; coreOptionArray[4].key = KM_CORE_KMX_ENV_PLATFORM; coreOptionArray[4].value = u"mac macos macosx hardware desktop native"; // const char16_t*, encoded as UTF-16 - + coreOptionArray[5] = (km_core_option_item) {0}; - + return TRUE; } -(BOOL)setOptionsForCore: (NSString *) key value:(NSString *) value { [self.coreHelper logDebugMessage:@"setOptionsForCore, key = %@, value = %@", key, value]; - + // array of length 2, second item is terminating null struct km_core_option_item option[2] = {0}; option[0].key = [self.coreHelper createUnicharStringFromNSString: key]; option[0].value = [self.coreHelper createUnicharStringFromNSString: value]; option[0].scope = KM_CORE_OPT_KEYBOARD; - + km_core_status result = km_core_state_options_update(self.coreState, &option[0]); [self.coreHelper logDebugMessage:@"setOptionsForCore, km_core_state_options_update result = %d", result]; - + return (result==KM_CORE_STATUS_OK); } @@ -289,9 +289,9 @@ -(void)readCoreOptions: (km_core_cu const *) key { km_core_cu const * valueFromCore = nil; km_core_status result = km_core_state_option_lookup(self.coreState, - KM_CORE_OPT_KEYBOARD, - key, - &valueFromCore); + KM_CORE_OPT_KEYBOARD, + key, + &valueFromCore); if (result == KM_CORE_STATUS_OK) { if (valueFromCore) { [self.coreHelper logDebugMessage:@"km_core_state_option_lookup successful, current value set in core= %@", [self.coreHelper createNSStringFromUnicharString:valueFromCore]]; @@ -305,7 +305,7 @@ -(void)readCoreOptions: (km_core_cu const *) key { [self.coreHelper logDebugMessage:@"km_core_state_option_lookup returned nil, result = %d", result]; } } - + } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMBinaryFileFormat.h b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMBinaryFileFormat.h index d91f9b4f40e..8126b1d5e75 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMBinaryFileFormat.h +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMBinaryFileFormat.h @@ -14,21 +14,21 @@ typedef uint32_t DWORD; //typedef wchar_t* PWSTR; struct COMP_KEYBOARD { - DWORD dwIdentifier; // 0000 Keyman compiled keyboard id - DWORD dwFileVersion; // 0004 Version of the file - Keyman 4.0 is 0x0400 - DWORD dwCheckSum; // 0008 As stored in keyboard. DEPRECATED as of 16.0 - DWORD KeyboardID; // 000C as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts - DWORD IsRegistered; // 0010 - DWORD version; // 0014 keyboard version - DWORD cxStoreArray; // 0018 in array entries - DWORD cxGroupArray; // 001C in array entries - DWORD dpStoreArray; // 0020 [LPCOMP_STORE] address of first item in store array - DWORD dpGroupArray; // 0024 [LPCOMP_GROUP] address of first item in group array - DWORD StartGroup[2]; // 0028 index of starting groups [2 of them] - DWORD dwFlags; // 0030 Flags for the keyboard file - DWORD dwHotKey; // 0034 standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey) - DWORD dpBitmapOffset; // 0038 offset of the bitmaps in the file - DWORD dwBitmapSize; // 003C size in bytes of the bitmaps + DWORD dwIdentifier; // 0000 Keyman compiled keyboard id + DWORD dwFileVersion; // 0004 Version of the file - Keyman 4.0 is 0x0400 + DWORD dwCheckSum; // 0008 As stored in keyboard. DEPRECATED as of 16.0 + DWORD KeyboardID; // 000C as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts + DWORD IsRegistered; // 0010 + DWORD version; // 0014 keyboard version + DWORD cxStoreArray; // 0018 in array entries + DWORD cxGroupArray; // 001C in array entries + DWORD dpStoreArray; // 0020 [LPCOMP_STORE] address of first item in store array + DWORD dpGroupArray; // 0024 [LPCOMP_GROUP] address of first item in group array + DWORD StartGroup[2]; // 0028 index of starting groups [2 of them] + DWORD dwFlags; // 0030 Flags for the keyboard file + DWORD dwHotKey; // 0034 standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey) + DWORD dpBitmapOffset; // 0038 offset of the bitmaps in the file + DWORD dwBitmapSize; // 003C size in bytes of the bitmaps }; #define VERSION_30 0x00000300 @@ -50,18 +50,18 @@ struct COMP_KEYBOARD { #define VERSION_MAX VERSION_170 struct COMP_GROUP { - DWORD dpName; // string (only debug) - DWORD dpKeyArray; // [LPCOMP_KEY] address of first item in key array - DWORD dpMatch; // extended string - DWORD dpNoMatch; // extended string - DWORD cxKeyArray; // in array entries - BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not + DWORD dpName; // string (only debug) + DWORD dpKeyArray; // [LPCOMP_KEY] address of first item in key array + DWORD dpMatch; // extended string + DWORD dpNoMatch; // extended string + DWORD cxKeyArray; // in array entries + BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not }; struct COMP_STORE { - DWORD dwSystemID; - DWORD dpName; // string (only debug) - DWORD dpString; // extended string + DWORD dwSystemID; + DWORD dpName; // string (only debug) + DWORD dpString; // extended string }; // dwSystemID definitions @@ -134,9 +134,9 @@ struct COMP_STORE { #define K_CTRLFLAG 0x0020 // Either ctrl flag #define K_ALTFLAG 0x0040 // Either alt flag //#define K_METAFLAG 0x0080 // Either Meta-key flag (tentative). Not usable in keyboard rules; - // Used internally (currently, only by KMW) to ensure Meta-key - // shortcuts safely bypass rules - // Meta key = Command key on macOS, Windows key on Windows +// Used internally (currently, only by KMW) to ensure Meta-key +// shortcuts safely bypass rules +// Meta key = Command key on macOS, Windows key on Windows #define CAPITALFLAG 0x0100 // Caps lock on #define NOTCAPITALFLAG 0x0200 // Caps lock NOT on #define NUMLOCKFLAG 0x0400 // Num lock on @@ -149,11 +149,11 @@ struct COMP_STORE { #define K_CAPITALMASK (CAPITALFLAG|NOTCAPITALFLAG) struct COMP_KEY { - WORD Key; // Windows VK code or character value (VIRTUALCHARKEY, ISVIRTUALKEY) - DWORD Line; - DWORD ShiftFlags; - DWORD dpOutput; // extended string - DWORD dpContext; // extended string + WORD Key; // Windows VK code or character value (VIRTUALCHARKEY, ISVIRTUALKEY) + DWORD Line; + DWORD ShiftFlags; + DWORD dpOutput; // extended string + DWORD dpContext; // extended string }; #define UC_SENTINEL 0xFFFF diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompGroup.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompGroup.m index 24a5a33adc8..1aaa3760848 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompGroup.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompGroup.m @@ -12,22 +12,22 @@ @implementation KMCompGroup - (id)init { - self = [super init]; - if (self) { - _name = @""; - _keys = [[NSMutableArray alloc] initWithCapacity:0]; - _match = @""; - _noMatch = @""; - } - - return self; + self = [super init]; + if (self) { + _name = @""; + _keys = [[NSMutableArray alloc] initWithCapacity:0]; + _match = @""; + _noMatch = @""; + } + + return self; } - (NSString *)description { - NSString *format = @"<%@:%p, Name:%@ Match:%@ NoMatch:%@ fUsingKeys:%d Keys:%@>"; - NSString *str = [NSString stringWithFormat:format, - [self className], self, _name, [_match codeString], [_noMatch codeString], _fUsingKeys, _keys]; - return str; + NSString *format = @"<%@:%p, Name:%@ Match:%@ NoMatch:%@ fUsingKeys:%d Keys:%@>"; + NSString *str = [NSString stringWithFormat:format, + [self className], self, _name, [_match codeString], [_noMatch codeString], _fUsingKeys, _keys]; + return str; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompKey.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompKey.m index 42fe5394891..f8508dbf4cf 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompKey.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompKey.m @@ -12,20 +12,20 @@ @implementation KMCompKey - (id)init { - self = [super init]; - if (self) { - _output = @""; - _context = @""; - } - - return self; + self = [super init]; + if (self) { + _output = @""; + _context = @""; + } + + return self; } - (NSString *)description { - NSString *format = @"<%@:%p K:0x%X L:0x%X F:0x%X O:%@ C:%@>"; - NSString *str = [NSString stringWithFormat:format, - self.className, self, self.key, self.line, self.shiftFlags, [self.output codeString], [self.context codeString]]; - return str; + NSString *format = @"<%@:%p K:0x%X L:0x%X F:0x%X O:%@ C:%@>"; + NSString *str = [NSString stringWithFormat:format, + self.className, self, self.key, self.line, self.shiftFlags, [self.output codeString], [self.context codeString]]; + return str; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompStore.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompStore.m index 9f7c6dc9c65..fbc510ed045 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompStore.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMCompStore.m @@ -11,169 +11,169 @@ @implementation KMCompStore - (id)init { - self = [super init]; - if (self) { - _systemID = @""; - _name = @""; - _string = @""; - } - - return self; + self = [super init]; + if (self) { + _systemID = @""; + _name = @""; + _string = @""; + } + + return self; } - (id)copyWithZone:(NSZone *)zone { - KMCompStore *newStore = [[[self class] allocWithZone:zone] init]; - - if (newStore) { - [newStore setDwSystemID:[self dwSystemID]]; - if ([self name]) newStore.name = [[NSString alloc] initWithString:[self name]]; - if ([self string]) newStore.string = [[NSString alloc] initWithString:[self string]]; - } - - return newStore; + KMCompStore *newStore = [[[self class] allocWithZone:zone] init]; + + if (newStore) { + [newStore setDwSystemID:[self dwSystemID]]; + if ([self name]) newStore.name = [[NSString alloc] initWithString:[self name]]; + if ([self string]) newStore.string = [[NSString alloc] initWithString:[self string]]; + } + + return newStore; } - (NSString *)description { - NSString *format = @"<%@:%p ID:0x%X DN:%@ N:%@ S:%@>"; - NSString *str = [NSString stringWithFormat:format, - self.className, self, self.dwSystemID, self.systemID, self.name, self.string]; - return str; + NSString *format = @"<%@:%p ID:0x%X DN:%@ N:%@ S:%@>"; + NSString *str = [NSString stringWithFormat:format, + self.className, self, self.dwSystemID, self.systemID, self.name, self.string]; + return str; } - (void)setDwSystemID:(DWORD)dwID { - _dwSystemID = dwID; - _systemID = [self TSS_DEF_NAME:_dwSystemID]; + _dwSystemID = dwID; + _systemID = [self TSS_DEF_NAME:_dwSystemID]; } - (NSString *)TSS_DEF_NAME:(DWORD)d { - switch (d) { - case TSS_NONE: - return @"TSS_NONE"; - break; - case TSS_BITMAP: - return @"TSS_BITMAP"; - break; - case TSS_COPYRIGHT: - return @"TSS_COPYRIGHT"; - break; - case TSS_HOTKEY: - return @"TSS_HOTKEY"; - break; - case TSS_LANGUAGE: - return @"TSS_LANGUAGE"; - break; - case TSS_LAYOUT: - return @"TSS_LAYOUT"; - break; - case TSS_MESSAGE: - return @"TSS_MESSAGE"; - break; - case TSS_NAME: - return @"TSS_NAME"; - break; - case TSS_VERSION: - return @"TSS_VERSION"; - break; - case TSS_CAPSONONLY: - return @"TSS_CAPSONONLY"; - break; - case TSS_CAPSALWAYSOFF: - return @"TSS_CAPSALWAYSOFF"; - break; - case TSS_SHIFTFREESCAPS: - return @"TSS_SHIFTFREESCAPS"; - break; - case TSS_LANGUAGENAME: - return @"TSS_LANGUAGENAME"; - break; - case TSS_CALLDEFINITION: - return @"TSS_CALLDEFINITION"; - break; - case TSS_CALLDEFINITION_LOADFAILED: - return @"TSS_CALLDEFINITION_LOADFAILED"; - break; - case TSS_ETHNOLOGUECODE: - return @"TSS_ETHNOLOGUECODE"; - break; - case TSS_DEBUG_LINE: - return @"TSS_DEBUG_LINE"; - break; - case TSS_MNEMONIC: - return @"TSS_MNEMONIC"; - break; - case TSS_INCLUDECODES: - return @"TSS_INCLUDECODES"; - break; - case TSS_OLDCHARPOSMATCHING: - return @"TSS_OLDCHARPOSMATCHING"; - break; - case TSS_COMPILEDVERSION: - return @"TSS_COMPILEDVERSION"; - break; - case TSS_KEYMANCOPYRIGHT: - return @"TSS_KEYMANCOPYRIGHT:"; - break; - case TSS_CUSTOMKEYMANEDITION: - return @"TSS_CUSTOMKEYMANEDITION"; - break; - case TSS_CUSTOMKEYMANEDITIONNAME: - return @"TSS_CUSTOMKEYMANEDITIONNAME"; - break; - case TSS_VISUALKEYBOARD: - return @"TSS_VISUALKEYBOARD"; - break; - case TSS_KMW_RTL: - return @"TSS_KMW_RTL"; - break; - case TSS_KMW_HELPFILE: - return @"TSS_HELPFILE"; - break; - case TSS_KMW_HELPTEXT: - return @"TSS_HELPTEXT"; - break; - case TSS_KMW_EMBEDJS: - return @"TSS_EMBEDJS"; - break; - case TSS_WINDOWSLANGUAGES: - return @"TSS_WINDOWSLANGUAGES"; - break; - case TSS_COMPARISON: - return @"TSS_COMPARISON"; - break; - case TSS_PLATFORM: - return @"TSS_PLATFORM"; - break; - case TSS_BASELAYOUT: - return @"TSS_BASELAYOUT"; - break; - case TSS_LAYER: - return @"TSS_LAYER"; - break; - case TSS_PLATFORM_NOMATCH: - return @"TSS_PLATFORM_NOMATCH"; - break; - case TSS_PLATFORM_MATCH: - return @"TSS_PLATFORM_MATCH"; - break; - case TSS_VKDICTIONARY: - return @"TSS_VKDICTIONARY"; - break; - case TSS_LAYOUTFILE: - return @"TSS_LAYOUTFILE"; - break; - case TSS_KEYBOARDVERSION: - return @"TSS_KEYBOARDVERSION"; - break; - case TSS_KMW_EMBEDCSS: - return @"TSS_KMW_EMBEDCSS"; - break; - case TSS_TARGETS: - return @"TSS_TARGETS"; - break; - default: - return nil; - break; - } + switch (d) { + case TSS_NONE: + return @"TSS_NONE"; + break; + case TSS_BITMAP: + return @"TSS_BITMAP"; + break; + case TSS_COPYRIGHT: + return @"TSS_COPYRIGHT"; + break; + case TSS_HOTKEY: + return @"TSS_HOTKEY"; + break; + case TSS_LANGUAGE: + return @"TSS_LANGUAGE"; + break; + case TSS_LAYOUT: + return @"TSS_LAYOUT"; + break; + case TSS_MESSAGE: + return @"TSS_MESSAGE"; + break; + case TSS_NAME: + return @"TSS_NAME"; + break; + case TSS_VERSION: + return @"TSS_VERSION"; + break; + case TSS_CAPSONONLY: + return @"TSS_CAPSONONLY"; + break; + case TSS_CAPSALWAYSOFF: + return @"TSS_CAPSALWAYSOFF"; + break; + case TSS_SHIFTFREESCAPS: + return @"TSS_SHIFTFREESCAPS"; + break; + case TSS_LANGUAGENAME: + return @"TSS_LANGUAGENAME"; + break; + case TSS_CALLDEFINITION: + return @"TSS_CALLDEFINITION"; + break; + case TSS_CALLDEFINITION_LOADFAILED: + return @"TSS_CALLDEFINITION_LOADFAILED"; + break; + case TSS_ETHNOLOGUECODE: + return @"TSS_ETHNOLOGUECODE"; + break; + case TSS_DEBUG_LINE: + return @"TSS_DEBUG_LINE"; + break; + case TSS_MNEMONIC: + return @"TSS_MNEMONIC"; + break; + case TSS_INCLUDECODES: + return @"TSS_INCLUDECODES"; + break; + case TSS_OLDCHARPOSMATCHING: + return @"TSS_OLDCHARPOSMATCHING"; + break; + case TSS_COMPILEDVERSION: + return @"TSS_COMPILEDVERSION"; + break; + case TSS_KEYMANCOPYRIGHT: + return @"TSS_KEYMANCOPYRIGHT:"; + break; + case TSS_CUSTOMKEYMANEDITION: + return @"TSS_CUSTOMKEYMANEDITION"; + break; + case TSS_CUSTOMKEYMANEDITIONNAME: + return @"TSS_CUSTOMKEYMANEDITIONNAME"; + break; + case TSS_VISUALKEYBOARD: + return @"TSS_VISUALKEYBOARD"; + break; + case TSS_KMW_RTL: + return @"TSS_KMW_RTL"; + break; + case TSS_KMW_HELPFILE: + return @"TSS_HELPFILE"; + break; + case TSS_KMW_HELPTEXT: + return @"TSS_HELPTEXT"; + break; + case TSS_KMW_EMBEDJS: + return @"TSS_EMBEDJS"; + break; + case TSS_WINDOWSLANGUAGES: + return @"TSS_WINDOWSLANGUAGES"; + break; + case TSS_COMPARISON: + return @"TSS_COMPARISON"; + break; + case TSS_PLATFORM: + return @"TSS_PLATFORM"; + break; + case TSS_BASELAYOUT: + return @"TSS_BASELAYOUT"; + break; + case TSS_LAYER: + return @"TSS_LAYER"; + break; + case TSS_PLATFORM_NOMATCH: + return @"TSS_PLATFORM_NOMATCH"; + break; + case TSS_PLATFORM_MATCH: + return @"TSS_PLATFORM_MATCH"; + break; + case TSS_VKDICTIONARY: + return @"TSS_VKDICTIONARY"; + break; + case TSS_LAYOUTFILE: + return @"TSS_LAYOUTFILE"; + break; + case TSS_KEYBOARDVERSION: + return @"TSS_KEYBOARDVERSION"; + break; + case TSS_KMW_EMBEDCSS: + return @"TSS_KMW_EMBEDCSS"; + break; + case TSS_TARGETS: + return @"TSS_TARGETS"; + break; + default: + return nil; + break; + } } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m index ea59fb950d0..71a59411778 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMEngine.m @@ -31,19 +31,19 @@ @implementation KMEngine const NSString* kEasterEggKmxName = @"EnglishSpanish.kmx"; - (id)initWithKMX:(KMXFile *)kmx context:(NSString *)contextString verboseLogging:(BOOL)enableDebugLogging { - self = [super init]; - if (self) { - self.debugMode = enableDebugLogging; - _kmx = kmx; - _coreHelper = [[CoreHelper alloc] initWithDebugMode:enableDebugLogging]; - - if (kmx) { - [self loadCoreWrapperFromKmxFile:self.kmx.filePath]; - [self.coreWrapper setContextIfNeeded:contextString]; - } + self = [super init]; + if (self) { + self.debugMode = enableDebugLogging; + _kmx = kmx; + _coreHelper = [[CoreHelper alloc] initWithDebugMode:enableDebugLogging]; + + if (kmx) { + [self loadCoreWrapperFromKmxFile:self.kmx.filePath]; + [self.coreWrapper setContextIfNeeded:contextString]; } - - return self; + } + + return self; } -(void)loadCoreWrapperFromKmxFile:(NSString *)kmxFilePath { @@ -66,27 +66,27 @@ -(void)setKmx:(KMXFile*) kmxFile { } - (void)setUseVerboseLogging:(BOOL)useVerboseLogging { - self.debugMode = useVerboseLogging; - - if (self.coreHelper) { - self.coreHelper.debugMode = useVerboseLogging; - } - - if (useVerboseLogging) { - NSLog(@"KMEngine - Turning verbose logging on"); - // In Keyman Engine if "debugMode" is turned on (explicitly) with "English plus Spanish" as the current keyboard and you type "Sentrycrash#KME", - // it will force a simulated crash to test reporting to sentry.keyman.com. - NSString * kmxName = [[_kmx filePath] lastPathComponent]; - NSLog(@"Sentry - KME: _kmx name = %@", kmxName); - if ([kEasterEggKmxName isEqualToString:kmxName]) { - NSLog(@"Sentry - KME: Preparing to detect Easter egg."); - _easterEggForSentry = [[NSMutableString alloc] init]; - } - else - _easterEggForSentry = nil; + self.debugMode = useVerboseLogging; + + if (self.coreHelper) { + self.coreHelper.debugMode = useVerboseLogging; + } + + if (useVerboseLogging) { + NSLog(@"KMEngine - Turning verbose logging on"); + // In Keyman Engine if "debugMode" is turned on (explicitly) with "English plus Spanish" as the current keyboard and you type "Sentrycrash#KME", + // it will force a simulated crash to test reporting to sentry.keyman.com. + NSString * kmxName = [[_kmx filePath] lastPathComponent]; + NSLog(@"Sentry - KME: _kmx name = %@", kmxName); + if ([kEasterEggKmxName isEqualToString:kmxName]) { + NSLog(@"Sentry - KME: Preparing to detect Easter egg."); + _easterEggForSentry = [[NSMutableString alloc] init]; } else - NSLog(@"KMEngine - Turning verbose logging off"); + _easterEggForSentry = nil; + } + else + NSLog(@"KMEngine - Turning verbose logging off"); } - (NSString *)getCoreContextDebug { @@ -111,82 +111,82 @@ - (void)setCoreOptions:(NSString *)key withValue:(NSString *)value { */ - (CoreKeyOutput *)processEvent:(NSEvent *)event { if (!self.kmx) - return nil; - + return nil; + return [self.coreWrapper processEvent:event]; } - (void) processPossibleEasterEggCharacterFrom:(NSString *)characters { - NSUInteger len = [_easterEggForSentry length]; - NSLog(@"Sentry - KME: Processing character(s): %@", characters); - if ([characters length] == 1 && [characters characterAtIndex:0] == [kEasterEggText characterAtIndex:len]) { - NSString *characterToAdd = [kEasterEggText substringWithRange:NSMakeRange(len, 1)]; - NSLog(@"Sentry - KME: Adding character to Easter Egg code string: %@", characterToAdd); - [_easterEggForSentry appendString:characterToAdd]; - if ([kEasterEggText isEqualToString:_easterEggForSentry]) { - NSLog(@"Sentry - KME: Forcing crash now!"); - // Both of the following approaches do throw an exception that causes control to exit this method, - // but at least in my debug builds locally, neither one seems to get picked up by Sentry in a - // way that results in a new report on sentry.keyman.com - + NSUInteger len = [_easterEggForSentry length]; + NSLog(@"Sentry - KME: Processing character(s): %@", characters); + if ([characters length] == 1 && [characters characterAtIndex:0] == [kEasterEggText characterAtIndex:len]) { + NSString *characterToAdd = [kEasterEggText substringWithRange:NSMakeRange(len, 1)]; + NSLog(@"Sentry - KME: Adding character to Easter Egg code string: %@", characterToAdd); + [_easterEggForSentry appendString:characterToAdd]; + if ([kEasterEggText isEqualToString:_easterEggForSentry]) { + NSLog(@"Sentry - KME: Forcing crash now!"); + // Both of the following approaches do throw an exception that causes control to exit this method, + // but at least in my debug builds locally, neither one seems to get picked up by Sentry in a + // way that results in a new report on sentry.keyman.com + #ifndef USE_ALERT_SHOW_HELP_TO_FORCE_EASTER_EGG_CRASH_FROM_ENGINE - //#1 - @throw ([NSException exceptionWithName:@"SentryForce" reason:@"Easter egg hit" userInfo:nil]); - - //#2 - // NSDecimalNumber *i = [NSDecimalNumber decimalNumberWithDecimal:[@(1) decimalValue]]; - // NSDecimalNumber *o = [NSDecimalNumber decimalNumberWithDecimal:[@(0) decimalValue]]; - // // Divide by 0 to throw an exception - // NSDecimalNumber *x = [i decimalNumberByDividingBy:o]; - + //#1 + @throw ([NSException exceptionWithName:@"SentryForce" reason:@"Easter egg hit" userInfo:nil]); + + //#2 + // NSDecimalNumber *i = [NSDecimalNumber decimalNumberWithDecimal:[@(1) decimalValue]]; + // NSDecimalNumber *o = [NSDecimalNumber decimalNumberWithDecimal:[@(0) decimalValue]]; + // // Divide by 0 to throw an exception + // NSDecimalNumber *x = [i decimalNumberByDividingBy:o]; + #else - //#3 The following DOES work, but it's really lame because the crash actually gets forced in the IM - // via this bogus call to a protocol method implemented in the IM's App Delegate just for the - // purpose of enabling the engine to force a crash. - [(NSObject *)[NSApp delegate] alertShowHelp:[NSAlert alertWithMessageText:@"Forcing an error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"Forcing an Easter egg error from KME!"]]; + //#3 The following DOES work, but it's really lame because the crash actually gets forced in the IM + // via this bogus call to a protocol method implemented in the IM's App Delegate just for the + // purpose of enabling the engine to force a crash. + [(NSObject *)[NSApp delegate] alertShowHelp:[NSAlert alertWithMessageText:@"Forcing an error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"Forcing an Easter egg error from KME!"]]; #endif - - NSLog(@"Sentry - KME: You should not be seeing this line!"); - } - } - else if (len > 0) { - NSLog(@"Sentry - KME: Clearing Easter Egg code string."); - [_easterEggForSentry setString:@""]; + + NSLog(@"Sentry - KME: You should not be seeing this line!"); } + } + else if (len > 0) { + NSLog(@"Sentry - KME: Clearing Easter Egg code string."); + [_easterEggForSentry setString:@""]; + } } - (NSString *)getCharsFromKeyCode:(UInt16)keyCode { - TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardLayoutInputSource(); - CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); - const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr); - - if (keyboardLayout) { - UInt32 deadKeyState = 0; - UniCharCount maxStringLength = 255; - UniCharCount actualStringLength = 0; - UniChar unicodeString[maxStringLength]; - - OSStatus status = UCKeyTranslate(keyboardLayout, - keyCode, kUCKeyActionDown, 0, - LMGetKbdType(), 0, - &deadKeyState, - maxStringLength, - &actualStringLength, unicodeString); - - if (actualStringLength == 0 && deadKeyState) { - status = UCKeyTranslate(keyboardLayout, - kVK_Space, kUCKeyActionDown, 0, - LMGetKbdType(), 0, - &deadKeyState, - maxStringLength, - &actualStringLength, unicodeString); - } - - if (actualStringLength > 0 && status == noErr) - return [NSString stringWithCharacters:unicodeString length:(NSUInteger)actualStringLength]; + TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardLayoutInputSource(); + CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); + const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr); + + if (keyboardLayout) { + UInt32 deadKeyState = 0; + UniCharCount maxStringLength = 255; + UniCharCount actualStringLength = 0; + UniChar unicodeString[maxStringLength]; + + OSStatus status = UCKeyTranslate(keyboardLayout, + keyCode, kUCKeyActionDown, 0, + LMGetKbdType(), 0, + &deadKeyState, + maxStringLength, + &actualStringLength, unicodeString); + + if (actualStringLength == 0 && deadKeyState) { + status = UCKeyTranslate(keyboardLayout, + kVK_Space, kUCKeyActionDown, 0, + LMGetKbdType(), 0, + &deadKeyState, + maxStringLength, + &actualStringLength, unicodeString); } - - return nil; + + if (actualStringLength > 0 && status == noErr) + return [NSString stringWithCharacters:unicodeString length:(NSUInteger)actualStringLength]; + } + + return nil; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMXFile.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMXFile.m index a2c705519a7..6fa222c2b02 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMXFile.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KMXFile.m @@ -21,235 +21,235 @@ @implementation KMXFile - (id)initWithFilePath:(NSString *)path { - self = [super init]; - if (self) { - if (path == nil) { - _filePath = nil; - return nil; - } - - - NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; - if (file == nil) { - //NSLog(@"Failed to open kmx file"); - _filePath = nil; - return nil; - } - else { - _filePath = [NSString stringWithString:path]; - } - - struct COMP_KEYBOARD cmp_kb; - [file seekToFileOffset:0]; - size_t size = sizeof(cmp_kb); - NSData *dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&cmp_kb length:size]; - - if (cmp_kb.dwFileVersion < VERSION_MIN || cmp_kb.dwFileVersion > VERSION_MAX) { - [file closeFile]; - return nil; - } - - _identifier = cmp_kb.dwIdentifier; - _fileVersion = cmp_kb.dwFileVersion; - _keyboardID = cmp_kb.KeyboardID; - _isRegistered = (cmp_kb.IsRegistered == 0?NO:YES); - _version = cmp_kb.version; - NSMutableArray *mStartGroup = [[NSMutableArray alloc] initWithCapacity:2]; - [mStartGroup addObject:[NSNumber numberWithInt:cmp_kb.StartGroup[0]]]; - [mStartGroup addObject:[NSNumber numberWithInt:cmp_kb.StartGroup[1]]]; - _startGroup = [[NSArray alloc] initWithArray:mStartGroup]; - _flags = cmp_kb.dwFlags; - _hotKey = cmp_kb.dwHotKey; - - struct COMP_STORE cmp_str[cmp_kb.cxStoreArray]; - [file seekToFileOffset:cmp_kb.dpStoreArray]; - size = sizeof(cmp_str); - dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:cmp_str length:size]; - NSMutableArray *mStore = [[NSMutableArray alloc] initWithCapacity:cmp_kb.cxStoreArray]; - for (int i = 0; i < cmp_kb.cxStoreArray; i++) { - KMCompStore *kmStore = [[KMCompStore alloc] init]; - kmStore.dwSystemID = cmp_str[i].dwSystemID; - kmStore.name = [KMXFile UTF16StringWithPointer:cmp_str[i].dpName inFile:file]; - - if (kmStore.dwSystemID == TSS_VERSION) - kmStore.string = [[KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file] stringByReplacingOccurrencesOfString:@"\n" withString:@""]; - else { - kmStore.string = [KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file]; - if (kmStore.dwSystemID == TSS_MNEMONIC && [kmStore.string isEqualToString:@"1"]) - _isMnemonic = YES; - } - - if (kmStore.dwSystemID == TSS_VERSION) - kmStore.string = [[KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file] stringByReplacingOccurrencesOfString:@"\n" withString:@""]; - else - kmStore.string = [KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file]; - - [mStore addObject:kmStore]; - } - - _store = [[NSArray alloc] initWithArray:mStore]; - _storeSaved = [[NSArray alloc] initWithArray:mStore copyItems:YES]; - - struct COMP_GROUP cmp_grp[cmp_kb.cxGroupArray]; - [file seekToFileOffset:cmp_kb.dpGroupArray]; - size = sizeof(cmp_grp); - dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:cmp_grp length:size]; - - NSMutableArray *mGroup = [[NSMutableArray alloc] initWithCapacity:cmp_kb.cxGroupArray]; - for (int i = 0; i < cmp_kb.cxGroupArray; i++) { - KMCompGroup *kmGrp = [[KMCompGroup alloc] init]; - kmGrp.name = [KMXFile UTF16StringWithPointer:cmp_grp[i].dpName inFile:file]; - kmGrp.match = [KMXFile UTF16StringWithPointer:cmp_grp[i].dpMatch inFile:file]; - kmGrp.noMatch = [KMXFile UTF16StringWithPointer:cmp_grp[i].dpNoMatch inFile:file]; - kmGrp.fUsingKeys = cmp_grp[i].fUsingKeys; - - struct COMP_KEY cmp_keys[cmp_grp[i].cxKeyArray]; - [file seekToFileOffset:cmp_grp[i].dpKeyArray]; - size = sizeof(cmp_keys); - dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:cmp_keys length:size]; - - for (int j = 0; j < cmp_grp[i].cxKeyArray; j++) { - KMCompKey *kmKey = [[KMCompKey alloc] init]; - kmKey.key = cmp_keys[j].Key; - kmKey.line = cmp_keys[j].Line; - kmKey.shiftFlags = cmp_keys[j].ShiftFlags; - kmKey.output = [KMXFile UTF16StringWithPointer:cmp_keys[j].dpOutput inFile:file]; - kmKey.context = [KMXFile UTF16StringWithPointer:cmp_keys[j].dpContext inFile:file]; - [kmGrp.keys addObject:kmKey]; - } - - [mGroup addObject:kmGrp]; - } - _group = [[NSArray alloc] initWithArray:mGroup]; - - [file seekToFileOffset:cmp_kb.dpBitmapOffset]; - NSData *bitmapData = [file readDataOfLength:cmp_kb.dwBitmapSize]; - NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:bitmapData]; - _bitmap = [[NSImage alloc] initWithCGImage:imageRep.CGImage size:NSMakeSize(CGImageGetWidth(imageRep.CGImage), CGImageGetHeight(imageRep.CGImage))]; - - [file closeFile]; - } - - return self; -} - -- (NSString *)description { - NSString *format = @"<%@: %p, File version: 0x%X Flags: 0x%X Store: %@ Group: %@>"; - NSString *str = [NSString stringWithFormat:format, - self.className, self, self.fileVersion, self.flags, self.store, self.group]; - return str; -} - -- (BOOL)isValid { - for (KMCompGroup *gp in self.group) { - if ((gp.match && ![gp.match isValidCode]) || (gp.noMatch && ![gp.noMatch isValidCode])) - return NO; - - for (KMCompKey *kmKey in gp.keys) { - if (![kmKey.context isValidCode] || ![kmKey.output isValidCode]) - return NO; - } + self = [super init]; + if (self) { + if (path == nil) { + _filePath = nil; + return nil; } - - return YES; -} - -+ (NSDictionary *)keyboardInfoFromKmxFile:(NSString *)path { + + NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; - if (file == nil) { - //NSLog(@"Failed to open file"); - return nil; + //NSLog(@"Failed to open kmx file"); + _filePath = nil; + return nil; } - - + else { + _filePath = [NSString stringWithString:path]; + } + struct COMP_KEYBOARD cmp_kb; [file seekToFileOffset:0]; size_t size = sizeof(cmp_kb); NSData *dataBuffer = [file readDataOfLength:size]; [dataBuffer getBytes:&cmp_kb length:size]; - + if (cmp_kb.dwFileVersion < VERSION_MIN || cmp_kb.dwFileVersion > VERSION_MAX) { - [file closeFile]; - return nil; + [file closeFile]; + return nil; } - + + _identifier = cmp_kb.dwIdentifier; + _fileVersion = cmp_kb.dwFileVersion; + _keyboardID = cmp_kb.KeyboardID; + _isRegistered = (cmp_kb.IsRegistered == 0?NO:YES); + _version = cmp_kb.version; + NSMutableArray *mStartGroup = [[NSMutableArray alloc] initWithCapacity:2]; + [mStartGroup addObject:[NSNumber numberWithInt:cmp_kb.StartGroup[0]]]; + [mStartGroup addObject:[NSNumber numberWithInt:cmp_kb.StartGroup[1]]]; + _startGroup = [[NSArray alloc] initWithArray:mStartGroup]; + _flags = cmp_kb.dwFlags; + _hotKey = cmp_kb.dwHotKey; + struct COMP_STORE cmp_str[cmp_kb.cxStoreArray]; [file seekToFileOffset:cmp_kb.dpStoreArray]; size = sizeof(cmp_str); dataBuffer = [file readDataOfLength:size]; [dataBuffer getBytes:cmp_str length:size]; - - NSString *nameStr = nil; - NSString *verStr = nil; - NSString *copyrightStr = nil; - NSString *visualKeyboard = nil; + NSMutableArray *mStore = [[NSMutableArray alloc] initWithCapacity:cmp_kb.cxStoreArray]; for (int i = 0; i < cmp_kb.cxStoreArray; i++) { - if (cmp_str[i].dwSystemID == TSS_NAME) - nameStr = [KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file]; - if (cmp_str[i].dwSystemID == TSS_VERSION) - verStr = [[KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file] stringByReplacingOccurrencesOfString:@"\n" withString:@""]; - if (cmp_str[i].dwSystemID == TSS_COPYRIGHT) - copyrightStr = [KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file]; - if (cmp_str[i].dwSystemID == TSS_VISUALKEYBOARD) - visualKeyboard = [KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file]; + KMCompStore *kmStore = [[KMCompStore alloc] init]; + kmStore.dwSystemID = cmp_str[i].dwSystemID; + kmStore.name = [KMXFile UTF16StringWithPointer:cmp_str[i].dpName inFile:file]; + + if (kmStore.dwSystemID == TSS_VERSION) + kmStore.string = [[KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file] stringByReplacingOccurrencesOfString:@"\n" withString:@""]; + else { + kmStore.string = [KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file]; + if (kmStore.dwSystemID == TSS_MNEMONIC && [kmStore.string isEqualToString:@"1"]) + _isMnemonic = YES; + } + + if (kmStore.dwSystemID == TSS_VERSION) + kmStore.string = [[KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file] stringByReplacingOccurrencesOfString:@"\n" withString:@""]; + else + kmStore.string = [KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file]; + + [mStore addObject:kmStore]; } - + + _store = [[NSArray alloc] initWithArray:mStore]; + _storeSaved = [[NSArray alloc] initWithArray:mStore copyItems:YES]; + + struct COMP_GROUP cmp_grp[cmp_kb.cxGroupArray]; + [file seekToFileOffset:cmp_kb.dpGroupArray]; + size = sizeof(cmp_grp); + dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:cmp_grp length:size]; + + NSMutableArray *mGroup = [[NSMutableArray alloc] initWithCapacity:cmp_kb.cxGroupArray]; + for (int i = 0; i < cmp_kb.cxGroupArray; i++) { + KMCompGroup *kmGrp = [[KMCompGroup alloc] init]; + kmGrp.name = [KMXFile UTF16StringWithPointer:cmp_grp[i].dpName inFile:file]; + kmGrp.match = [KMXFile UTF16StringWithPointer:cmp_grp[i].dpMatch inFile:file]; + kmGrp.noMatch = [KMXFile UTF16StringWithPointer:cmp_grp[i].dpNoMatch inFile:file]; + kmGrp.fUsingKeys = cmp_grp[i].fUsingKeys; + + struct COMP_KEY cmp_keys[cmp_grp[i].cxKeyArray]; + [file seekToFileOffset:cmp_grp[i].dpKeyArray]; + size = sizeof(cmp_keys); + dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:cmp_keys length:size]; + + for (int j = 0; j < cmp_grp[i].cxKeyArray; j++) { + KMCompKey *kmKey = [[KMCompKey alloc] init]; + kmKey.key = cmp_keys[j].Key; + kmKey.line = cmp_keys[j].Line; + kmKey.shiftFlags = cmp_keys[j].ShiftFlags; + kmKey.output = [KMXFile UTF16StringWithPointer:cmp_keys[j].dpOutput inFile:file]; + kmKey.context = [KMXFile UTF16StringWithPointer:cmp_keys[j].dpContext inFile:file]; + [kmGrp.keys addObject:kmKey]; + } + + [mGroup addObject:kmGrp]; + } + _group = [[NSArray alloc] initWithArray:mGroup]; + [file seekToFileOffset:cmp_kb.dpBitmapOffset]; NSData *bitmapData = [file readDataOfLength:cmp_kb.dwBitmapSize]; NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:bitmapData]; - NSImage *icon = [[NSImage alloc] initWithCGImage:imageRep.CGImage size:NSMakeSize(CGImageGetWidth(imageRep.CGImage), CGImageGetHeight(imageRep.CGImage))]; - + _bitmap = [[NSImage alloc] initWithCGImage:imageRep.CGImage size:NSMakeSize(CGImageGetWidth(imageRep.CGImage), CGImageGetHeight(imageRep.CGImage))]; + [file closeFile]; + } + + return self; +} - if (!nameStr || !nameStr.length) { - nameStr = [path.lastPathComponent stringByReplacingOccurrencesOfString:@".kmx" withString:@""]; - } - if (!verStr) - verStr = @""; - if (!copyrightStr) - copyrightStr = @""; +- (NSString *)description { + NSString *format = @"<%@: %p, File version: 0x%X Flags: 0x%X Store: %@ Group: %@>"; + NSString *str = [NSString stringWithFormat:format, + self.className, self, self.fileVersion, self.flags, self.store, self.group]; + return str; +} - NSDictionary *info; - if (icon) { - info = [[NSDictionary alloc] initWithObjectsAndKeys:nameStr, kKMKeyboardNameKey, - verStr, kKMKeyboardVersionKey, - copyrightStr, kKMKeyboardCopyrightKey, - icon, kKMKeyboardIconKey, - visualKeyboard, kKMVisualKeyboardKey, nil]; - } - else { - info = [[NSDictionary alloc] initWithObjectsAndKeys:nameStr, kKMKeyboardNameKey, - verStr, kKMKeyboardVersionKey, - copyrightStr, kKMKeyboardCopyrightKey, - visualKeyboard, kKMVisualKeyboardKey, nil]; +- (BOOL)isValid { + for (KMCompGroup *gp in self.group) { + if ((gp.match && ![gp.match isValidCode]) || (gp.noMatch && ![gp.noMatch isValidCode])) + return NO; + + for (KMCompKey *kmKey in gp.keys) { + if (![kmKey.context isValidCode] || ![kmKey.output isValidCode]) + return NO; } + } + + return YES; +} - return info; ++ (NSDictionary *)keyboardInfoFromKmxFile:(NSString *)path { + NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; + + if (file == nil) { + //NSLog(@"Failed to open file"); + return nil; + } + + + struct COMP_KEYBOARD cmp_kb; + [file seekToFileOffset:0]; + size_t size = sizeof(cmp_kb); + NSData *dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:&cmp_kb length:size]; + + if (cmp_kb.dwFileVersion < VERSION_MIN || cmp_kb.dwFileVersion > VERSION_MAX) { + [file closeFile]; + return nil; + } + + struct COMP_STORE cmp_str[cmp_kb.cxStoreArray]; + [file seekToFileOffset:cmp_kb.dpStoreArray]; + size = sizeof(cmp_str); + dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:cmp_str length:size]; + + NSString *nameStr = nil; + NSString *verStr = nil; + NSString *copyrightStr = nil; + NSString *visualKeyboard = nil; + for (int i = 0; i < cmp_kb.cxStoreArray; i++) { + if (cmp_str[i].dwSystemID == TSS_NAME) + nameStr = [KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file]; + if (cmp_str[i].dwSystemID == TSS_VERSION) + verStr = [[KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file] stringByReplacingOccurrencesOfString:@"\n" withString:@""]; + if (cmp_str[i].dwSystemID == TSS_COPYRIGHT) + copyrightStr = [KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file]; + if (cmp_str[i].dwSystemID == TSS_VISUALKEYBOARD) + visualKeyboard = [KMXFile UTF16StringWithPointer:cmp_str[i].dpString inFile:file]; + } + + [file seekToFileOffset:cmp_kb.dpBitmapOffset]; + NSData *bitmapData = [file readDataOfLength:cmp_kb.dwBitmapSize]; + NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:bitmapData]; + NSImage *icon = [[NSImage alloc] initWithCGImage:imageRep.CGImage size:NSMakeSize(CGImageGetWidth(imageRep.CGImage), CGImageGetHeight(imageRep.CGImage))]; + + [file closeFile]; + + if (!nameStr || !nameStr.length) { + nameStr = [path.lastPathComponent stringByReplacingOccurrencesOfString:@".kmx" withString:@""]; + } + if (!verStr) + verStr = @""; + if (!copyrightStr) + copyrightStr = @""; + + NSDictionary *info; + if (icon) { + info = [[NSDictionary alloc] initWithObjectsAndKeys:nameStr, kKMKeyboardNameKey, + verStr, kKMKeyboardVersionKey, + copyrightStr, kKMKeyboardCopyrightKey, + icon, kKMKeyboardIconKey, + visualKeyboard, kKMVisualKeyboardKey, nil]; + } + else { + info = [[NSDictionary alloc] initWithObjectsAndKeys:nameStr, kKMKeyboardNameKey, + verStr, kKMKeyboardVersionKey, + copyrightStr, kKMKeyboardCopyrightKey, + visualKeyboard, kKMVisualKeyboardKey, nil]; + } + + return info; } + (NSString *)UTF16StringWithPointer:(DWORD)dp inFile:(NSFileHandle *)file { - if (dp == 0) - return nil; - - [file seekToFileOffset:dp]; - UTF16Char ch = '\0'; - size_t size = sizeof(ch); - NSData *dataBuffer = [file readDataOfLength:size]; + if (dp == 0) + return nil; + + [file seekToFileOffset:dp]; + UTF16Char ch = '\0'; + size_t size = sizeof(ch); + NSData *dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:&ch length:size]; + NSMutableString *mStr = [NSMutableString stringWithString:@""]; + while (ch != '\0') { + //if (ch != '\n') + [mStr appendString:[NSString stringWithCharacters:&ch length:1]]; + dataBuffer = [file readDataOfLength:size]; [dataBuffer getBytes:&ch length:size]; - NSMutableString *mStr = [NSMutableString stringWithString:@""]; - while (ch != '\0') { - //if (ch != '\n') - [mStr appendString:[NSString stringWithCharacters:&ch length:1]]; - dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&ch length:size]; - } - - return mStr; + } + + return mStr; } diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KVKFile.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KVKFile.m index 80c0ccf84be..202426d853d 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KVKFile.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/KVKFile.m @@ -12,141 +12,141 @@ @implementation KVKFile - (id)initWithFilePath:(NSString *)path { - self = [super init]; - if (self) { - if (path == nil) { - _filePath = nil; - return nil; - } - - NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; - if (file == nil) { - //NSLog(@"Failed to open kvk file"); - _filePath = nil; - return nil; - } - else { - _filePath = [NSString stringWithString:path]; - } - - [file seekToFileOffset:0]; - DWORD dwMagic; - size_t size = sizeof(dwMagic); - NSData *dataBuffer = [file readDataOfLength:size]; - _magic = [[NSString alloc] initWithData:dataBuffer encoding:NSUTF8StringEncoding]; - - size = sizeof(_version); - dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&_version length:size]; - - size = sizeof(_flags); - dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&_flags length:size]; - - _associatedKeyboard = [KVKFile NStringFromFile:file]; - _ansiFont = [KVKFile NFontFromFile:file]; - _unicodeFont = [KVKFile NFontFromFile:file]; - - DWORD keyCount; - size = sizeof(keyCount); - dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&keyCount length:size]; - - NSMutableArray *mKeys = [[NSMutableArray alloc] initWithCapacity:keyCount]; - for (int i = 0; i < keyCount; i++) { - [mKeys addObject:[KVKFile NKeyFromFile:file]]; - } - - _keys = [NSArray arrayWithArray:mKeys]; - - [file closeFile]; + self = [super init]; + if (self) { + if (path == nil) { + _filePath = nil; + return nil; } - return self; -} - -- (NSString *)description { - NSString *format = @"<%@:%p\nM:%@\nV:0x%X\nF:0x%X\nAK:%@\nAF:%@\nUF:%@\n>"; - NSString *str = [NSString stringWithFormat:format, - self.className, self, self.magic, self.version, self.flags, self.associatedKeyboard, self.ansiFont, self.unicodeFont]; - return str; -} - -+ (NSString *)NStringFromFile:(NSFileHandle *)file { - WORD strLen; - size_t size = sizeof(strLen); - NSData *dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&strLen length:size]; - - WORD ch; - size = sizeof(ch); - NSMutableString *mStr = [NSMutableString stringWithString:@""]; - for (int i = 0; i < strLen; i++) { - dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&ch length:size]; - if (ch > 0) - [mStr appendString:[NSString stringWithFormat:@"%C", ch]]; + NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; + if (file == nil) { + //NSLog(@"Failed to open kvk file"); + _filePath = nil; + return nil; + } + else { + _filePath = [NSString stringWithString:path]; } - return [NSString stringWithString:mStr]; -} - -+ (NFont *)NFontFromFile:(NSFileHandle *)file { - NFont *nfont = [[NFont alloc] init]; - nfont.name = [KVKFile NStringFromFile:file]; - - DWORD fSize; - size_t size = sizeof(fSize); + [file seekToFileOffset:0]; + DWORD dwMagic; + size_t size = sizeof(dwMagic); NSData *dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&fSize length:size]; - nfont.size = fSize; + _magic = [[NSString alloc] initWithData:dataBuffer encoding:NSUTF8StringEncoding]; - DWORD fColor; - size = sizeof(fColor); + size = sizeof(_version); dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&fColor length:size]; - nfont.color = fColor; + [dataBuffer getBytes:&_version length:size]; - return nfont; -} - -+ (NKey *)NKeyFromFile:(NSFileHandle *)file { - NKey *nkey = [[NKey alloc] init]; + size = sizeof(_flags); + dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:&_flags length:size]; - Byte flags; - size_t size = sizeof(flags); - NSData *dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&flags length:size]; - nkey.flags = flags; + _associatedKeyboard = [KVKFile NStringFromFile:file]; + _ansiFont = [KVKFile NFontFromFile:file]; + _unicodeFont = [KVKFile NFontFromFile:file]; - WORD shift; - size = sizeof(shift); + DWORD keyCount; + size = sizeof(keyCount); dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&shift length:size]; - nkey.shift = shift; + [dataBuffer getBytes:&keyCount length:size]; - WORD vkey; - size = sizeof(vkey); - dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&vkey length:size]; - nkey.vkey = vkey; + NSMutableArray *mKeys = [[NSMutableArray alloc] initWithCapacity:keyCount]; + for (int i = 0; i < keyCount; i++) { + [mKeys addObject:[KVKFile NKeyFromFile:file]]; + } - nkey.text = [KVKFile NStringFromFile:file]; + _keys = [NSArray arrayWithArray:mKeys]; - DWORD bmpSize; - size = sizeof(bmpSize); + [file closeFile]; + } + + return self; +} + +- (NSString *)description { + NSString *format = @"<%@:%p\nM:%@\nV:0x%X\nF:0x%X\nAK:%@\nAF:%@\nUF:%@\n>"; + NSString *str = [NSString stringWithFormat:format, + self.className, self, self.magic, self.version, self.flags, self.associatedKeyboard, self.ansiFont, self.unicodeFont]; + return str; +} + ++ (NSString *)NStringFromFile:(NSFileHandle *)file { + WORD strLen; + size_t size = sizeof(strLen); + NSData *dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:&strLen length:size]; + + WORD ch; + size = sizeof(ch); + NSMutableString *mStr = [NSMutableString stringWithString:@""]; + for (int i = 0; i < strLen; i++) { dataBuffer = [file readDataOfLength:size]; - [dataBuffer getBytes:&bmpSize length:size]; - if (bmpSize > 0) { - dataBuffer = [file readDataOfLength:bmpSize]; - NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:dataBuffer]; - const CGFloat colorMasking[6] = {255.0, 255.0, 255.0, 255.0, 255.0, 255.0}; - CGImageRef imageRef = CGImageCreateWithMaskingColors(imageRep.CGImage, colorMasking); - nkey.bitmap = [[NSImage alloc] initWithCGImage:imageRef size:NSMakeSize(CGImageGetWidth(imageRep.CGImage), CGImageGetHeight(imageRep.CGImage))]; - CGImageRelease(imageRef); - } - - return nkey; + [dataBuffer getBytes:&ch length:size]; + if (ch > 0) + [mStr appendString:[NSString stringWithFormat:@"%C", ch]]; + } + + return [NSString stringWithString:mStr]; +} + ++ (NFont *)NFontFromFile:(NSFileHandle *)file { + NFont *nfont = [[NFont alloc] init]; + nfont.name = [KVKFile NStringFromFile:file]; + + DWORD fSize; + size_t size = sizeof(fSize); + NSData *dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:&fSize length:size]; + nfont.size = fSize; + + DWORD fColor; + size = sizeof(fColor); + dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:&fColor length:size]; + nfont.color = fColor; + + return nfont; +} + ++ (NKey *)NKeyFromFile:(NSFileHandle *)file { + NKey *nkey = [[NKey alloc] init]; + + Byte flags; + size_t size = sizeof(flags); + NSData *dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:&flags length:size]; + nkey.flags = flags; + + WORD shift; + size = sizeof(shift); + dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:&shift length:size]; + nkey.shift = shift; + + WORD vkey; + size = sizeof(vkey); + dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:&vkey length:size]; + nkey.vkey = vkey; + + nkey.text = [KVKFile NStringFromFile:file]; + + DWORD bmpSize; + size = sizeof(bmpSize); + dataBuffer = [file readDataOfLength:size]; + [dataBuffer getBytes:&bmpSize length:size]; + if (bmpSize > 0) { + dataBuffer = [file readDataOfLength:bmpSize]; + NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:dataBuffer]; + const CGFloat colorMasking[6] = {255.0, 255.0, 255.0, 255.0, 255.0, 255.0}; + CGImageRef imageRef = CGImageCreateWithMaskingColors(imageRep.CGImage, colorMasking); + nkey.bitmap = [[NSImage alloc] initWithCGImage:imageRef size:NSMakeSize(CGImageGetWidth(imageRep.CGImage), CGImageGetHeight(imageRep.CGImage))]; + CGImageRelease(imageRef); + } + + return nkey; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/NFont.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/NFont.m index 739baba6adc..9134445f376 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/NFont.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/NFont.m @@ -11,18 +11,18 @@ @implementation NFont - (id)init { - self = [super init]; - if (self) { - _name = @""; - } - - return self; + self = [super init]; + if (self) { + _name = @""; + } + + return self; } - (NSString *)description { - NSString *format = @"<%@:%p N:%@ S:%d C:%d>"; - NSString *str = [NSString stringWithFormat:format, self.className, self, self.name, self.size, self.color]; - return str; + NSString *format = @"<%@:%p N:%@ S:%d C:%d>"; + NSString *str = [NSString stringWithFormat:format, self.className, self, self.name, self.size, self.color]; + return str; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/NKey.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/NKey.m index b07e8f8da22..f9ed1977b2e 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/NKey.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/NKey.m @@ -11,18 +11,18 @@ @implementation NKey - (id)init { - self = [super init]; - if (self) { - _text = @""; - } - - return self; + self = [super init]; + if (self) { + _text = @""; + } + + return self; } - (NSString *)description { - NSString *format = @"<%@:%p F:%d S:%d VK:%d TXT:%@ BMP:%@>"; - NSString *str = [NSString stringWithFormat:format, self.className, self, self.flags, self.shift, self.vkey, self.text, self.bitmap]; - return str; + NSString *format = @"<%@:%p F:%d S:%d VK:%d TXT:%@ BMP:%@>"; + NSString *str = [NSString stringWithFormat:format, self.className, self, self.flags, self.shift, self.vkey, self.text, self.bitmap]; + return str; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyLabel.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyLabel.m index e3157712795..b7acda4af66 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyLabel.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyLabel.m @@ -12,13 +12,13 @@ @implementation KeyLabel - (id)initWithFrame:(NSRect)frameRect { - [KeyLabel setCellClass:[KeyLabelCell class]]; - self = [super initWithFrame:frameRect]; - if (self) { - // - } - - return self; + [KeyLabel setCellClass:[KeyLabelCell class]]; + self = [super initWithFrame:frameRect]; + if (self) { + // + } + + return self; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyLabelCell.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyLabelCell.m index 78a5cc7c92d..26388895a3c 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyLabelCell.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyLabelCell.m @@ -11,36 +11,36 @@ @implementation KeyLabelCell - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { - NSRect titleRect = [self titleRectForBounds:cellFrame]; - if (self.drawsBackground && self.backgroundColor != nil) { - if (self.backgroundColor.alphaComponent > 0) { - [self.backgroundColor set]; - NSRectFill(titleRect); - } + NSRect titleRect = [self titleRectForBounds:cellFrame]; + if (self.drawsBackground && self.backgroundColor != nil) { + if (self.backgroundColor.alphaComponent > 0) { + [self.backgroundColor set]; + NSRectFill(titleRect); } - - NSAttributedString *attrString = self.attributedStringValue; - if (self.isHighlighted && self.backgroundStyle == NSBackgroundStyleDark) { - NSMutableAttributedString *whiteString = attrString.mutableCopy; - [whiteString addAttribute:NSForegroundColorAttributeName - value:[NSColor whiteColor] - range:NSMakeRange(0, whiteString.length)]; - attrString = whiteString; - } - - [attrString drawWithRect:titleRect options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin]; + } + + NSAttributedString *attrString = self.attributedStringValue; + if (self.isHighlighted && self.backgroundStyle == NSBackgroundStyleDark) { + NSMutableAttributedString *whiteString = attrString.mutableCopy; + [whiteString addAttribute:NSForegroundColorAttributeName + value:[NSColor whiteColor] + range:NSMakeRange(0, whiteString.length)]; + attrString = whiteString; + } + + [attrString drawWithRect:titleRect options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin]; } - (NSRect)titleRectForBounds:(NSRect)theRect { - NSRect titleRect = [super titleRectForBounds:theRect]; - NSAttributedString *attrString = self.attributedStringValue; - NSRect textRect = [attrString boundingRectWithSize:titleRect.size options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin]; - if (NSHeight(textRect) < NSHeight(titleRect)) { - titleRect.origin.y = theRect.origin.y + (NSHeight(theRect) - NSHeight(textRect))*0.5f; - titleRect.size.height = NSHeight(textRect); - } - - return titleRect; + NSRect titleRect = [super titleRectForBounds:theRect]; + NSAttributedString *attrString = self.attributedStringValue; + NSRect textRect = [attrString boundingRectWithSize:titleRect.size options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin]; + if (NSHeight(textRect) < NSHeight(titleRect)) { + titleRect.origin.y = theRect.origin.y + (NSHeight(theRect) - NSHeight(textRect))*0.5f; + titleRect.size.height = NSHeight(textRect); + } + + return titleRect; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m index ba55da77167..fc8029812e4 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m @@ -39,127 +39,127 @@ @implementation KeyView @synthesize bgColorRegularKey, bgColorSpecialKey; - (id)initWithFrame:(NSRect)frame { - os_log_t oskKeyLog = os_log_create("org.sil.keyman", "osk-key"); - self = [super initWithFrame:frame]; - if (self) { - os_log_with_type(oskKeyLog, OS_LOG_TYPE_DEBUG, "KeyView initWithFrame: %{public}@, bounds: %{public}@, default clipsToBounds %{public}@", NSStringFromRect(frame), NSStringFromRect(self.bounds), self.clipsToBounds?@"YES":@"NO"); - self.clipsToBounds = true; - CGSize size = frame.size; - CGFloat x = size.width*0.05; - NSRect labelFrame = NSMakeRect(x, 0, size.width -lw -2*x, size.height); - _label = [[KeyLabel alloc] initWithFrame:labelFrame]; - [_label setEditable:NO]; - [_label setBordered:NO]; - [_label setDrawsBackground:NO]; - [_label setAlignment:NSTextAlignmentCenter]; - if ([_caption respondsToSelector:@selector(setLineBreakMode:)]) { - [_label setLineBreakMode:NSLineBreakByClipping]; - } // There might be some problem not calling this, but it seems to be okay as far as I can tell - - CGFloat fontSize = labelFrame.size.height*kRelativeModifierLabelHeight; - [_label setFont:[NSFont systemFontOfSize:fontSize]]; - [_label setTextColor:[NSColor blackColor]]; - [_label setStringValue:@""]; - [_label setLineBreakMode:NSLineBreakByClipping]; - [self addSubview:_label]; - - bgColorRegularKey = [self getOpaqueColorWithRed:209 green:211 blue:212]; - bgColorSpecialKey = [self getOpaqueColorWithRed:166 green:169 blue:172]; - } - - return self; + os_log_t oskKeyLog = os_log_create("org.sil.keyman", "osk-key"); + self = [super initWithFrame:frame]; + if (self) { + os_log_with_type(oskKeyLog, OS_LOG_TYPE_DEBUG, "KeyView initWithFrame: %{public}@, bounds: %{public}@, default clipsToBounds %{public}@", NSStringFromRect(frame), NSStringFromRect(self.bounds), self.clipsToBounds?@"YES":@"NO"); + self.clipsToBounds = true; + CGSize size = frame.size; + CGFloat x = size.width*0.05; + NSRect labelFrame = NSMakeRect(x, 0, size.width -lw -2*x, size.height); + _label = [[KeyLabel alloc] initWithFrame:labelFrame]; + [_label setEditable:NO]; + [_label setBordered:NO]; + [_label setDrawsBackground:NO]; + [_label setAlignment:NSTextAlignmentCenter]; + if ([_caption respondsToSelector:@selector(setLineBreakMode:)]) { + [_label setLineBreakMode:NSLineBreakByClipping]; + } // There might be some problem not calling this, but it seems to be okay as far as I can tell + + CGFloat fontSize = labelFrame.size.height*kRelativeModifierLabelHeight; + [_label setFont:[NSFont systemFontOfSize:fontSize]]; + [_label setTextColor:[NSColor blackColor]]; + [_label setStringValue:@""]; + [_label setLineBreakMode:NSLineBreakByClipping]; + [self addSubview:_label]; + + bgColorRegularKey = [self getOpaqueColorWithRed:209 green:211 blue:212]; + bgColorSpecialKey = [self getOpaqueColorWithRed:166 green:169 blue:172]; + } + + return self; } - (void)drawRect:(NSRect)rect { - os_log_t oskKeyLog = os_log_create("org.sil.keyman", "osk-key"); - os_log_with_type(oskKeyLog, OS_LOG_TYPE_DEBUG, "KeyView drawRect: %{public}@, bounds: %{public}@, keyCode: 0x%lx, caption: %{public}@, label: %{public}@", NSStringFromRect(rect), NSStringFromRect(self.bounds), self.keyCode, self.caption.stringValue, self.label.stringValue); + os_log_t oskKeyLog = os_log_create("org.sil.keyman", "osk-key"); + os_log_with_type(oskKeyLog, OS_LOG_TYPE_DEBUG, "KeyView drawRect: %{public}@, bounds: %{public}@, keyCode: 0x%lx, caption: %{public}@, label: %{public}@", NSStringFromRect(rect), NSStringFromRect(self.bounds), self.keyCode, self.caption.stringValue, self.label.stringValue); - [[self getOpaqueColorWithRed:241 green:242 blue:242] setFill]; - NSRectFillUsingOperation(rect, NSCompositingOperationSourceOver); - - // Drawing code here. - CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; - - CGContextSetLineJoin(context, kCGLineJoinRound); - CGContextSetLineWidth(context, lw); - CGContextSetStrokeColorWithColor(context, bgColorRegularKey.CGColor); - - CGFloat x = rect.origin.x + lw; - CGFloat y = rect.origin.y + lw; - CGFloat w = rect.size.width - 2*lw; - CGFloat h = rect.size.height - 2*lw; - - CGContextBeginPath(context); - CGContextMoveToPoint(context, w/2.0, y); - CGContextAddArcToPoint(context, w, y, w, y+h, r); - CGContextAddArcToPoint(context, w, y+h, x, y+h, r); - CGContextAddArcToPoint(context, x, y+h, x, y, r); - CGContextAddArcToPoint(context, x, y, w/2.0, y, r); - CGContextClosePath(context); - CGContextDrawPath(context, kCGPathStroke); - - CGContextBeginPath(context); - CGContextMoveToPoint(context, w/2.0, y); - CGContextAddArcToPoint(context, w, y, w, y+h, r); - CGContextAddArcToPoint(context, w, y+h, x, y+h, r); - CGContextAddArcToPoint(context, x, y+h, x, y, r); - CGContextAddArcToPoint(context, x, y, w/2.0, y, r); - CGContextClosePath(context); - CGContextClip(context); - - NSColor *bgColor = bgColorRegularKey; - - if ([self isSpecialKey]) - bgColor = bgColorSpecialKey; - - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGFloat gradientLocations[] = {0, 1}; - NSArray *gradientColors = [NSArray arrayWithObjects:(id)bgColor.CGColor, bgColor.CGColor, nil]; - CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations); - CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); - CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); - CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); - CGGradientRelease(gradient); - CGColorSpaceRelease(colorSpace); + [[self getOpaqueColorWithRed:241 green:242 blue:242] setFill]; + NSRectFillUsingOperation(rect, NSCompositingOperationSourceOver); + + // Drawing code here. + CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; + + CGContextSetLineJoin(context, kCGLineJoinRound); + CGContextSetLineWidth(context, lw); + CGContextSetStrokeColorWithColor(context, bgColorRegularKey.CGColor); + + CGFloat x = rect.origin.x + lw; + CGFloat y = rect.origin.y + lw; + CGFloat w = rect.size.width - 2*lw; + CGFloat h = rect.size.height - 2*lw; + + CGContextBeginPath(context); + CGContextMoveToPoint(context, w/2.0, y); + CGContextAddArcToPoint(context, w, y, w, y+h, r); + CGContextAddArcToPoint(context, w, y+h, x, y+h, r); + CGContextAddArcToPoint(context, x, y+h, x, y, r); + CGContextAddArcToPoint(context, x, y, w/2.0, y, r); + CGContextClosePath(context); + CGContextDrawPath(context, kCGPathStroke); + + CGContextBeginPath(context); + CGContextMoveToPoint(context, w/2.0, y); + CGContextAddArcToPoint(context, w, y, w, y+h, r); + CGContextAddArcToPoint(context, w, y+h, x, y+h, r); + CGContextAddArcToPoint(context, x, y+h, x, y, r); + CGContextAddArcToPoint(context, x, y, w/2.0, y, r); + CGContextClosePath(context); + CGContextClip(context); + + NSColor *bgColor = bgColorRegularKey; + + if ([self isSpecialKey]) + bgColor = bgColorSpecialKey; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGFloat gradientLocations[] = {0, 1}; + NSArray *gradientColors = [NSArray arrayWithObjects:(id)bgColor.CGColor, bgColor.CGColor, nil]; + CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations); + CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); + CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); + CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); + CGGradientRelease(gradient); + CGColorSpaceRelease(colorSpace); } - (BOOL)isFlipped { - return YES; + return YES; } - (void)setKey:(OSKKey *)key { - _key = key; - [self setKeyCode:key.keyCode]; - [self setTag:key.keyCode|0x1000]; - if ([self isSpecialKey]) - [self setLabelText:key.caption]; - else - [self setLabelText:@""]; - if (key.scale == 1.0) - [self setCaptionText:key.caption]; + _key = key; + [self setKeyCode:key.keyCode]; + [self setTag:key.keyCode|0x1000]; + if ([self isSpecialKey]) + [self setLabelText:key.caption]; + else + [self setLabelText:@""]; + if (key.scale == 1.0) + [self setCaptionText:key.caption]; } - (void)setKeyCode:(NSUInteger)keyCode { - _keyCode = keyCode; - if (keyCode == MVK_LEFT_SHIFT || keyCode == MVK_RIGHT_SHIFT) - _isModifierKey = YES; - else if (keyCode == MVK_LEFT_ALT || keyCode == MVK_RIGHT_ALT) - _isModifierKey = YES; - else if (keyCode == MVK_LEFT_CTRL || keyCode == MVK_RIGHT_CTRL) - _isModifierKey = YES; - - if (keyCode >= MVK_CAPS_LOCK && keyCode <= MVK_RIGHT_ALT) - _isSpecialKey = YES; - else if (self.keyCode == MVK_ENTER || self.keyCode == MVK_TAB || self.keyCode == MVK_BACKSPACE) - _isSpecialKey = YES; - else - _isSpecialKey = NO; - - if (!_isSpecialKey && !_isModifierKey) { - _isCharacterKey = YES; - } else { - _isCharacterKey = NO; - } + _keyCode = keyCode; + if (keyCode == MVK_LEFT_SHIFT || keyCode == MVK_RIGHT_SHIFT) + _isModifierKey = YES; + else if (keyCode == MVK_LEFT_ALT || keyCode == MVK_RIGHT_ALT) + _isModifierKey = YES; + else if (keyCode == MVK_LEFT_CTRL || keyCode == MVK_RIGHT_CTRL) + _isModifierKey = YES; + + if (keyCode >= MVK_CAPS_LOCK && keyCode <= MVK_RIGHT_ALT) + _isSpecialKey = YES; + else if (self.keyCode == MVK_ENTER || self.keyCode == MVK_TAB || self.keyCode == MVK_BACKSPACE) + _isSpecialKey = YES; + else + _isSpecialKey = NO; + + if (!_isSpecialKey && !_isModifierKey) { + _isCharacterKey = YES; + } else { + _isCharacterKey = NO; + } // having changed the keycode, adjust the font size of the key label to optimize for available space [self adjustLabelFontSize]; @@ -171,179 +171,179 @@ - (void)setKeyCode:(NSUInteger)keyCode { * This allows larger more readable character key text. */ - (void)adjustLabelFontSize { - CGFloat relativeFontSize = kRelativeCharacterLabelHeight; - - if (!self.isCharacterKey) { - relativeFontSize = kRelativeModifierLabelHeight; - } - - CGFloat fontSize = self.label.bounds.size.height*relativeFontSize; - [self.label setFont:[NSFont systemFontOfSize:fontSize]]; + CGFloat relativeFontSize = kRelativeCharacterLabelHeight; + + if (!self.isCharacterKey) { + relativeFontSize = kRelativeModifierLabelHeight; + } + + CGFloat fontSize = self.label.bounds.size.height*relativeFontSize; + [self.label setFont:[NSFont systemFontOfSize:fontSize]]; } - (void)setLabelText:(NSString *)text { - [_label setStringValue:text]; + [_label setStringValue:text]; } - (void)setLabelFont:(NSString *)fontName { - CGFloat fontSize = [_label.font pointSize]; - if (fontName != nil) { - NSFont *font = [NSFont fontWithName:fontName size:fontSize]; - if (font != nil) { - [_label setFont:font]; - } + CGFloat fontSize = [_label.font pointSize]; + if (fontName != nil) { + NSFont *font = [NSFont fontWithName:fontName size:fontSize]; + if (font != nil) { + [_label setFont:font]; } + } } - (void)setCaptionText:(NSString *)text { - if (_caption == nil) - [self setHasKeyCaption:YES]; - [_caption setStringValue:text]; + if (_caption == nil) + [self setHasKeyCaption:YES]; + [_caption setStringValue:text]; } - (void)setCaptionFont:(NSString *)fontName { - if (_caption == nil) - [self setHasKeyCaption:YES]; - - CGFloat fontSize = [_caption.font pointSize]; - if (fontName != nil) { - NSFont *font = [NSFont fontWithName:fontName size:fontSize]; - if (font != nil) { - [_caption setFont:font]; - } + if (_caption == nil) + [self setHasKeyCaption:YES]; + + CGFloat fontSize = [_caption.font pointSize]; + if (fontName != nil) { + NSFont *font = [NSFont fontWithName:fontName size:fontSize]; + if (font != nil) { + [_caption setFont:font]; } + } } - (void)setBitmap:(NSImage *)bitmap { - // Bitmap is disabled: Per Marc, this is super low priority. Bitmaps are ugly and scale badly. We - // supported them a long time ago in Windows but you'd need to add support for Windows' BMP format - // to show them. I think we'd be better off not supporting them for now (just document as a platform - // difference). - _bitmap = nil; - /* - _bitmap = bitmap; - [_bitmapView removeFromSuperview]; - if (_bitmap != nil) { - NSTextFieldCell *cell = (NSTextFieldCell *)self.label.cell; - NSRect frame = cell.controlView.frame; - frame = NSInsetRect(frame, frame.size.width*0.15, frame.size.height*0.15); - _bitmapView = [[NSImageView alloc] initWithFrame:frame]; - [_bitmapView setImageScaling:NSImageScaleProportionallyUpOrDown]; - [_bitmapView setImage:_bitmap]; - [self.label setStringValue:@"[ ]"]; - [self addSubview:_bitmapView]; - }*/ + // Bitmap is disabled: Per Marc, this is super low priority. Bitmaps are ugly and scale badly. We + // supported them a long time ago in Windows but you'd need to add support for Windows' BMP format + // to show them. I think we'd be better off not supporting them for now (just document as a platform + // difference). + _bitmap = nil; + /* + _bitmap = bitmap; + [_bitmapView removeFromSuperview]; + if (_bitmap != nil) { + NSTextFieldCell *cell = (NSTextFieldCell *)self.label.cell; + NSRect frame = cell.controlView.frame; + frame = NSInsetRect(frame, frame.size.width*0.15, frame.size.height*0.15); + _bitmapView = [[NSImageView alloc] initWithFrame:frame]; + [_bitmapView setImageScaling:NSImageScaleProportionallyUpOrDown]; + [_bitmapView setImage:_bitmap]; + [self.label setStringValue:@"[ ]"]; + [self addSubview:_bitmapView]; + }*/ } - (void)setHasKeyCaption:(BOOL)hasKeyCaption { - _hasKeyCaption = hasKeyCaption; - if (hasKeyCaption && _caption == nil) { - NSRect captionFrame = NSMakeRect(1.5, 3, self.frame.size.width*0.3, self.frame.size.height*0.3); - CGFloat fontSize = captionFrame.size.height*0.7; - _caption = [[NSTextField alloc] initWithFrame:captionFrame]; - [_caption setEditable:NO]; - [_caption setBordered:NO]; - [_caption setDrawsBackground:NO]; - //[_caption setBackgroundColor:[NSColor yellowColor]]; - [_caption setAlignment:NSTextAlignmentLeft]; - if ([_caption respondsToSelector:@selector(setLineBreakMode:)]) { - [_caption setLineBreakMode:NSLineBreakByClipping]; - } // There might be some problem not calling this, but it seems to be okay as far as I can tell - [_caption setFont:[NSFont systemFontOfSize:fontSize]]; - [_caption setTextColor:[NSColor darkGrayColor]]; - [_caption setStringValue:@""]; - [self addSubview:_caption]; - } - else if (!hasKeyCaption) { - [_caption removeFromSuperview]; - _caption = nil; - } + _hasKeyCaption = hasKeyCaption; + if (hasKeyCaption && _caption == nil) { + NSRect captionFrame = NSMakeRect(1.5, 3, self.frame.size.width*0.3, self.frame.size.height*0.3); + CGFloat fontSize = captionFrame.size.height*0.7; + _caption = [[NSTextField alloc] initWithFrame:captionFrame]; + [_caption setEditable:NO]; + [_caption setBordered:NO]; + [_caption setDrawsBackground:NO]; + //[_caption setBackgroundColor:[NSColor yellowColor]]; + [_caption setAlignment:NSTextAlignmentLeft]; + if ([_caption respondsToSelector:@selector(setLineBreakMode:)]) { + [_caption setLineBreakMode:NSLineBreakByClipping]; + } // There might be some problem not calling this, but it seems to be okay as far as I can tell + [_caption setFont:[NSFont systemFontOfSize:fontSize]]; + [_caption setTextColor:[NSColor darkGrayColor]]; + [_caption setStringValue:@""]; + [self addSubview:_caption]; + } + else if (!hasKeyCaption) { + [_caption removeFromSuperview]; + _caption = nil; + } } - (void)mouseDown:(NSEvent *)theEvent { - @synchronized(self.target) { - if (!self.isModifierKey) { - // All KeyViews are about to get blown away and recreated, so we don't want the timer to fire - // again until some other key gets pressed. - [self stopTimer]; - } - else { - [self setKeyPressed:YES]; - } - [self processKeyClick]; - if (!self.isModifierKey) - [self startTimerWithTimeInterval:delayBeforeRepeating]; + @synchronized(self.target) { + if (!self.isModifierKey) { + // All KeyViews are about to get blown away and recreated, so we don't want the timer to fire + // again until some other key gets pressed. + [self stopTimer]; + } + else { + [self setKeyPressed:YES]; } + [self processKeyClick]; + if (!self.isModifierKey) + [self startTimerWithTimeInterval:delayBeforeRepeating]; + } } - (void)mouseUp:(NSEvent *)theEvent { - if (!self.isModifierKey) { - [self setKeyPressed:NO]; - [self stopTimer]; - } + if (!self.isModifierKey) { + [self setKeyPressed:NO]; + [self stopTimer]; + } } -(void)processKeyClick { - [self.target keyAction:self]; + [self.target keyAction:self]; } - (void)startTimerWithTimeInterval:(NSTimeInterval)interval { - @synchronized(self.target) { - if (_keyEventTimer == nil) { - // The TimerTarget class and the following two lines allow the timer to hold a *weak* - // reference to this KeyView object, so it can be disposed even if there is a timer waiting - // to fire that refers to it. - TimerTarget *timerTarget = [[TimerTarget alloc] init]; - timerTarget.target = self; - _keyEventTimer = [NSTimer scheduledTimerWithTimeInterval:interval - target:timerTarget - selector:@selector(timerAction:) - userInfo:nil - repeats:YES]; - } + @synchronized(self.target) { + if (_keyEventTimer == nil) { + // The TimerTarget class and the following two lines allow the timer to hold a *weak* + // reference to this KeyView object, so it can be disposed even if there is a timer waiting + // to fire that refers to it. + TimerTarget *timerTarget = [[TimerTarget alloc] init]; + timerTarget.target = self; + _keyEventTimer = [NSTimer scheduledTimerWithTimeInterval:interval + target:timerTarget + selector:@selector(timerAction:) + userInfo:nil + repeats:YES]; } + } } - (void)stopTimer { - @synchronized(self.target) { - //NSLog(@"KeyView TIMER - stopping"); - if (_keyEventTimer != nil) { - [_keyEventTimer invalidate]; - _keyEventTimer = nil; - } + @synchronized(self.target) { + //NSLog(@"KeyView TIMER - stopping"); + if (_keyEventTimer != nil) { + [_keyEventTimer invalidate]; + _keyEventTimer = nil; } + } } - (void)timerAction:(NSTimer *)timer { - @synchronized(self.target) { - //NSLog(@"KeyView TIMER - Fired for key %lu", [self keyCode]); - [self processKeyClick]; - - if ([timer timeInterval] == delayBeforeRepeating) { - // Fired following a normal (non-modifier key press). As long as user continues to hold - // down that key, it will now begin to repeat every 0.05 seconds. All we really want to - // do is change the time interval, but NSTimer doesn't support that. - [self stopTimer]; - [self startTimerWithTimeInterval:repeatInterval]; - } + @synchronized(self.target) { + //NSLog(@"KeyView TIMER - Fired for key %lu", [self keyCode]); + [self processKeyClick]; + + if ([timer timeInterval] == delayBeforeRepeating) { + // Fired following a normal (non-modifier key press). As long as user continues to hold + // down that key, it will now begin to repeat every 0.05 seconds. All we really want to + // do is change the time interval, but NSTimer doesn't support that. + [self stopTimer]; + [self startTimerWithTimeInterval:repeatInterval]; } + } } - (void)setKeyPressed:(BOOL)keyPressed { - _keyPressed = keyPressed; - if (keyPressed) { - bgColorRegularKey = [self getOpaqueColorWithRed:109 green:111 blue:112]; - bgColorSpecialKey = [self getOpaqueColorWithRed:236 green:239 blue:242]; - [self setNeedsDisplay:YES]; - } - else { - bgColorRegularKey = [self getOpaqueColorWithRed:209 green:211 blue:212]; - bgColorSpecialKey = [self getOpaqueColorWithRed:166 green:169 blue:172]; - [self setNeedsDisplay:YES]; - } + _keyPressed = keyPressed; + if (keyPressed) { + bgColorRegularKey = [self getOpaqueColorWithRed:109 green:111 blue:112]; + bgColorSpecialKey = [self getOpaqueColorWithRed:236 green:239 blue:242]; + [self setNeedsDisplay:YES]; + } + else { + bgColorRegularKey = [self getOpaqueColorWithRed:209 green:211 blue:212]; + bgColorSpecialKey = [self getOpaqueColorWithRed:166 green:169 blue:172]; + [self setNeedsDisplay:YES]; + } } - (NSColor *)getOpaqueColorWithRed:(NSUInteger) red green: (NSUInteger) green blue: (NSUInteger) blue { - return [NSColor colorWithSRGBRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1.0]; + return [NSColor colorWithSRGBRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1.0]; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m index d5a5ee722a0..a8840eb4118 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m @@ -12,21 +12,21 @@ @implementation OSKKey - (id)initWithKeyCode:(NSUInteger)keyCode caption:(NSString *)caption scale:(CGFloat)scale { - self = [super init]; - if (self) { - os_log_t oskKeyLog = os_log_create("org.sil.keyman", "osk-key"); - os_log_with_type(oskKeyLog, OS_LOG_TYPE_DEBUG, "OSKKey initWithKeyCode: 0x%lx, caption: %{public}@, scale: %f", keyCode, caption, scale); - _keyCode = keyCode; - - if (caption == nil) - _caption = @""; - else - _caption = [NSString stringWithString:caption]; - - _scale = scale; - } + self = [super init]; + if (self) { + os_log_t oskKeyLog = os_log_create("org.sil.keyman", "osk-key"); + os_log_with_type(oskKeyLog, OS_LOG_TYPE_DEBUG, "OSKKey initWithKeyCode: 0x%lx, caption: %{public}@, scale: %f", keyCode, caption, scale); + _keyCode = keyCode; - return self; + if (caption == nil) + _caption = @""; + else + _caption = [NSString stringWithString:caption]; + + _scale = scale; + } + + return self; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m index f0b5bdf566b..2dda9283587 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m @@ -33,654 +33,654 @@ @implementation OSKView @synthesize tag; - (id)initWithFrame:(NSRect)frame { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView initWithFrame: %{public}@", NSStringFromRect(frame)); - self = [super initWithFrame:frame]; - if (self) { - // Custom initialization - [self initOSKKeys]; - } - - return self; + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView initWithFrame: %{public}@", NSStringFromRect(frame)); + self = [super initWithFrame:frame]; + if (self) { + // Custom initialization + [self initOSKKeys]; + } + + return self; } - (void)drawRect:(NSRect)rect { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView drawRect: %{public}@", NSStringFromRect(rect)); - - CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; - CGContextSetLineJoin(context, kCGLineJoinRound); - CGContextSetLineWidth(context, 1.0); - CGColorRef cgClearColor = CGColorGetConstantColor(kCGColorClear); - CGContextSetStrokeColorWithColor(context, cgClearColor); - CGContextSetFillColorWithColor(context, cgClearColor); - - CGContextBeginPath(context); - CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0)); - CGContextDrawPath(context, kCGPathStroke); - - CGContextBeginPath(context); - CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0)); - CGContextClip(context); - - //TODO: gradient from clear to clear -- what does this do? - NSColor *bgColor = [NSColor clearColor]; //[NSColor colorWithWhite:0.7 alpha:1.0]; - NSColor *bgColor2 = [NSColor clearColor]; //[NSColor colorWithWhite:0.5 alpha:1.0]; - - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - NSArray *gradientColors = [NSArray arrayWithObjects:(id)bgColor.CGColor, bgColor2.CGColor, nil]; - CGFloat gradientLocations[] = {0, 1}; - CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations); - CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); - CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); - CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); - CGGradientRelease(gradient); - CGColorSpaceRelease(colorSpace); + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView drawRect: %{public}@", NSStringFromRect(rect)); + + CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; + CGContextSetLineJoin(context, kCGLineJoinRound); + CGContextSetLineWidth(context, 1.0); + CGColorRef cgClearColor = CGColorGetConstantColor(kCGColorClear); + CGContextSetStrokeColorWithColor(context, cgClearColor); + CGContextSetFillColorWithColor(context, cgClearColor); + + CGContextBeginPath(context); + CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0)); + CGContextDrawPath(context, kCGPathStroke); + + CGContextBeginPath(context); + CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0)); + CGContextClip(context); + + //TODO: gradient from clear to clear -- what does this do? + NSColor *bgColor = [NSColor clearColor]; //[NSColor colorWithWhite:0.7 alpha:1.0]; + NSColor *bgColor2 = [NSColor clearColor]; //[NSColor colorWithWhite:0.5 alpha:1.0]; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + NSArray *gradientColors = [NSArray arrayWithObjects:(id)bgColor.CGColor, bgColor2.CGColor, nil]; + CGFloat gradientLocations[] = {0, 1}; + CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations); + CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); + CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); + CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); + CGGradientRelease(gradient); + CGColorSpaceRelease(colorSpace); } - (BOOL)isFlipped { - return YES; + return YES; } // Returns TRUE for ISO keyboards or when the .kvk file requests the 102nd key // to right of the Left Shift key. - (BOOL)use102ndKey { - /* - Note: LMGetKbdType() does not appear to work reliably; it seems to always - return ANSI even when there is a European keyboard plugged in to my Macbook. - We'll use it anyway in case better results are found for Macs with native - ISO keyboards. - */ - UInt8 kbdType = LMGetKbdType(); - PhysicalKeyboardLayoutType kbdLayoutType = KBGetLayoutType(kbdType); - switch(kbdLayoutType) { - case kKeyboardANSI: return _kvk != nil && _kvk.flags & KVKH_102; - case kKeyboardJIS: - case kKeyboardISO: return YES; - } - // We don't know what the keyboard is, so let's err on the side of - // more keys, not fewer - return YES; + /* + Note: LMGetKbdType() does not appear to work reliably; it seems to always + return ANSI even when there is a European keyboard plugged in to my Macbook. + We'll use it anyway in case better results are found for Macs with native + ISO keyboards. + */ + UInt8 kbdType = LMGetKbdType(); + PhysicalKeyboardLayoutType kbdLayoutType = KBGetLayoutType(kbdType); + switch(kbdLayoutType) { + case kKeyboardANSI: return _kvk != nil && _kvk.flags & KVKH_102; + case kKeyboardJIS: + case kKeyboardISO: return YES; + } + // We don't know what the keyboard is, so let's err on the side of + // more keys, not fewer + return YES; } - (void)setKvk:(KVKFile *)kvk { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView setKvk, forces keyboard to re-layout"); - _kvk = kvk; - - // Force the keyboard to re-layout - _oskLayout = nil; - _oskDefaultNKeys = nil; - - [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:self.oskCtrlState]; + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView setKvk, forces keyboard to re-layout"); + _kvk = kvk; + + // Force the keyboard to re-layout + _oskLayout = nil; + _oskDefaultNKeys = nil; + + [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:self.oskCtrlState]; } - (void)initOSKKeys { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView initOSKKeys"); - CGFloat viewWidth = self.frame.size.width; - CGFloat viewHeight = self.frame.size.height; - CGFloat margin = 2.0; - CGFloat keyHeight = (viewHeight - margin*2)/self.oskLayout.count; - CGFloat keyWidth = (viewWidth - margin*2)/14.5; - CGFloat px; - CGFloat py = margin; - for (NSArray *row in self.oskLayout) { - px = margin; - NSUInteger len = [row count]; - for (int i = 0; i < len; i++) { - OSKKey *key = (OSKKey *)[row objectAtIndex:i]; - CGFloat width = keyWidth * key.scale; - if ((i+1) == len && (px + width + margin) < viewWidth) - width += (viewWidth - (px + width + margin)); - NSRect rect = NSInsetRect(NSMakeRect(px, py, width, keyHeight), 2, 2); - KeyView *keyView = [[KeyView alloc] initWithFrame:rect];; - [keyView setKey:key]; - [keyView setTarget:self]; - if (self.oskShiftState && (keyView.key.keyCode == MVK_LEFT_SHIFT || keyView.key.keyCode == MVK_RIGHT_SHIFT)) - [keyView setKeyPressed:YES]; - else if (self.oskAltState && (keyView.key.keyCode == MVK_LEFT_ALT || keyView.key.keyCode == MVK_RIGHT_ALT)) - [keyView setKeyPressed:YES]; - [self addSubview:keyView]; - px += width; - } - py += keyHeight; + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView initOSKKeys"); + CGFloat viewWidth = self.frame.size.width; + CGFloat viewHeight = self.frame.size.height; + CGFloat margin = 2.0; + CGFloat keyHeight = (viewHeight - margin*2)/self.oskLayout.count; + CGFloat keyWidth = (viewWidth - margin*2)/14.5; + CGFloat px; + CGFloat py = margin; + for (NSArray *row in self.oskLayout) { + px = margin; + NSUInteger len = [row count]; + for (int i = 0; i < len; i++) { + OSKKey *key = (OSKKey *)[row objectAtIndex:i]; + CGFloat width = keyWidth * key.scale; + if ((i+1) == len && (px + width + margin) < viewWidth) + width += (viewWidth - (px + width + margin)); + NSRect rect = NSInsetRect(NSMakeRect(px, py, width, keyHeight), 2, 2); + KeyView *keyView = [[KeyView alloc] initWithFrame:rect];; + [keyView setKey:key]; + [keyView setTarget:self]; + if (self.oskShiftState && (keyView.key.keyCode == MVK_LEFT_SHIFT || keyView.key.keyCode == MVK_RIGHT_SHIFT)) + [keyView setKeyPressed:YES]; + else if (self.oskAltState && (keyView.key.keyCode == MVK_LEFT_ALT || keyView.key.keyCode == MVK_RIGHT_ALT)) + [keyView setKeyPressed:YES]; + [self addSubview:keyView]; + px += width; } - - [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:self.oskCtrlState]; + py += keyHeight; + } + + [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:self.oskCtrlState]; } - (NSArray *)oskLayout { - if (_oskLayout == nil) { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "oskLayout -> creating new arrays of OSKKey objects"); - NSArray *row1 = [NSArray arrayWithObjects: - [[OSKKey alloc] initWithKeyCode:MVK_GRAVE caption:@"`" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_1 caption:@"1" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_2 caption:@"2" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_3 caption:@"3" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_4 caption:@"4" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_5 caption:@"5" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_6 caption:@"6" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_7 caption:@"7" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_8 caption:@"8" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_9 caption:@"9" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_0 caption:@"0" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_MINUS caption:@"-" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_EQUAL caption:@"=" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_BACKSPACE caption:@"⬅︎" scale:1.5], nil]; - - NSArray *row2 = [NSArray arrayWithObjects: - [[OSKKey alloc] initWithKeyCode:MVK_TAB caption:@"↹" scale:1.5], - [[OSKKey alloc] initWithKeyCode:MVK_Q caption:@"Q" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_W caption:@"W" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_E caption:@"E" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_R caption:@"R" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_T caption:@"T" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_Y caption:@"Y" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_U caption:@"U" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_I caption:@"I" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_O caption:@"O" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_P caption:@"P" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_LEFT_BRACKET caption:@"[" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_BRACKET caption:@"]" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_BACKSLASH caption:@"\\" scale:1.0], nil]; - - NSArray *row3 = [NSArray arrayWithObjects: - [[OSKKey alloc] initWithKeyCode:MVK_CAPS_LOCK caption:@"Caps Lock" scale:1.75], - [[OSKKey alloc] initWithKeyCode:MVK_A caption:@"A" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_S caption:@"S" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_D caption:@"D" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_F caption:@"F" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_G caption:@"G" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_H caption:@"H" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_J caption:@"J" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_K caption:@"K" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_L caption:@"L" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_SEMICOLON caption:@";" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_QUOTE caption:@"'" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_ENTER caption:@"↵" scale:1.75], nil]; - - NSArray *row4a = [self use102ndKey] ? - [NSArray arrayWithObjects: - [[OSKKey alloc] initWithKeyCode:MVK_LEFT_SHIFT caption:@"⇧" scale:1.25], - [[OSKKey alloc] initWithKeyCode:MVK_OEM102 caption:@"\\" scale:1.0], nil] : - [NSArray arrayWithObjects: - [[OSKKey alloc] initWithKeyCode:MVK_LEFT_SHIFT caption:@"⇧" scale:2.25], nil]; - - NSArray *row4b = [NSArray arrayWithObjects: - [[OSKKey alloc] initWithKeyCode:MVK_Z caption:@"Z" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_X caption:@"X" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_C caption:@"C" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_V caption:@"V" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_B caption:@"B" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_N caption:@"N" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_M caption:@"M" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_COMMA caption:@"," scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_PERIOD caption:@"." scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_SLASH caption:@"/" scale:1.0], - [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_SHIFT caption:@"⇧" scale:2.25], nil]; - - NSArray *row4 = [row4a arrayByAddingObjectsFromArray:row4b]; - - NSArray *row5 = [NSArray arrayWithObjects: - [[OSKKey alloc] initWithKeyCode:MVK_LEFT_CTRL caption:@"Ctrl" scale:1.75], - [[OSKKey alloc] initWithKeyCode:MVK_LEFT_ALT caption:@"Alt" scale:1.5], - [[OSKKey alloc] initWithKeyCode:MVK_SPACE caption:@"" scale:8.0], - [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_ALT caption:@"Alt" scale:1.5], - [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_CTRL caption:@"Ctrl" scale:1.75], nil]; - - _oskLayout = [NSArray arrayWithObjects:row1, row2, row3, row4, row5, nil]; - } + if (_oskLayout == nil) { + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "oskLayout -> creating new arrays of OSKKey objects"); + NSArray *row1 = [NSArray arrayWithObjects: + [[OSKKey alloc] initWithKeyCode:MVK_GRAVE caption:@"`" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_1 caption:@"1" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_2 caption:@"2" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_3 caption:@"3" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_4 caption:@"4" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_5 caption:@"5" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_6 caption:@"6" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_7 caption:@"7" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_8 caption:@"8" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_9 caption:@"9" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_0 caption:@"0" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_MINUS caption:@"-" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_EQUAL caption:@"=" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_BACKSPACE caption:@"⬅︎" scale:1.5], nil]; + + NSArray *row2 = [NSArray arrayWithObjects: + [[OSKKey alloc] initWithKeyCode:MVK_TAB caption:@"↹" scale:1.5], + [[OSKKey alloc] initWithKeyCode:MVK_Q caption:@"Q" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_W caption:@"W" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_E caption:@"E" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_R caption:@"R" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_T caption:@"T" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_Y caption:@"Y" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_U caption:@"U" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_I caption:@"I" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_O caption:@"O" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_P caption:@"P" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_LEFT_BRACKET caption:@"[" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_BRACKET caption:@"]" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_BACKSLASH caption:@"\\" scale:1.0], nil]; + + NSArray *row3 = [NSArray arrayWithObjects: + [[OSKKey alloc] initWithKeyCode:MVK_CAPS_LOCK caption:@"Caps Lock" scale:1.75], + [[OSKKey alloc] initWithKeyCode:MVK_A caption:@"A" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_S caption:@"S" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_D caption:@"D" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_F caption:@"F" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_G caption:@"G" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_H caption:@"H" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_J caption:@"J" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_K caption:@"K" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_L caption:@"L" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_SEMICOLON caption:@";" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_QUOTE caption:@"'" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_ENTER caption:@"↵" scale:1.75], nil]; + + NSArray *row4a = [self use102ndKey] ? + [NSArray arrayWithObjects: + [[OSKKey alloc] initWithKeyCode:MVK_LEFT_SHIFT caption:@"⇧" scale:1.25], + [[OSKKey alloc] initWithKeyCode:MVK_OEM102 caption:@"\\" scale:1.0], nil] : + [NSArray arrayWithObjects: + [[OSKKey alloc] initWithKeyCode:MVK_LEFT_SHIFT caption:@"⇧" scale:2.25], nil]; + + NSArray *row4b = [NSArray arrayWithObjects: + [[OSKKey alloc] initWithKeyCode:MVK_Z caption:@"Z" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_X caption:@"X" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_C caption:@"C" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_V caption:@"V" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_B caption:@"B" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_N caption:@"N" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_M caption:@"M" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_COMMA caption:@"," scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_PERIOD caption:@"." scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_SLASH caption:@"/" scale:1.0], + [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_SHIFT caption:@"⇧" scale:2.25], nil]; + + NSArray *row4 = [row4a arrayByAddingObjectsFromArray:row4b]; - return _oskLayout; + NSArray *row5 = [NSArray arrayWithObjects: + [[OSKKey alloc] initWithKeyCode:MVK_LEFT_CTRL caption:@"Ctrl" scale:1.75], + [[OSKKey alloc] initWithKeyCode:MVK_LEFT_ALT caption:@"Alt" scale:1.5], + [[OSKKey alloc] initWithKeyCode:MVK_SPACE caption:@"" scale:8.0], + [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_ALT caption:@"Alt" scale:1.5], + [[OSKKey alloc] initWithKeyCode:MVK_RIGHT_CTRL caption:@"Ctrl" scale:1.75], nil]; + + _oskLayout = [NSArray arrayWithObjects:row1, row2, row3, row4, row5, nil]; + } + + return _oskLayout; } - (NSArray *)oskDefaultNKeys { - if (_oskDefaultNKeys == nil) { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "oskDefaultNKeys -> creating new arrays of default number OSKKey objects"); - NSMutableArray *defNKeys = [[NSMutableArray alloc] initWithCapacity:0]; - - // row 1 - NKey *nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_GRAVE; nkey1.text = @"`"; nkey1.bitmap = nil; - NKey *nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_GRAVE; nkey2.text = @"~"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_1; nkey1.text = @"1"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_1; nkey2.text = @"!"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_2; nkey1.text = @"2"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_2; nkey2.text = @"@"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_3; nkey1.text = @"3"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_3; nkey2.text = @"#"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_4; nkey1.text = @"4"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_4; nkey2.text = @"$"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_5; nkey1.text = @"5"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_5; nkey2.text = @"%"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_6; nkey1.text = @"6"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_6; nkey2.text = @"^"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_7; nkey1.text = @"7"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_7; nkey2.text = @"&"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_8; nkey1.text = @"8"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_8; nkey2.text = @"*"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_9; nkey1.text = @"9"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_9; nkey2.text = @"("; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_0; nkey1.text = @"0"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_0; nkey2.text = @")"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_MINUS; nkey1.text = @"-"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_MINUS; nkey2.text = @"_"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_EQUAL; nkey1.text = @"="; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_EQUAL; nkey2.text = @"+"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - - // row 2 - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_Q; nkey1.text = @"q"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_Q; nkey2.text = @"Q"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_W; nkey1.text = @"w"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_W; nkey2.text = @"W"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_E; nkey1.text = @"e"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_E; nkey2.text = @"E"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_R; nkey1.text = @"r"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_R; nkey2.text = @"R"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_T; nkey1.text = @"t"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_T; nkey2.text = @"T"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_Y; nkey1.text = @"y"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_Y; nkey2.text = @"Y"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_U; nkey1.text = @"u"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_U; nkey2.text = @"U"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_I; nkey1.text = @"i"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_I; nkey2.text = @"I"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_O; nkey1.text = @"o"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_O; nkey2.text = @"O"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_P; nkey1.text = @"p"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_P; nkey2.text = @"P"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_LEFT_BRACKET; nkey1.text = @"["; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_LEFT_BRACKET; nkey2.text = @"{"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_RIGHT_BRACKET; nkey1.text = @"]"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_RIGHT_BRACKET; nkey2.text = @"}"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_BACKSLASH; nkey1.text = @"\\"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_BACKSLASH; nkey2.text = @"|"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - - // row 3 - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_A; nkey1.text = @"a"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_A; nkey2.text = @"A"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_S; nkey1.text = @"s"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_S; nkey2.text = @"S"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_D; nkey1.text = @"d"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_D; nkey2.text = @"D"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_F; nkey1.text = @"f"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_F; nkey2.text = @"F"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_G; nkey1.text = @"g"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_G; nkey2.text = @"G"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_H; nkey1.text = @"h"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_H; nkey2.text = @"H"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_J; nkey1.text = @"j"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_J; nkey2.text = @"J"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_K; nkey1.text = @"k"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_K; nkey2.text = @"K"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_L; nkey1.text = @"l"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_L; nkey2.text = @"L"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_SEMICOLON; nkey1.text = @";"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_SEMICOLON; nkey2.text = @":"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_QUOTE; nkey1.text = @"'"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_QUOTE; nkey2.text = @"\""; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - - if([self use102ndKey]) { - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_OEM_102; nkey1.text = @"\\"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_OEM_102; nkey2.text = @"|"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - } - // row 4 - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_Z; nkey1.text = @"z"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_Z; nkey2.text = @"Z"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_X; nkey1.text = @"x"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_X; nkey2.text = @"X"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_C; nkey1.text = @"c"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_C; nkey2.text = @"C"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_V; nkey1.text = @"v"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_V; nkey2.text = @"V"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_B; nkey1.text = @"b"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_B; nkey2.text = @"B"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_N; nkey1.text = @"n"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_N; nkey2.text = @"N"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_M; nkey1.text = @"m"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_M; nkey2.text = @"M"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_COMMA; nkey1.text = @","; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_COMMA; nkey2.text = @"<"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_PERIOD; nkey1.text = @"."; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_PERIOD; nkey2.text = @">"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_SLASH; nkey1.text = @"/"; nkey1.bitmap = nil; - nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_SLASH; nkey2.text = @"?"; nkey2.bitmap = nil; - [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - - _oskDefaultNKeys = [[NSArray alloc] initWithArray:defNKeys]; + if (_oskDefaultNKeys == nil) { + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "oskDefaultNKeys -> creating new arrays of default number OSKKey objects"); + NSMutableArray *defNKeys = [[NSMutableArray alloc] initWithCapacity:0]; + + // row 1 + NKey *nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_GRAVE; nkey1.text = @"`"; nkey1.bitmap = nil; + NKey *nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_GRAVE; nkey2.text = @"~"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_1; nkey1.text = @"1"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_1; nkey2.text = @"!"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_2; nkey1.text = @"2"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_2; nkey2.text = @"@"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_3; nkey1.text = @"3"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_3; nkey2.text = @"#"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_4; nkey1.text = @"4"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_4; nkey2.text = @"$"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_5; nkey1.text = @"5"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_5; nkey2.text = @"%"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_6; nkey1.text = @"6"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_6; nkey2.text = @"^"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_7; nkey1.text = @"7"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_7; nkey2.text = @"&"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_8; nkey1.text = @"8"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_8; nkey2.text = @"*"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_9; nkey1.text = @"9"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_9; nkey2.text = @"("; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_0; nkey1.text = @"0"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_0; nkey2.text = @")"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_MINUS; nkey1.text = @"-"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_MINUS; nkey2.text = @"_"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_EQUAL; nkey1.text = @"="; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_EQUAL; nkey2.text = @"+"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + + // row 2 + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_Q; nkey1.text = @"q"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_Q; nkey2.text = @"Q"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_W; nkey1.text = @"w"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_W; nkey2.text = @"W"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_E; nkey1.text = @"e"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_E; nkey2.text = @"E"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_R; nkey1.text = @"r"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_R; nkey2.text = @"R"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_T; nkey1.text = @"t"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_T; nkey2.text = @"T"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_Y; nkey1.text = @"y"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_Y; nkey2.text = @"Y"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_U; nkey1.text = @"u"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_U; nkey2.text = @"U"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_I; nkey1.text = @"i"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_I; nkey2.text = @"I"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_O; nkey1.text = @"o"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_O; nkey2.text = @"O"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_P; nkey1.text = @"p"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_P; nkey2.text = @"P"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_LEFT_BRACKET; nkey1.text = @"["; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_LEFT_BRACKET; nkey2.text = @"{"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_RIGHT_BRACKET; nkey1.text = @"]"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_RIGHT_BRACKET; nkey2.text = @"}"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_BACKSLASH; nkey1.text = @"\\"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_BACKSLASH; nkey2.text = @"|"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + + // row 3 + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_A; nkey1.text = @"a"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_A; nkey2.text = @"A"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_S; nkey1.text = @"s"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_S; nkey2.text = @"S"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_D; nkey1.text = @"d"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_D; nkey2.text = @"D"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_F; nkey1.text = @"f"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_F; nkey2.text = @"F"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_G; nkey1.text = @"g"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_G; nkey2.text = @"G"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_H; nkey1.text = @"h"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_H; nkey2.text = @"H"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_J; nkey1.text = @"j"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_J; nkey2.text = @"J"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_K; nkey1.text = @"k"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_K; nkey2.text = @"K"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_L; nkey1.text = @"l"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_L; nkey2.text = @"L"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_SEMICOLON; nkey1.text = @";"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_SEMICOLON; nkey2.text = @":"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_QUOTE; nkey1.text = @"'"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_QUOTE; nkey2.text = @"\""; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + + if([self use102ndKey]) { + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_OEM_102; nkey1.text = @"\\"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_OEM_102; nkey2.text = @"|"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; } + // row 4 + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_Z; nkey1.text = @"z"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_Z; nkey2.text = @"Z"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_X; nkey1.text = @"x"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_X; nkey2.text = @"X"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_C; nkey1.text = @"c"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_C; nkey2.text = @"C"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_V; nkey1.text = @"v"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_V; nkey2.text = @"V"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_B; nkey1.text = @"b"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_B; nkey2.text = @"B"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_N; nkey1.text = @"n"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_N; nkey2.text = @"N"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_KEY_M; nkey1.text = @"m"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_KEY_M; nkey2.text = @"M"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_COMMA; nkey1.text = @","; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_COMMA; nkey2.text = @"<"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_PERIOD; nkey1.text = @"."; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_PERIOD; nkey2.text = @">"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; + nkey1 = [[NKey alloc] init]; nkey1.flags = 2; nkey1.shift = 0; nkey1.vkey = VK_SLASH; nkey1.text = @"/"; nkey1.bitmap = nil; + nkey2 = [[NKey alloc] init]; nkey2.flags = 2; nkey2.shift = 1; nkey2.vkey = VK_SLASH; nkey2.text = @"?"; nkey2.bitmap = nil; + [defNKeys addObjectsFromArray:@[nkey1, nkey2]]; - return _oskDefaultNKeys; + _oskDefaultNKeys = [[NSArray alloc] initWithArray:defNKeys]; + } + + return _oskDefaultNKeys; } - (void)resetOSK { - [self setOskShiftState:NO]; - [self setOskAltState:NO]; - [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; - [self initOSKKeys]; + [self setOskShiftState:NO]; + [self setOskAltState:NO]; + [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; + [self initOSKKeys]; } - (void)resizeOSKLayout { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView resizeOSKLayout, removing all superviews"); - [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; - [self initOSKKeys]; + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView resizeOSKLayout, removing all superviews"); + [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; + [self initOSKKeys]; } - (void)keyAction:(id)sender { - KeyView *keyView = (KeyView *)sender; - NSUInteger keyCode = [keyView.key keyCode]; - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView keyAction keyCode: 0x%lx", keyCode); - if (keyCode < 0x100) { - NSRunningApplication *app = NSWorkspace.sharedWorkspace.frontmostApplication; - pid_t processId = app.processIdentifier; - CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate); - CGEventRef keyDownEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, true); - CGEventRef keyUpEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, false); - if (self.shiftState || self.oskShiftState) { - CGEventSetFlags(keyDownEvent, CGEventGetFlags(keyDownEvent) | kCGEventFlagMaskShift); - CGEventSetFlags(keyUpEvent, CGEventGetFlags(keyUpEvent) | kCGEventFlagMaskShift); - } - if (self.altState || self.oskAltState) { - CGEventSetFlags(keyDownEvent, CGEventGetFlags(keyDownEvent) | kCGEventFlagMaskAlternate); - CGEventSetFlags(keyUpEvent, CGEventGetFlags(keyUpEvent) | kCGEventFlagMaskAlternate); - } - if (self.ctrlState || self.oskCtrlState) { - CGEventSetFlags(keyDownEvent, CGEventGetFlags(keyDownEvent) | kCGEventFlagMaskControl); - CGEventSetFlags(keyUpEvent, CGEventGetFlags(keyUpEvent) | kCGEventFlagMaskControl); - } - CGEventPostToPid(processId, keyDownEvent); - CGEventPostToPid(processId, keyUpEvent); - CFRelease(source); - CFRelease(keyDownEvent); - CFRelease(keyUpEvent); + KeyView *keyView = (KeyView *)sender; + NSUInteger keyCode = [keyView.key keyCode]; + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView keyAction keyCode: 0x%lx", keyCode); + if (keyCode < 0x100) { + NSRunningApplication *app = NSWorkspace.sharedWorkspace.frontmostApplication; + pid_t processId = app.processIdentifier; + CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate); + CGEventRef keyDownEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, true); + CGEventRef keyUpEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, false); + if (self.shiftState || self.oskShiftState) { + CGEventSetFlags(keyDownEvent, CGEventGetFlags(keyDownEvent) | kCGEventFlagMaskShift); + CGEventSetFlags(keyUpEvent, CGEventGetFlags(keyUpEvent) | kCGEventFlagMaskShift); } - else { - if (keyCode == MVK_LEFT_SHIFT || keyCode == MVK_RIGHT_SHIFT) { - [self setOskShiftState:!self.oskShiftState]; - } - else if (keyCode == MVK_LEFT_ALT || keyCode == MVK_RIGHT_ALT) { - [self setOskAltState:!self.oskAltState]; - } - else if (keyCode == MVK_LEFT_CTRL || keyCode == MVK_RIGHT_CTRL) { - [self setOskCtrlState:!self.oskCtrlState]; - } + if (self.altState || self.oskAltState) { + CGEventSetFlags(keyDownEvent, CGEventGetFlags(keyDownEvent) | kCGEventFlagMaskAlternate); + CGEventSetFlags(keyUpEvent, CGEventGetFlags(keyUpEvent) | kCGEventFlagMaskAlternate); + } + if (self.ctrlState || self.oskCtrlState) { + CGEventSetFlags(keyDownEvent, CGEventGetFlags(keyDownEvent) | kCGEventFlagMaskControl); + CGEventSetFlags(keyUpEvent, CGEventGetFlags(keyUpEvent) | kCGEventFlagMaskControl); + } + CGEventPostToPid(processId, keyDownEvent); + CGEventPostToPid(processId, keyUpEvent); + CFRelease(source); + CFRelease(keyDownEvent); + CFRelease(keyUpEvent); + } + else { + if (keyCode == MVK_LEFT_SHIFT || keyCode == MVK_RIGHT_SHIFT) { + [self setOskShiftState:!self.oskShiftState]; } + else if (keyCode == MVK_LEFT_ALT || keyCode == MVK_RIGHT_ALT) { + [self setOskAltState:!self.oskAltState]; + } + else if (keyCode == MVK_LEFT_CTRL || keyCode == MVK_RIGHT_CTRL) { + [self setOskCtrlState:!self.oskCtrlState]; + } + } } - (void)handleKeyEvent:(NSEvent *)event { - os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); - os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView handleKeyEvent event.type: %lu", event.type); - NSView *view = [self viewWithTag:event.keyCode|0x1000]; - if (view == nil || ![view isKindOfClass:[KeyView class]]) - return; - - KeyView *keyView = (KeyView *)view; - if (event.type == NSEventTypeKeyDown) - [keyView setKeyPressed:YES]; - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(setKeyPressedOff:) object:keyView]; - [self performSelector:@selector(setKeyPressedOff:) withObject:keyView afterDelay:0.1]; + os_log_t oskLog = os_log_create("org.sil.keyman", "osk"); + os_log_with_type(oskLog, OS_LOG_TYPE_DEBUG, "OSKView handleKeyEvent event.type: %lu", event.type); + NSView *view = [self viewWithTag:event.keyCode|0x1000]; + if (view == nil || ![view isKindOfClass:[KeyView class]]) + return; + + KeyView *keyView = (KeyView *)view; + if (event.type == NSEventTypeKeyDown) + [keyView setKeyPressed:YES]; + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(setKeyPressedOff:) object:keyView]; + [self performSelector:@selector(setKeyPressedOff:) withObject:keyView afterDelay:0.1]; } - (void)setKeyPressedOff:(KeyView *)keyView { - [keyView setKeyPressed:NO]; + [keyView setKeyPressed:NO]; } - (void)setKeyLabels:(BOOL)shift alt:(BOOL)alt ctrl:(BOOL)ctrl { - [self resetKeyLabels]; - NSMutableArray *mKeys = [[self keyTags] mutableCopy]; - NSArray *nkeys = [self.kvk keys]; - if (nkeys == nil) - nkeys = self.oskDefaultNKeys; - - WORD flags = 0; - if (shift) - flags |= KVKS_SHIFT; - if (alt) - flags |= KVKS_RALT; - if (ctrl) - flags |= KVKS_RCTRL; - - NSString *ansiFont = [self ansiFont]; - NSString *unicodeFont = [self unicodeFont]; - unsigned short keyCode; - for (NKey *nkey in nkeys) { - if (nkey.shift == flags) { - keyCode = [self MacKeyCode:nkey.vkey]; - if (keyCode < USHRT_MAX) { - NSView *view = [self viewWithTag:keyCode|0x1000]; - if (view == nil || ![view isKindOfClass:[KeyView class]]) - continue; - - KeyView *keyView = (KeyView *)view; - [keyView setLabelFont:ansiFont]; - if (nkey.flags & KVKK_UNICODE) { - [keyView setLabelText:nkey.text]; - [keyView setLabelFont:unicodeFont]; - [mKeys removeObject:[NSNumber numberWithInteger:(keyCode|0x1000)]]; - } - - if (nkey.flags & KVKK_BITMAP) { - [keyView setBitmap:nkey.bitmap]; - } - - [keyView setNeedsDisplay:YES]; - } - } - } - /* - for (NSNumber *t in mKeys) { - NSView *view = [self viewWithTag:[t integerValue]|0x1000]; + [self resetKeyLabels]; + NSMutableArray *mKeys = [[self keyTags] mutableCopy]; + NSArray *nkeys = [self.kvk keys]; + if (nkeys == nil) + nkeys = self.oskDefaultNKeys; + + WORD flags = 0; + if (shift) + flags |= KVKS_SHIFT; + if (alt) + flags |= KVKS_RALT; + if (ctrl) + flags |= KVKS_RCTRL; + + NSString *ansiFont = [self ansiFont]; + NSString *unicodeFont = [self unicodeFont]; + unsigned short keyCode; + for (NKey *nkey in nkeys) { + if (nkey.shift == flags) { + keyCode = [self MacKeyCode:nkey.vkey]; + if (keyCode < USHRT_MAX) { + NSView *view = [self viewWithTag:keyCode|0x1000]; if (view == nil || ![view isKindOfClass:[KeyView class]]) - continue; + continue; KeyView *keyView = (KeyView *)view; - [keyView setLabelText:@""]; - }*/ + [keyView setLabelFont:ansiFont]; + if (nkey.flags & KVKK_UNICODE) { + [keyView setLabelText:nkey.text]; + [keyView setLabelFont:unicodeFont]; + [mKeys removeObject:[NSNumber numberWithInteger:(keyCode|0x1000)]]; + } + + if (nkey.flags & KVKK_BITMAP) { + [keyView setBitmap:nkey.bitmap]; + } + + [keyView setNeedsDisplay:YES]; + } + } + } + /* + for (NSNumber *t in mKeys) { + NSView *view = [self viewWithTag:[t integerValue]|0x1000]; + if (view == nil || ![view isKindOfClass:[KeyView class]]) + continue; + + KeyView *keyView = (KeyView *)view; + [keyView setLabelText:@""]; + }*/ } - (NSArray *)keyTags { - NSMutableArray *keyTags = [NSMutableArray arrayWithCapacity:0]; - NSArray *views = [self subviews]; - for (NSView *view in views) { - if (![view isKindOfClass:[KeyView class]]) - continue; - - [keyTags addObject:[NSNumber numberWithInteger:[view tag]]]; - } + NSMutableArray *keyTags = [NSMutableArray arrayWithCapacity:0]; + NSArray *views = [self subviews]; + for (NSView *view in views) { + if (![view isKindOfClass:[KeyView class]]) + continue; - return keyTags; + [keyTags addObject:[NSNumber numberWithInteger:[view tag]]]; + } + + return keyTags; } - (void)resetKeyLabels { - NSArray *views = [self subviews]; - for (NSView *view in views) { - if (![view isKindOfClass:[KeyView class]]) - continue; - - [(KeyView *)view setKey:[(KeyView *)view key]]; - [(KeyView *)view setBitmap:nil]; - [(KeyView *)view setNeedsDisplay:YES]; - } + NSArray *views = [self subviews]; + for (NSView *view in views) { + if (![view isKindOfClass:[KeyView class]]) + continue; + + [(KeyView *)view setKey:[(KeyView *)view key]]; + [(KeyView *)view setBitmap:nil]; + [(KeyView *)view setNeedsDisplay:YES]; + } } - (void)setShiftState:(BOOL)shiftState { - if (_shiftState != shiftState) { - _shiftState = shiftState; - KeyView *shiftKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_SHIFT|0x1000]; - KeyView *shiftKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_SHIFT|0x1000]; - if (shiftState) { - [self setKeyLabels:YES alt:self.oskAltState ctrl:self.oskCtrlState]; - [shiftKeyL setKeyPressed:YES]; - [shiftKeyR setKeyPressed:YES]; - } - else { - [self setKeyLabels:NO alt:self.oskAltState ctrl:self.oskCtrlState]; - [shiftKeyL setKeyPressed:NO]; - [shiftKeyR setKeyPressed:NO]; - } + if (_shiftState != shiftState) { + _shiftState = shiftState; + KeyView *shiftKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_SHIFT|0x1000]; + KeyView *shiftKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_SHIFT|0x1000]; + if (shiftState) { + [self setKeyLabels:YES alt:self.oskAltState ctrl:self.oskCtrlState]; + [shiftKeyL setKeyPressed:YES]; + [shiftKeyR setKeyPressed:YES]; } + else { + [self setKeyLabels:NO alt:self.oskAltState ctrl:self.oskCtrlState]; + [shiftKeyL setKeyPressed:NO]; + [shiftKeyR setKeyPressed:NO]; + } + } } - (void)setOskShiftState:(BOOL)oskShiftState { - if (_oskShiftState != oskShiftState && !self.shiftState) { - _oskShiftState = oskShiftState; - KeyView *shiftKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_SHIFT|0x1000]; - KeyView *shiftKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_SHIFT|0x1000]; - if (oskShiftState) { - [self setKeyLabels:YES alt:self.oskAltState ctrl:self.oskCtrlState]; - [shiftKeyL setKeyPressed:YES]; - [shiftKeyR setKeyPressed:YES]; - } - else if (!self.shiftState) { - [self setKeyLabels:NO alt:self.oskAltState ctrl:self.oskCtrlState]; - [shiftKeyL setKeyPressed:NO]; - [shiftKeyR setKeyPressed:NO]; - } + if (_oskShiftState != oskShiftState && !self.shiftState) { + _oskShiftState = oskShiftState; + KeyView *shiftKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_SHIFT|0x1000]; + KeyView *shiftKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_SHIFT|0x1000]; + if (oskShiftState) { + [self setKeyLabels:YES alt:self.oskAltState ctrl:self.oskCtrlState]; + [shiftKeyL setKeyPressed:YES]; + [shiftKeyR setKeyPressed:YES]; + } + else if (!self.shiftState) { + [self setKeyLabels:NO alt:self.oskAltState ctrl:self.oskCtrlState]; + [shiftKeyL setKeyPressed:NO]; + [shiftKeyR setKeyPressed:NO]; } + } } - (void)setAltState:(BOOL)altState { - if (_altState != altState) { - _altState = altState; - KeyView *altKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_ALT|0x1000]; - KeyView *altKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_ALT|0x1000]; - if (altState) { - [self setKeyLabels:self.oskShiftState alt:YES ctrl:self.oskCtrlState]; - [altKeyL setKeyPressed:YES]; - [altKeyR setKeyPressed:YES]; - } - else { - [self setKeyLabels:self.oskShiftState alt:NO ctrl:self.oskCtrlState]; - [altKeyL setKeyPressed:NO]; - [altKeyR setKeyPressed:NO]; - } + if (_altState != altState) { + _altState = altState; + KeyView *altKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_ALT|0x1000]; + KeyView *altKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_ALT|0x1000]; + if (altState) { + [self setKeyLabels:self.oskShiftState alt:YES ctrl:self.oskCtrlState]; + [altKeyL setKeyPressed:YES]; + [altKeyR setKeyPressed:YES]; + } + else { + [self setKeyLabels:self.oskShiftState alt:NO ctrl:self.oskCtrlState]; + [altKeyL setKeyPressed:NO]; + [altKeyR setKeyPressed:NO]; } + } } - (void)setOskAltState:(BOOL)oskAltState { - if (_oskAltState != oskAltState && !self.altState) { - _oskAltState = oskAltState; - KeyView *altKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_ALT|0x1000]; - KeyView *altKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_ALT|0x1000]; - if (oskAltState) { - [self setKeyLabels:self.oskShiftState alt:YES ctrl:self.oskCtrlState]; - [altKeyL setKeyPressed:YES]; - [altKeyR setKeyPressed:YES]; - } - else if (!self.altState) { - [self setKeyLabels:self.oskShiftState alt:NO ctrl:self.oskCtrlState]; - [altKeyL setKeyPressed:NO]; - [altKeyR setKeyPressed:NO]; - } + if (_oskAltState != oskAltState && !self.altState) { + _oskAltState = oskAltState; + KeyView *altKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_ALT|0x1000]; + KeyView *altKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_ALT|0x1000]; + if (oskAltState) { + [self setKeyLabels:self.oskShiftState alt:YES ctrl:self.oskCtrlState]; + [altKeyL setKeyPressed:YES]; + [altKeyR setKeyPressed:YES]; + } + else if (!self.altState) { + [self setKeyLabels:self.oskShiftState alt:NO ctrl:self.oskCtrlState]; + [altKeyL setKeyPressed:NO]; + [altKeyR setKeyPressed:NO]; } + } } - (void)setCtrlState:(BOOL)ctrlState { - if (_ctrlState != ctrlState) { - _ctrlState = ctrlState; - KeyView *ctrlKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_CTRL|0x1000]; - KeyView *ctrlKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_CTRL|0x1000]; - if (ctrlState) { - [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:YES]; - [ctrlKeyL setKeyPressed:YES]; - [ctrlKeyR setKeyPressed:YES]; - } - else { - [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:NO]; - [ctrlKeyL setKeyPressed:NO]; - [ctrlKeyR setKeyPressed:NO]; - } + if (_ctrlState != ctrlState) { + _ctrlState = ctrlState; + KeyView *ctrlKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_CTRL|0x1000]; + KeyView *ctrlKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_CTRL|0x1000]; + if (ctrlState) { + [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:YES]; + [ctrlKeyL setKeyPressed:YES]; + [ctrlKeyR setKeyPressed:YES]; + } + else { + [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:NO]; + [ctrlKeyL setKeyPressed:NO]; + [ctrlKeyR setKeyPressed:NO]; } + } } - (void)setOskCtrlState:(BOOL)oskCtrlState { - if (_oskCtrlState != oskCtrlState && !self.ctrlState) { - _oskCtrlState = oskCtrlState; - KeyView *ctrlKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_CTRL|0x1000]; - KeyView *ctrlKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_CTRL|0x1000]; - if (oskCtrlState) { - [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:YES]; - [ctrlKeyL setKeyPressed:YES]; - [ctrlKeyR setKeyPressed:YES]; - } - else if (!self.ctrlState) { - [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:NO]; - [ctrlKeyL setKeyPressed:NO]; - [ctrlKeyR setKeyPressed:NO]; - } + if (_oskCtrlState != oskCtrlState && !self.ctrlState) { + _oskCtrlState = oskCtrlState; + KeyView *ctrlKeyL = (KeyView *)[self viewWithTag:MVK_LEFT_CTRL|0x1000]; + KeyView *ctrlKeyR = (KeyView *)[self viewWithTag:MVK_RIGHT_CTRL|0x1000]; + if (oskCtrlState) { + [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:YES]; + [ctrlKeyL setKeyPressed:YES]; + [ctrlKeyR setKeyPressed:YES]; } + else if (!self.ctrlState) { + [self setKeyLabels:self.oskShiftState alt:self.oskAltState ctrl:NO]; + [ctrlKeyL setKeyPressed:NO]; + [ctrlKeyR setKeyPressed:NO]; + } + } } - (NSString *)ansiFont { - return [self.kvk ansiFont].name; + return [self.kvk ansiFont].name; } - (NSString *)unicodeFont { - return [self.kvk unicodeFont].name; + return [self.kvk unicodeFont].name; } // Converts a Windows VK code to Mac VK code - (unsigned short)MacKeyCode:(unsigned short)vkCode { - unsigned short keyCode = USHRT_MAX; - for (unsigned short i = 0; i < 0x80; i++) { - if (VirtualKeyMap[i] == vkCode) { - keyCode = i; - break; - } + unsigned short keyCode = USHRT_MAX; + for (unsigned short i = 0; i < 0x80; i++) { + if (VirtualKeyMap[i] == vkCode) { + keyCode = i; + break; } - - return keyCode; + } + + return keyCode; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/Supporting Files/TimerTarget.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/Supporting Files/TimerTarget.m index 18a4607a714..b2beabb5b47 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/Supporting Files/TimerTarget.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/Supporting Files/TimerTarget.m @@ -11,7 +11,7 @@ @implementation TimerTarget - (void)timerAction:(NSTimer *)timer { - [self.target performSelector:@selector(timerAction:) withObject:timer]; + [self.target performSelector:@selector(timerAction:) withObject:timer]; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreHelperTests.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreHelperTests.m index baa4190f1e7..ac61bb805a3 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreHelperTests.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreHelperTests.m @@ -26,7 +26,7 @@ + (void)setUp { } - (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. + // Put teardown code here. This method is called after the invocation of each test method in the class. } - (void)testKeycodeConversion_MacA_ReturnsWindowsA { @@ -130,17 +130,17 @@ - (void)testConversionToUnicharString_brahmiAndLatinString_matchesLiteral { - (void)testConversionFromUnicharString_optionName_matchesLiteral { unichar const * unicharString = u"option_ligature_ew"; NSString *optionNameString = @"option_ligature_ew"; - + NSString *convertedString = [[CoreTestStaticHelperMethods helper] createNSStringFromUnicharString:unicharString]; - + XCTAssertTrue([convertedString isEqual:optionNameString], @"Converted unichar string is not equal to literal string."); } - (void)testHelperCreationPerformance { - // This is an example of a performance test case. - [self measureBlock:^{ - CoreHelper *helper = [[CoreHelper alloc] init]; - }]; + // This is an example of a performance test case. + [self measureBlock:^{ + CoreHelper *helper = [[CoreHelper alloc] init]; + }]; } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreTestStaticHelperMethods.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreTestStaticHelperMethods.m index 858e8424170..0f0aaf8a830 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreTestStaticHelperMethods.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreTestStaticHelperMethods.m @@ -23,16 +23,16 @@ + (CoreHelper *)helper { + (NSString *)getKmxFilePathTestMacEngine { NSString *path = [[NSBundle bundleForClass:[CoreTestStaticHelperMethods class]] pathForResource:@"TestMacEngine.kmx" ofType:nil]; - return path; + return path; } + (NSString *)getKmxFilePathForPlatformTest { - NSString *path = [[NSBundle bundleForClass:[CoreTestStaticHelperMethods class]] pathForResource:@"PlatformTest.kmx" ofType:@"NSString"]; + NSString *path = [[NSBundle bundleForClass:[CoreTestStaticHelperMethods class]] pathForResource:@"PlatformTest.kmx" ofType:@"NSString"]; return path; } + (NSString *)getKmxFilePathForCipherMusicTests { - NSString *path = [[NSBundle bundleForClass:[CoreTestStaticHelperMethods class]] pathForResource:@"CipherMusicUnicode.kmx" ofType:@"NSString"]; + NSString *path = [[NSBundle bundleForClass:[CoreTestStaticHelperMethods class]] pathForResource:@"CipherMusicUnicode.kmx" ofType:@"NSString"]; return path; } diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreWrapperTests.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreWrapperTests.m index 2748695a81a..6b6beb3f69d 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreWrapperTests.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/CoreWrapperTests.m @@ -27,14 +27,14 @@ @implementation CoreWrapperTests + (void)setUp { NSString *khmerKeyboardPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"khmer_angkor.kmx"]; - + NSLog(@"mockKmxFilePath = %@\n", mockKmxFilePath); - + mockWrapper = [[CoreWrapper alloc] initWithHelper: [CoreTestStaticHelperMethods helper] kmxFilePath:mockKmxFilePath]; } - (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. + // Put teardown code here. This method is called after the invocation of each test method in the class. } - (void)testCreateWrapper_mockKeyboardPath_noException { @@ -57,7 +57,7 @@ - (void)testLoadKeyboard_nonExistentKeyboard_Exception { - (void)testprocessEvent_lowercaseA_returnsExpectedCharacterForKmx { NSString *kmxPath = [CoreTestStaticHelperMethods getKmxFilePathTestMacEngine]; CoreWrapper *core = [[CoreWrapper alloc] initWithHelper: [CoreTestStaticHelperMethods helper] kmxFilePath:kmxPath]; - + // expecting character with 'Ç' CoreKeyOutput *coreOutput = [core processMacVirtualKey:MVK_A withModifiers:0 withKeyDown:YES]; XCTAssert([coreOutput.textToInsert isEqualToString:@"\u00C7"], @"Expected capital C cedille (U+00C7)"); diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m index 7bb1ed97faf..275b73911dd 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMEngineTests.m @@ -21,393 +21,393 @@ @implementation KMEngineTests NSString * names[nCombinations]; - (void)setUp { - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; } - (void)testinitWithKMX_NilKmx_ProcessEventReturnsNil { - KMEngine *engine = [[KMEngine alloc] initWithKMX:nil context:@"" verboseLogging:YES]; - NSEvent *event = [[NSEvent alloc] init]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output == nil, @"Expected processEvent to return nil for nil kmx"); + KMEngine *engine = [[KMEngine alloc] initWithKMX:nil context:@"" verboseLogging:YES]; + NSEvent *event = [[NSEvent alloc] init]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output == nil, @"Expected processEvent to return nil for nil kmx"); } - (void)testinitWithKMX_ValidKmxEmptyContext_InitializedWithEmptyContext { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - XCTAssert(engine != nil, @"Expected non-nil engine"); - // Note: relying on km_core_state_context_debug output format is just barely - // acceptable for a unit test - XCTAssert([engine.getCoreContextDebug isEqualToString:@"|| (len: 0) [ ]"], @"Expected empty context buffer"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + XCTAssert(engine != nil, @"Expected non-nil engine"); + // Note: relying on km_core_state_context_debug output format is just barely + // acceptable for a unit test + XCTAssert([engine.getCoreContextDebug isEqualToString:@"|| (len: 0) [ ]"], @"Expected empty context buffer"); } - (void)testinitWithKMX_ValidKmxNonEmptyContext_InitializedWithContext { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"abc" verboseLogging:YES]; - XCTAssert(engine != nil, @"Expected non-nil engine"); - // Note: relying on km_core_state_context_debug output format is just barely - // acceptable for a unit test - XCTAssert([engine.getCoreContextDebug isEqualToString:@"|abc| (len: 3) [ U+0061 U+0062 U+0063 ]"], @"Expected 'abc' in context buffer"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"abc" verboseLogging:YES]; + XCTAssert(engine != nil, @"Expected non-nil engine"); + // Note: relying on km_core_state_context_debug output format is just barely + // acceptable for a unit test + XCTAssert([engine.getCoreContextDebug isEqualToString:@"|abc| (len: 3) [ U+0061 U+0062 U+0063 ]"], @"Expected 'abc' in context buffer"); } - (void)testsetCoreContextIfNeeded_NonEmptyContext_InitialContextUpdated { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"a" verboseLogging:YES]; - [engine setCoreContextIfNeeded:@"xyz"]; - // Note: relying on km_core_state_context_debug output format is just barely - // acceptable for a unit test - XCTAssert([engine.getCoreContextDebug isEqualToString:@"|xyz| (len: 3) [ U+0078 U+0079 U+007a ]"], @"Expected 'xyz' in context buffer"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"a" verboseLogging:YES]; + [engine setCoreContextIfNeeded:@"xyz"]; + // Note: relying on km_core_state_context_debug output format is just barely + // acceptable for a unit test + XCTAssert([engine.getCoreContextDebug isEqualToString:@"|xyz| (len: 3) [ U+0078 U+0079 U+007a ]"], @"Expected 'xyz' in context buffer"); } // TODO: re-enable this one after the core API km_core_state_context_set_if_needed is fixed /* -- (void)testsetCoreContextIfNeeded_EmptyContext_InitialContextUpdated { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - [engine setCoreContextIfNeeded:@"xyz"]; - // Note: relying on km_core_state_context_debug output format is just barely - // acceptable for a unit test - XCTAssert([engine.getCoreContextDebug isEqualToString:@"|xyz| (len: 3) [ U+0078 U+0079 U+007a ]"], @"Expected 'xyz' in context buffer"); -} + - (void)testsetCoreContextIfNeeded_EmptyContext_InitialContextUpdated { + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + [engine setCoreContextIfNeeded:@"xyz"]; + // Note: relying on km_core_state_context_debug output format is just barely + // acceptable for a unit test + XCTAssert([engine.getCoreContextDebug isEqualToString:@"|xyz| (len: 3) [ U+0078 U+0079 U+007a ]"], @"Expected 'xyz' in context buffer"); + } */ - (void)testprocessEvent_eventForCommandKey_ReturnsNilOutput { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagCommand timestamp:0 windowNumber:0 context:nil characters:@"a" charactersIgnoringModifiers:@"a" isARepeat:NO keyCode:kVK_ANSI_A]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output == nil, @"expected nil output from core"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagCommand timestamp:0 windowNumber:0 context:nil characters:@"a" charactersIgnoringModifiers:@"a" isARepeat:NO keyCode:kVK_ANSI_A]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output == nil, @"expected nil output from core"); } - (void)testprocessEvent_eventWithoutKeycode_ReturnsNilOutput { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - NSEvent *event = [NSEvent mouseEventWithType:NSEventTypeMouseMoved location:NSMakePoint(29, 21) modifierFlags:NSEventModifierFlagShift timestamp:0 windowNumber:0 context:nil eventNumber:23 clickCount:0 pressure:0]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output == nil, @"nil CoreKeyOutput"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + NSEvent *event = [NSEvent mouseEventWithType:NSEventTypeMouseMoved location:NSMakePoint(29, 21) modifierFlags:NSEventModifierFlagShift timestamp:0 windowNumber:0 context:nil eventNumber:23 clickCount:0 pressure:0]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output == nil, @"nil CoreKeyOutput"); } // TODO: shouldn't this return emitKeystroke = YES? - (void)testprocessEvent_eventForUnmappedKey_ReturnsNoActions { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"z" charactersIgnoringModifiers:@"z" isARepeat:NO keyCode:kVK_ANSI_Z]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output == nil, @"Expected nil array of actions"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"z" charactersIgnoringModifiers:@"z" isARepeat:NO keyCode:kVK_ANSI_Z]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output == nil, @"Expected nil array of actions"); } - (void)testprocessEvent_eventForLowercaseA_ReturnsCharacterActionWithExpectedCharacterBasedOnKmx { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - 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]; - CoreKeyOutput *output = [engine processEvent:event]; - NSLog(@"output = %@", output); - XCTAssert(output.hasTextToInsert, @"output has text to insert"); - XCTAssert([output.textToInsert isEqualToString:@"\u00C7"], @"Expected capital C cedille (U+00C7)"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + 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]; + CoreKeyOutput *output = [engine processEvent:event]; + NSLog(@"output = %@", output); + XCTAssert(output.hasTextToInsert, @"output has text to insert"); + XCTAssert([output.textToInsert isEqualToString:@"\u00C7"], @"Expected capital C cedille (U+00C7)"); } // TODO: fails with core, investigate /* --(void)testprocessEvent_eventForCtrlShiftNumeralWithCipherMusicKmx_ReturnsQstrActionForCorrectUnicodeSurrogatePair { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@"" verboseLogging:YES]; - for (int i = 1; i <= 6; i++) - { - unsigned short ansiCode = kVK_ANSI_1 + i - 1; - NSString * chars = [NSString stringWithFormat:@"%d", i]; - UTF32Char expectedUtf32Char; - switch (i) { - case 1: expectedUtf32Char = 0x1D100; break; - case 2: expectedUtf32Char = 0x1D101; break; - case 3: expectedUtf32Char = 0x1D103; break; - case 4: expectedUtf32Char = 0x1D102; break; - case 5: - expectedUtf32Char = 0x1D106; - ansiCode = kVK_ANSI_5; // 5 and 6 have codes swapped so they are not in sequential order - break; - case 6: - expectedUtf32Char = 0x1D107; - ansiCode = kVK_ANSI_6; - break; - } - NSString * expectedOutput = [[NSString alloc] initWithBytes:&expectedUtf32Char length:4 encoding:NSUTF32LittleEndianStringEncoding]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagShift|NSEventModifierFlagControl timestamp:0 windowNumber:0 context:nil characters:chars charactersIgnoringModifiers:chars isARepeat:NO keyCode:ansiCode]; - 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:expectedOutput], @"Output incorrect"); - [engine clearContext]; - } -} + -(void)testprocessEvent_eventForCtrlShiftNumeralWithCipherMusicKmx_ReturnsQstrActionForCorrectUnicodeSurrogatePair { + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@"" verboseLogging:YES]; + for (int i = 1; i <= 6; i++) + { + unsigned short ansiCode = kVK_ANSI_1 + i - 1; + NSString * chars = [NSString stringWithFormat:@"%d", i]; + UTF32Char expectedUtf32Char; + switch (i) { + case 1: expectedUtf32Char = 0x1D100; break; + case 2: expectedUtf32Char = 0x1D101; break; + case 3: expectedUtf32Char = 0x1D103; break; + case 4: expectedUtf32Char = 0x1D102; break; + case 5: + expectedUtf32Char = 0x1D106; + ansiCode = kVK_ANSI_5; // 5 and 6 have codes swapped so they are not in sequential order + break; + case 6: + expectedUtf32Char = 0x1D107; + ansiCode = kVK_ANSI_6; + break; + } + NSString * expectedOutput = [[NSString alloc] initWithBytes:&expectedUtf32Char length:4 encoding:NSUTF32LittleEndianStringEncoding]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagShift|NSEventModifierFlagControl timestamp:0 windowNumber:0 context:nil characters:chars charactersIgnoringModifiers:chars isARepeat:NO keyCode:ansiCode]; + 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:expectedOutput], @"Output incorrect"); + [engine clearContext]; + } + } */ - (void)testprocessEvent_eventsForOpenCurlyBraceWithCipherMusicKmx_ReturnsCharacterForStartSlide { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - UTF32Char expectedUtf32Char = 0x1D177; - NSString * expectedStartSlideSurrogatePair = [[NSString alloc] initWithBytes:&expectedUtf32Char length:4 encoding:NSUTF32LittleEndianStringEncoding]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagShift timestamp:0 windowNumber:0 context:nil characters:@"{" charactersIgnoringModifiers:@"[" isARepeat:NO keyCode:kVK_ANSI_LeftBracket]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output.hasTextToInsert, @"expected hasTextToInsert"); - XCTAssert([output.textToInsert isEqualToString:expectedStartSlideSurrogatePair], @"output = %@", expectedStartSlideSurrogatePair); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + UTF32Char expectedUtf32Char = 0x1D177; + NSString * expectedStartSlideSurrogatePair = [[NSString alloc] initWithBytes:&expectedUtf32Char length:4 encoding:NSUTF32LittleEndianStringEncoding]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagShift timestamp:0 windowNumber:0 context:nil characters:@"{" charactersIgnoringModifiers:@"[" isARepeat:NO keyCode:kVK_ANSI_LeftBracket]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output.hasTextToInsert, @"expected hasTextToInsert"); + XCTAssert([output.textToInsert isEqualToString:expectedStartSlideSurrogatePair], @"output = %@", expectedStartSlideSurrogatePair); } /* -// TODO: fails with core, investigate -- (void)testprocessEvent_eventForUnshiftedNumeralWithCipherMusicKmx_ReturnsCharacterActionToInsertNumeral { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@"" verboseLogging:YES]; - for (int i = 1; i <= 9; i++) - { - unsigned short ansiCode = kVK_ANSI_1 + i - 1; - NSString * numeral = [NSString stringWithFormat:@"%d", i]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:numeral charactersIgnoringModifiers:numeral isARepeat:NO keyCode:ansiCode]; - NSArray *actions = [engine processEvent:event]; - NSLog(@"testprocessEvent, actions[0]: %@, expected numeral: %@", actions[0], numeral); - XCTAssert(actions.count == 1, @"Expected 1 action"); - CoreAction *action = actions[0]; - XCTAssert([action isCharacter], @"Expected CharacterAction"); - XCTAssert([action.content isEqualToString:numeral], @"Output incorrect"); - [engine clearContext]; - } -} -*/ + // TODO: fails with core, investigate + - (void)testprocessEvent_eventForUnshiftedNumeralWithCipherMusicKmx_ReturnsCharacterActionToInsertNumeral { + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile contextBuffer:@"" verboseLogging:YES]; + for (int i = 1; i <= 9; i++) + { + unsigned short ansiCode = kVK_ANSI_1 + i - 1; + NSString * numeral = [NSString stringWithFormat:@"%d", i]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:numeral charactersIgnoringModifiers:numeral isARepeat:NO keyCode:ansiCode]; + NSArray *actions = [engine processEvent:event]; + NSLog(@"testprocessEvent, actions[0]: %@, expected numeral: %@", actions[0], numeral); + XCTAssert(actions.count == 1, @"Expected 1 action"); + CoreAction *action = actions[0]; + XCTAssert([action isCharacter], @"Expected CharacterAction"); + XCTAssert([action.content isEqualToString:numeral], @"Output incorrect"); + [engine clearContext]; + } + } + */ // TODO: fails with core, returns CharacterAction - (void)testprocessEvent_eventForShiftNumeralsWithoutRulesInCipherMusicKmx_ReturnsNoAction { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - for (int i = 0; i <= 9; i++) - { - if (i == 6) - continue; // There is a rule in the keyboard for '^' (which is a SHIFT+6). - unsigned short ansiCode = kVK_ANSI_1 + i - 1; // This works for 1-4 - NSString * unmodifiedChars = [NSString stringWithFormat:@"%d", i]; - NSString * chars; - switch (i) { - case 0: - chars = @")"; - ansiCode = kVK_ANSI_0; - break; - case 1: chars = @"!"; break; - case 2: chars = @"@"; break; - case 3: chars = @"#"; break; - case 4: chars = @"$"; break; - case 5: - chars = @"%"; - ansiCode = kVK_ANSI_5; - break; - case 7: - chars = @"&"; - ansiCode = kVK_ANSI_7; - break; - case 8: - chars = @"*"; - ansiCode = kVK_ANSI_8; - break; - case 9: - chars = @"(%)"; - ansiCode = kVK_ANSI_9; - break; - } - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagShift timestamp:0 windowNumber:0 context:nil characters:chars charactersIgnoringModifiers:unmodifiedChars isARepeat:NO keyCode:ansiCode]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output.emitKeystroke, @"expected emit keycode"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + for (int i = 0; i <= 9; i++) + { + if (i == 6) + continue; // There is a rule in the keyboard for '^' (which is a SHIFT+6). + unsigned short ansiCode = kVK_ANSI_1 + i - 1; // This works for 1-4 + NSString * unmodifiedChars = [NSString stringWithFormat:@"%d", i]; + NSString * chars; + switch (i) { + case 0: + chars = @")"; + ansiCode = kVK_ANSI_0; + break; + case 1: chars = @"!"; break; + case 2: chars = @"@"; break; + case 3: chars = @"#"; break; + case 4: chars = @"$"; break; + case 5: + chars = @"%"; + ansiCode = kVK_ANSI_5; + break; + case 7: + chars = @"&"; + ansiCode = kVK_ANSI_7; + break; + case 8: + chars = @"*"; + ansiCode = kVK_ANSI_8; + break; + case 9: + chars = @"(%)"; + ansiCode = kVK_ANSI_9; + break; } + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagShift timestamp:0 windowNumber:0 context:nil characters:chars charactersIgnoringModifiers:unmodifiedChars isARepeat:NO keyCode:ansiCode]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output.emitKeystroke, @"expected emit keycode"); + } } // TODO: fails with core, returns CharacterAction - (void)testprocessEvent_eventForPeriodWithCipherMusicKmx_ReturnsNoAction { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"." charactersIgnoringModifiers:@"." isARepeat:NO keyCode:kVK_ANSI_Period]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(!output.hasTextToInsert, @"expected no text to insert"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"." charactersIgnoringModifiers:@"." isARepeat:NO keyCode:kVK_ANSI_Period]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(!output.hasTextToInsert, @"expected no text to insert"); } - (void)testprocessEvent_eventForCtrl8WithCipherMusicKmx_ReturnsEmit { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagControl timestamp:0 windowNumber:0 context:nil characters:@"8" charactersIgnoringModifiers:@"8" isARepeat:NO keyCode:kVK_ANSI_8]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output.emitKeystroke, @"emitKeystroke == YES"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForCipherMusicTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:NSEventModifierFlagControl timestamp:0 windowNumber:0 context:nil characters:@"8" charactersIgnoringModifiers:@"8" isARepeat:NO keyCode:kVK_ANSI_8]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output.emitKeystroke, @"emitKeystroke == YES"); } + (void)fillInNamesAndModifiersForAllChiralCombinations { - int i = 0; - modifiers[i] = LEFT_CTRL_FLAG; - names[i++] = @"LEFT CTRL"; - modifiers[i] = LEFT_SHIFT_FLAG; - names[i++] = @"LEFT SHIFT"; - modifiers[i] = RIGHT_SHIFT_FLAG; - names[i++] = @"RIGHT SHIFT"; - modifiers[i] = RIGHT_CTRL_FLAG; - names[i++] = @"RIGHT CTRL"; - modifiers[i] = LEFT_ALT_FLAG; - names[i++] = @"LEFT ALT"; - modifiers[i] = RIGHT_ALT_FLAG; - names[i++] = @"RIGHT ALT"; - modifiers[i] = LEFT_CTRL_FLAG | LEFT_ALT_FLAG; - names[i++] = @"LEFT CTRL+ALT"; - modifiers[i] = RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG; - names[i++] = @"RIGHT CTRL+ALT"; - modifiers[i] = LEFT_CTRL_FLAG | LEFT_SHIFT_FLAG; - names[i++] = @"LEFT CTRL+SHIFT"; - modifiers[i] = RIGHT_CTRL_FLAG | RIGHT_SHIFT_FLAG; - names[i++] = @"RIGHT CTRL+SHIFT"; - modifiers[i] = LEFT_ALT_FLAG | LEFT_SHIFT_FLAG; - names[i++] = @"LEFT ALT+SHIFT"; - modifiers[i] = RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG; - names[i++] = @"RIGHT ALT+SHIFT"; - modifiers[i] = LEFT_CTRL_FLAG | LEFT_ALT_FLAG | LEFT_SHIFT_FLAG; - names[i++] = @"LEFT CTRL+ALT+SHIFT"; - modifiers[i] = RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG; - names[i++] = @"RIGHT CTRL+ALT+SHIFT"; + int i = 0; + modifiers[i] = LEFT_CTRL_FLAG; + names[i++] = @"LEFT CTRL"; + modifiers[i] = LEFT_SHIFT_FLAG; + names[i++] = @"LEFT SHIFT"; + modifiers[i] = RIGHT_SHIFT_FLAG; + names[i++] = @"RIGHT SHIFT"; + modifiers[i] = RIGHT_CTRL_FLAG; + names[i++] = @"RIGHT CTRL"; + modifiers[i] = LEFT_ALT_FLAG; + names[i++] = @"LEFT ALT"; + modifiers[i] = RIGHT_ALT_FLAG; + names[i++] = @"RIGHT ALT"; + modifiers[i] = LEFT_CTRL_FLAG | LEFT_ALT_FLAG; + names[i++] = @"LEFT CTRL+ALT"; + modifiers[i] = RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG; + names[i++] = @"RIGHT CTRL+ALT"; + modifiers[i] = LEFT_CTRL_FLAG | LEFT_SHIFT_FLAG; + names[i++] = @"LEFT CTRL+SHIFT"; + modifiers[i] = RIGHT_CTRL_FLAG | RIGHT_SHIFT_FLAG; + names[i++] = @"RIGHT CTRL+SHIFT"; + modifiers[i] = LEFT_ALT_FLAG | LEFT_SHIFT_FLAG; + names[i++] = @"LEFT ALT+SHIFT"; + modifiers[i] = RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG; + names[i++] = @"RIGHT ALT+SHIFT"; + modifiers[i] = LEFT_CTRL_FLAG | LEFT_ALT_FLAG | LEFT_SHIFT_FLAG; + names[i++] = @"LEFT CTRL+ALT+SHIFT"; + modifiers[i] = RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG; + names[i++] = @"RIGHT CTRL+ALT+SHIFT"; } - (void)testprocessEvent_eventForAWithModifiers_ReturnsCharacterActionWithExpectedCharacterBasedOnKmx { - int i = 0; - [KMEngineTests fillInNamesAndModifiersForAllChiralCombinations]; - - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - - for (i = 0; i < nCombinations; i++) { - [engine clearCoreContext]; - NSString *charactersIgnoringModifiers = (modifiers[i] & (LEFT_SHIFT_FLAG | RIGHT_SHIFT_FLAG)) ? @"A" : @"a"; - NSString * characters = charactersIgnoringModifiers; - if (modifiers[i] & (LEFT_ALT_FLAG | RIGHT_ALT_FLAG)) - characters = [characters stringByAppendingString:@"\u030A"]; - - NSLog(@"Test case: %lu", (NSUInteger)modifiers[i]); - // NOTE: 'a' happens to be keyCode 0 (see initVirtualKeyMapping in CoreHelper) - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:modifiers[i] timestamp:0 windowNumber:0 context:nil characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:0]; - NSString * keyCombination = [names[i] stringByAppendingFormat:@" %@", charactersIgnoringModifiers]; - CoreKeyOutput *coreKeyOutput = [engine processEvent:event]; - XCTAssert(coreKeyOutput.hasTextToInsert, @"hasTextToInsert for %@", keyCombination); - NSString *output = coreKeyOutput.textToInsert; - NSLog(@"output = %@", output); - switch (modifiers[i]) { - case LEFT_SHIFT_FLAG: - case RIGHT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00AE"], @"Expected Registered Sign (U+00AE) for %@", keyCombination); - break; - case LEFT_CTRL_FLAG: - XCTAssert([output isEqualToString:@"\u00A3"], @"Expected Pound Sign (U+00A3) for %@", keyCombination); - break; - case RIGHT_CTRL_FLAG: - XCTAssert([output isEqualToString:@"\u00A4"], @"Expected Currency Sign (U+00A4) for %@", keyCombination); - break; - case LEFT_ALT_FLAG: - XCTAssert([output isEqualToString:@"\u00A1"], @"Expected Inverted Exclamation Mark (U+00A1) for %@", keyCombination); - break; - case RIGHT_ALT_FLAG: - XCTAssert([output isEqualToString:@"\u00A2"], @"Expected Cent Sign (U+00A2) for %@", keyCombination); - break; - case LEFT_CTRL_FLAG | LEFT_ALT_FLAG: - XCTAssert([output isEqualToString:@"\u00A6"], @"Expected Broken Bar (U+00A6) for %@", keyCombination); - break; - case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG: - XCTAssert([output isEqualToString:@"\u00A5"], @"Expected Yen Sign (U+00A5) for %@", keyCombination); - break; - case LEFT_CTRL_FLAG | LEFT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00DB"], @"Expected Capital U with Circumflex (U+00DB) for %@", keyCombination); - break; - case RIGHT_CTRL_FLAG | RIGHT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00DF"], @"Expected Small Letter Sharp S (U+00DF) for %@", keyCombination); - break; - case LEFT_ALT_FLAG | LEFT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00CB"], @"Expected Capital E with Diaresis (U+00CB) for %@", keyCombination); - break; - case RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00BD"], @"Expected Vulgar Fraction One Half (U+00BD) for %@", keyCombination); - break; - case LEFT_CTRL_FLAG | LEFT_ALT_FLAG | LEFT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00D8"], @"Expected Capital O with Stroke (U+00D8) for %@", keyCombination); - break; - case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00B5"], @"Expected Micro Sign (U+00B5) for %@", keyCombination); - break; - } + int i = 0; + [KMEngineTests fillInNamesAndModifiersForAllChiralCombinations]; + + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + + for (i = 0; i < nCombinations; i++) { + [engine clearCoreContext]; + NSString *charactersIgnoringModifiers = (modifiers[i] & (LEFT_SHIFT_FLAG | RIGHT_SHIFT_FLAG)) ? @"A" : @"a"; + NSString * characters = charactersIgnoringModifiers; + if (modifiers[i] & (LEFT_ALT_FLAG | RIGHT_ALT_FLAG)) + characters = [characters stringByAppendingString:@"\u030A"]; + + NSLog(@"Test case: %lu", (NSUInteger)modifiers[i]); + // NOTE: 'a' happens to be keyCode 0 (see initVirtualKeyMapping in CoreHelper) + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:modifiers[i] timestamp:0 windowNumber:0 context:nil characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:0]; + NSString * keyCombination = [names[i] stringByAppendingFormat:@" %@", charactersIgnoringModifiers]; + CoreKeyOutput *coreKeyOutput = [engine processEvent:event]; + XCTAssert(coreKeyOutput.hasTextToInsert, @"hasTextToInsert for %@", keyCombination); + NSString *output = coreKeyOutput.textToInsert; + NSLog(@"output = %@", output); + switch (modifiers[i]) { + case LEFT_SHIFT_FLAG: + case RIGHT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00AE"], @"Expected Registered Sign (U+00AE) for %@", keyCombination); + break; + case LEFT_CTRL_FLAG: + XCTAssert([output isEqualToString:@"\u00A3"], @"Expected Pound Sign (U+00A3) for %@", keyCombination); + break; + case RIGHT_CTRL_FLAG: + XCTAssert([output isEqualToString:@"\u00A4"], @"Expected Currency Sign (U+00A4) for %@", keyCombination); + break; + case LEFT_ALT_FLAG: + XCTAssert([output isEqualToString:@"\u00A1"], @"Expected Inverted Exclamation Mark (U+00A1) for %@", keyCombination); + break; + case RIGHT_ALT_FLAG: + XCTAssert([output isEqualToString:@"\u00A2"], @"Expected Cent Sign (U+00A2) for %@", keyCombination); + break; + case LEFT_CTRL_FLAG | LEFT_ALT_FLAG: + XCTAssert([output isEqualToString:@"\u00A6"], @"Expected Broken Bar (U+00A6) for %@", keyCombination); + break; + case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG: + XCTAssert([output isEqualToString:@"\u00A5"], @"Expected Yen Sign (U+00A5) for %@", keyCombination); + break; + case LEFT_CTRL_FLAG | LEFT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00DB"], @"Expected Capital U with Circumflex (U+00DB) for %@", keyCombination); + break; + case RIGHT_CTRL_FLAG | RIGHT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00DF"], @"Expected Small Letter Sharp S (U+00DF) for %@", keyCombination); + break; + case LEFT_ALT_FLAG | LEFT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00CB"], @"Expected Capital E with Diaresis (U+00CB) for %@", keyCombination); + break; + case RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00BD"], @"Expected Vulgar Fraction One Half (U+00BD) for %@", keyCombination); + break; + case LEFT_CTRL_FLAG | LEFT_ALT_FLAG | LEFT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00D8"], @"Expected Capital O with Stroke (U+00D8) for %@", keyCombination); + break; + case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00B5"], @"Expected Micro Sign (U+00B5) for %@", keyCombination); + break; } + } } - (void)testprocessEvent_eventForSWithModifiers_ReturnsCharacterActionWithExpectedCharacterBasedOnKmx { - int i = 0; - [KMEngineTests fillInNamesAndModifiersForAllChiralCombinations]; - - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - - for (i = 0; i < nCombinations; i++) { - [engine clearCoreContext]; - NSString *charactersIgnoringModifiers = (modifiers[i] & (LEFT_SHIFT_FLAG | RIGHT_SHIFT_FLAG)) ? @"S" : @"s"; - NSString * characters = charactersIgnoringModifiers; - if (modifiers[i] & (LEFT_ALT_FLAG | RIGHT_ALT_FLAG)) { - if (modifiers[i] & (LEFT_SHIFT_FLAG | RIGHT_SHIFT_FLAG)) - characters = @"Í"; - else - characters = @"ß"; - } - - NSLog(@"Test case: %lu", (NSUInteger)modifiers[i]); - // NOTE: 's' happens to be keyCode 1 (see initVirtualKeyMapping in CoreHelper) - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:modifiers[i] timestamp:0 windowNumber:0 context:nil characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:1]; - NSString * keyCombination = [names[i] stringByAppendingFormat:@" %@", charactersIgnoringModifiers]; - CoreKeyOutput *coreKeyOutput = [engine processEvent:event]; - NSString *output = coreKeyOutput.textToInsert; - NSLog(@"output = %@", output); - switch (modifiers[i]) { - case LEFT_SHIFT_FLAG: - case RIGHT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00E6"], @"Expected Small Letter ae (U+00E6) for %@", keyCombination); - break; - case LEFT_CTRL_FLAG: - XCTAssert([output isEqualToString:@"\u00AA"], @"Expected Feminine Ordinal Indicator (U+00AA) for %@", keyCombination); - break; - case RIGHT_CTRL_FLAG: - XCTAssert([output isEqualToString:@"\u00AB"], @"Expected Left-Pointing Double Angle Quotation Mark (U+00AB) for %@", keyCombination); - break; - case LEFT_ALT_FLAG: - XCTAssert([output isEqualToString:@"\u00A8"], @"Expected Diaresis (U+00A8) for %@", keyCombination); - break; - case RIGHT_ALT_FLAG: - XCTAssert([output isEqualToString:@"\u00A9"], @"Expected Copyright Sign (U+00A9) for %@", keyCombination); - break; - case LEFT_CTRL_FLAG | LEFT_ALT_FLAG: - XCTAssert([output isEqualToString:@"\u00AD"], @"Expected Soft Hyphen (U+00AD) for %@", keyCombination); - break; - case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG: - XCTAssert([output isEqualToString:@"\u00AC"], @"Expected Not Sign (U+00AC) for %@", keyCombination); - break; - case LEFT_CTRL_FLAG | LEFT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00E1"], @"Expected Small A with Acute (U+00E1) for %@", keyCombination); - break; - case RIGHT_CTRL_FLAG | RIGHT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00E0"], @"Expected Small A with Grave (U+00E0) for %@", keyCombination); - break; - case LEFT_ALT_FLAG | LEFT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00E5"], @"Expected Small A with Ring Above (U+00E5) for %@", keyCombination); - break; - case RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00E4"], @"Expected Small A with Diaresis (U+00E4) for %@", keyCombination); - break; - case LEFT_CTRL_FLAG | LEFT_ALT_FLAG | LEFT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00E2"], @"Expected Small A with Circumflex (U+00E2) for %@", keyCombination); - break; - case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG: - XCTAssert([output isEqualToString:@"\u00E3"], @"Expected Small A with Tilde (U+00E3) for %@", keyCombination); - break; - } + int i = 0; + [KMEngineTests fillInNamesAndModifiersForAllChiralCombinations]; + + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + + for (i = 0; i < nCombinations; i++) { + [engine clearCoreContext]; + NSString *charactersIgnoringModifiers = (modifiers[i] & (LEFT_SHIFT_FLAG | RIGHT_SHIFT_FLAG)) ? @"S" : @"s"; + NSString * characters = charactersIgnoringModifiers; + if (modifiers[i] & (LEFT_ALT_FLAG | RIGHT_ALT_FLAG)) { + if (modifiers[i] & (LEFT_SHIFT_FLAG | RIGHT_SHIFT_FLAG)) + characters = @"Í"; + else + characters = @"ß"; } + + NSLog(@"Test case: %lu", (NSUInteger)modifiers[i]); + // NOTE: 's' happens to be keyCode 1 (see initVirtualKeyMapping in CoreHelper) + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:modifiers[i] timestamp:0 windowNumber:0 context:nil characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:1]; + NSString * keyCombination = [names[i] stringByAppendingFormat:@" %@", charactersIgnoringModifiers]; + CoreKeyOutput *coreKeyOutput = [engine processEvent:event]; + NSString *output = coreKeyOutput.textToInsert; + NSLog(@"output = %@", output); + switch (modifiers[i]) { + case LEFT_SHIFT_FLAG: + case RIGHT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00E6"], @"Expected Small Letter ae (U+00E6) for %@", keyCombination); + break; + case LEFT_CTRL_FLAG: + XCTAssert([output isEqualToString:@"\u00AA"], @"Expected Feminine Ordinal Indicator (U+00AA) for %@", keyCombination); + break; + case RIGHT_CTRL_FLAG: + XCTAssert([output isEqualToString:@"\u00AB"], @"Expected Left-Pointing Double Angle Quotation Mark (U+00AB) for %@", keyCombination); + break; + case LEFT_ALT_FLAG: + XCTAssert([output isEqualToString:@"\u00A8"], @"Expected Diaresis (U+00A8) for %@", keyCombination); + break; + case RIGHT_ALT_FLAG: + XCTAssert([output isEqualToString:@"\u00A9"], @"Expected Copyright Sign (U+00A9) for %@", keyCombination); + break; + case LEFT_CTRL_FLAG | LEFT_ALT_FLAG: + XCTAssert([output isEqualToString:@"\u00AD"], @"Expected Soft Hyphen (U+00AD) for %@", keyCombination); + break; + case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG: + XCTAssert([output isEqualToString:@"\u00AC"], @"Expected Not Sign (U+00AC) for %@", keyCombination); + break; + case LEFT_CTRL_FLAG | LEFT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00E1"], @"Expected Small A with Acute (U+00E1) for %@", keyCombination); + break; + case RIGHT_CTRL_FLAG | RIGHT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00E0"], @"Expected Small A with Grave (U+00E0) for %@", keyCombination); + break; + case LEFT_ALT_FLAG | LEFT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00E5"], @"Expected Small A with Ring Above (U+00E5) for %@", keyCombination); + break; + case RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00E4"], @"Expected Small A with Diaresis (U+00E4) for %@", keyCombination); + break; + case LEFT_CTRL_FLAG | LEFT_ALT_FLAG | LEFT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00E2"], @"Expected Small A with Circumflex (U+00E2) for %@", keyCombination); + break; + case RIGHT_CTRL_FLAG | RIGHT_ALT_FLAG | RIGHT_SHIFT_FLAG: + XCTAssert([output isEqualToString:@"\u00E3"], @"Expected Small A with Tilde (U+00E3) for %@", keyCombination); + break; + } + } } // The following checkPlatform tests all use the PlatformTest KMX file based on PlatformTest.kmn @@ -417,84 +417,84 @@ - (void)testprocessEvent_eventForSWithModifiers_ReturnsCharacterActionWithExpect // 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]; + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForPlatformTest]; KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - 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]; - CoreKeyOutput *output = [engine processEvent:event]; - return output.textToInsert; + 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]; + CoreKeyOutput *output = [engine processEvent:event]; + return output.textToInsert; } // TODO: rewrite for combined character actions - (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."); + NSString *output = [self checkPlatform_getOutputForKeystroke:@"u" modifierFlags:0 keyCode:kVK_ANSI_U]; + XCTAssert([output isEqualToString:@" Native"], @"Expected checkPlatform to return YES for native."); } // TODO: rewrite for combined character actions - (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."); + NSString *output = [self checkPlatform_getOutputForKeystroke:@"U" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_U]; + XCTAssert([output isEqualToString:@" Native"], @"Expected checkPlatform to return YES for NATIVE."); } // TODO: rewrite for combined character actions - (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."); + NSString *output = [self checkPlatform_getOutputForKeystroke:@"p" modifierFlags:0 keyCode:kVK_ANSI_P]; + XCTAssert([output isEqualToString:@" Hardware"], @"Expected checkPlatform to return YES for hardware."); } // TODO: rewrite for combined character actions - (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."); + NSString *output = [self checkPlatform_getOutputForKeystroke:@"P" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_P]; + XCTAssert([output isEqualToString:@" Hardware"], @"Expected checkPlatform to return YES for HARDWARE."); } // TODO: rewrite for combined character actions - (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."); + NSString *output = [self checkPlatform_getOutputForKeystroke:@"I" modifierFlags:0 keyCode:kVK_ANSI_I]; + XCTAssert([output isEqualToString:@" Desktop"], @"Expected checkPlatform to return YES for desktop."); } // TODO: rewrite for combined character actions - (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."); + NSString *output = [self checkPlatform_getOutputForKeystroke:@"I" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_I]; + XCTAssert([output isEqualToString:@" Desktop"], @"Expected checkPlatform to return YES for Desktop."); } // TODO: rewrite for combined character actions - (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."); + NSString *output = [self checkPlatform_getOutputForKeystroke:@"o" modifierFlags:0 keyCode:kVK_ANSI_O]; + XCTAssert([output isEqualToString:@" macOS"], @"Expected checkPlatform to return YES for macosx."); } // TODO: rewrite for combined character actions - (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."); + NSString *output = [self checkPlatform_getOutputForKeystroke:@"K" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_K]; + XCTAssert([output isEqualToString:@" macOS"], @"Expected checkPlatform to return YES for MacOS."); } // TODO: rewrite for combined character actions - (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."); + NSString *output = [self checkPlatform_getOutputForKeystroke:@"L" modifierFlags:NSEventModifierFlagShift keyCode:kVK_ANSI_L]; + XCTAssert([output isEqualToString:@" mac"], @"Expected checkPlatform to return YES for MAC."); } // TODO: rewrite for combined character actions - (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)."); + 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)."); } // TODO: rewrite for combined character actions - (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."); + 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."); } // TODO: rewrite for combined character actions - (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."); + 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. @@ -514,95 +514,95 @@ - (void)testContextMatch_InvertedPlatformLogic_NotTouch { - (void)testEngine_ipaKeyboardAction_DoesNotCrash_Issue1892 { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForIndexOffsetTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"z" verboseLogging:YES]; - 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]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output.hasCodePointsToDelete, @"output hasCodePointsToDelete == YES"); - XCTAssert([output.textToInsert isEqualToString:@"Z"], @"Expected output to be 'Z'."); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForIndexOffsetTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"z" verboseLogging:YES]; + 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]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output.hasCodePointsToDelete, @"output hasCodePointsToDelete == YES"); + XCTAssert([output.textToInsert isEqualToString:@"Z"], @"Expected output to be 'Z'."); } - (void)testCoreProcessEvent_eventForFWithElNuerKmx_ReturnsCorrectCharacter { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"f" charactersIgnoringModifiers:@"f" isARepeat:NO keyCode:kVK_ANSI_F]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert([output.textToInsert isEqualToString:@"ɣ"], @"Expected output to be 'ɣ'."); - XCTAssert(!output.hasCodePointsToDelete, @"expected to delete nothing"); - XCTAssert(!output.emitKeystroke, @"expected to emit nothing"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"f" charactersIgnoringModifiers:@"f" isARepeat:NO keyCode:kVK_ANSI_F]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert([output.textToInsert isEqualToString:@"ɣ"], @"Expected output to be 'ɣ'."); + XCTAssert(!output.hasCodePointsToDelete, @"expected to delete nothing"); + XCTAssert(!output.emitKeystroke, @"expected to emit nothing"); } - (void)testArmenianMnemonic_triggerPersistOptions_ReturnsOptions { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForArmenianMnemonicTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"√" verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"w" charactersIgnoringModifiers:@"w" isARepeat:NO keyCode:kVK_ANSI_W]; - CoreKeyOutput *output = [engine processEvent:event]; - NSString *key = @"option_ligature_ew"; - NSDictionary *options = output.optionsToPersist; - NSString *value = options[key]; - XCTAssertEqualObjects(value, @"1", @"expected 'option_ligature_ew' with value of '1'"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForArmenianMnemonicTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"√" verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"w" charactersIgnoringModifiers:@"w" isARepeat:NO keyCode:kVK_ANSI_W]; + CoreKeyOutput *output = [engine processEvent:event]; + NSString *key = @"option_ligature_ew"; + NSDictionary *options = output.optionsToPersist; + NSString *value = options[key]; + XCTAssertEqualObjects(value, @"1", @"expected 'option_ligature_ew' with value of '1'"); } - (void)testCoreProcessEvent_backspaceElNuerEmptyContext_PassesThrough { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\b" charactersIgnoringModifiers:@"\b" isARepeat:NO keyCode:kVK_Delete]; - CoreKeyOutput *output = [engine processEvent:event]; - NSLog(@"output: %@", output); - XCTAssert(!output.hasTextToInsert, @"expected to insert nothing"); - XCTAssert(!output.hasCodePointsToDelete, @"expected to delete nothing"); - XCTAssert(output.emitKeystroke, @"expected to emit key"); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"" verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\b" charactersIgnoringModifiers:@"\b" isARepeat:NO keyCode:kVK_Delete]; + CoreKeyOutput *output = [engine processEvent:event]; + NSLog(@"output: %@", output); + XCTAssert(!output.hasTextToInsert, @"expected to insert nothing"); + XCTAssert(!output.hasCodePointsToDelete, @"expected to delete nothing"); + XCTAssert(output.emitKeystroke, @"expected to emit key"); } - (void)testCoreProcessEvent_backspaceElNuerWithContext_EmptiesContextReturnsDelete { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"ɣ" verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\b" charactersIgnoringModifiers:@"\b" isARepeat:NO keyCode:kVK_Delete]; - CoreKeyOutput *output = [engine processEvent:event]; - NSLog(@"output: %@", output); - XCTAssert(output.codePointsToDeleteBeforeInsert == 1, @"Expected output to delete one code point"); - XCTAssert(!output.hasTextToInsert, @"expected to insert nothing"); - NSString *context = engine.getCoreContextDebug; - // Note: relying on km_core_state_context_debug output format is just barely - // acceptable for a unit test - XCTAssert([context isEqualToString:@"|| (len: 0) [ ]"], @"Context should be empty."); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"ɣ" verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\b" charactersIgnoringModifiers:@"\b" isARepeat:NO keyCode:kVK_Delete]; + CoreKeyOutput *output = [engine processEvent:event]; + NSLog(@"output: %@", output); + XCTAssert(output.codePointsToDeleteBeforeInsert == 1, @"Expected output to delete one code point"); + XCTAssert(!output.hasTextToInsert, @"expected to insert nothing"); + NSString *context = engine.getCoreContextDebug; + // Note: relying on km_core_state_context_debug output format is just barely + // acceptable for a unit test + XCTAssert([context isEqualToString:@"|| (len: 0) [ ]"], @"Context should be empty."); } - (void)testCoreProcessEvent_eventReturnWithElNuerKmx_EmitWithContextEmpty { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"ɣ" verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\n" charactersIgnoringModifiers:@"\n" isARepeat:NO keyCode:kVK_Return]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output.emitKeystroke, @"Expected emitKeystroke==YES"); - NSString *context = engine.getCoreContextDebug; - // Note: relying on km_core_state_context_debug output format is just barely - // acceptable for a unit test - XCTAssert([context isEqualToString:@"|| (len: 0) [ ]"], @"Context should be cleared."); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"ɣ" verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\n" charactersIgnoringModifiers:@"\n" isARepeat:NO keyCode:kVK_Return]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output.emitKeystroke, @"Expected emitKeystroke==YES"); + NSString *context = engine.getCoreContextDebug; + // Note: relying on km_core_state_context_debug output format is just barely + // acceptable for a unit test + XCTAssert([context isEqualToString:@"|| (len: 0) [ ]"], @"Context should be cleared."); } - (void)testCoreProcessEvent_eventTabWithElNuerKmx_EmitWithContextEmpty { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"ɣ" verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\t" charactersIgnoringModifiers:@"\t" isARepeat:NO keyCode:kVK_Tab]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output.emitKeystroke, @"Expected emitKeystroke==YES"); - NSString *context = engine.getCoreContextDebug; - // Note: relying on km_core_state_context_debug output format is just barely - // acceptable for a unit test - XCTAssert([context isEqualToString:@"|| (len: 0) [ ]"], @"Context should be cleared."); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:@"ɣ" verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"\t" charactersIgnoringModifiers:@"\t" isARepeat:NO keyCode:kVK_Tab]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output.emitKeystroke, @"Expected emitKeystroke==YES"); + NSString *context = engine.getCoreContextDebug; + // Note: relying on km_core_state_context_debug output format is just barely + // acceptable for a unit test + XCTAssert([context isEqualToString:@"|| (len: 0) [ ]"], @"Context should be cleared."); } - (void)testCoreProcessEvent_eventSingleQuoteWithElNuerKmx_ReturnsDiacritic { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; - NSString *context = @"ɛ"; - KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:context verboseLogging:YES]; - NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"'" charactersIgnoringModifiers:@"'" isARepeat:NO keyCode:kVK_ANSI_Quote]; - CoreKeyOutput *output = [engine processEvent:event]; - XCTAssert(output.hasTextToInsert, @"returns text to insert"); - context = engine.getCoreContextDebug; - // Note: relying on km_core_state_context_debug output format is just barely - // acceptable for a unit test - XCTAssert([context isEqualToString:@"|\u025B\u0308| (len: 2) [ U+025b U+0308 ]"], @"Context updated with diacritic."); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileForElNuerTests]; + NSString *context = @"ɛ"; + KMEngine *engine = [[KMEngine alloc] initWithKMX:kmxFile context:context verboseLogging:YES]; + NSEvent *event = [NSEvent keyEventWithType:NSEventTypeKeyDown location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:0 context:nil characters:@"'" charactersIgnoringModifiers:@"'" isARepeat:NO keyCode:kVK_ANSI_Quote]; + CoreKeyOutput *output = [engine processEvent:event]; + XCTAssert(output.hasTextToInsert, @"returns text to insert"); + context = engine.getCoreContextDebug; + // Note: relying on km_core_state_context_debug output format is just barely + // acceptable for a unit test + XCTAssert([context isEqualToString:@"|\u025B\u0308| (len: 2) [ U+025b U+0308 ]"], @"Context updated with diacritic."); } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMXFileTests.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMXFileTests.m index e5ddf800941..6b13479d872 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMXFileTests.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KMXFileTests.m @@ -17,29 +17,29 @@ @interface KMXFileTests : XCTestCase @implementation KMXFileTests - (void)setUp { - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; } - (void)testinitWithFilePath_NilPath_ReturnsNil { - KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:nil]; - XCTAssert(kmxFile == nil, @"Expected nil file"); + KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:nil]; + XCTAssert(kmxFile == nil, @"Expected nil file"); } - (void)testinitWithFilePath_BogusPath_ReturnsNil { - KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:@"This is not a valid path to nuthin'"]; - XCTAssert(kmxFile == nil, @"Expected nil file"); + KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:@"This is not a valid path to nuthin'"]; + XCTAssert(kmxFile == nil, @"Expected nil file"); } - (void)testinitWithFilePath_Valid_ReturnsInitializedKmxFile { - KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; - XCTAssert(kmxFile != nil, @"Expected non-nil file"); - XCTAssert([kmxFile isValid], @"Expected valid KMX file."); + KMXFile *kmxFile = [KeymanEngineTestsStaticHelperMethods getKmxFileTestMacEngine]; + XCTAssert(kmxFile != nil, @"Expected non-nil file"); + XCTAssert([kmxFile isValid], @"Expected valid KMX file."); } @end diff --git a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m index 65576e80d53..b431fd3412a 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4MacTests/KeymanEngineTestsStaticHelperMethods.m @@ -12,21 +12,21 @@ @implementation KeymanEngineTestsStaticHelperMethods + (KMXFile *)getKmxFileTestMacEngine { - NSString *path = [[NSBundle bundleForClass:[KeymanEngineTestsStaticHelperMethods class]] pathForResource:@"TestMacEngine.kmx" ofType:nil]; - KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:path]; - return kmxFile; + NSString *path = [[NSBundle bundleForClass:[KeymanEngineTestsStaticHelperMethods class]] pathForResource:@"TestMacEngine.kmx" ofType:nil]; + 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; + NSString *path = [[NSBundle bundleForClass:[KeymanEngineTestsStaticHelperMethods class]] pathForResource:@"PlatformTest.kmx" ofType:nil]; + KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:path]; + return kmxFile; } + (KMXFile *)getKmxFileForCipherMusicTests { - NSString *path = [[NSBundle bundleForClass:[KeymanEngineTestsStaticHelperMethods class]] pathForResource:@"CipherMusicUnicode.kmx" ofType:nil]; - KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:path]; - return kmxFile; + NSString *path = [[NSBundle bundleForClass:[KeymanEngineTestsStaticHelperMethods class]] pathForResource:@"CipherMusicUnicode.kmx" ofType:nil]; + KMXFile *kmxFile = [[KMXFile alloc] initWithFilePath:path]; + return kmxFile; } + (KMXFile *)getKmxFileForSilIpaTests {