diff --git a/HISTORY.md b/HISTORY.md index a99386923b..4f17258728 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,28 @@ # Keyman Version History +## 18.0.106 alpha 2024-09-06 + +* feat(windows): add right modifier included in hotkey optional functionality (#12259) +* fix(android): Skip language counts for lexical-model packages (#12361) +* docs(web): fix link to documentation page (#12369) + +## 18.0.105 alpha 2024-09-05 + +* chore(common): Fix missing entries in HISTORY.md (#12352) +* docs(android): Add in-app help for adjusting longpress delay (#12359) +* fix(mac): avoid crash on startup with macOS 10.15 (Catalina) (#12354) +* chore(oem/fv): Update to fv_all 13.0 (#12362) +* feat(windows): Add two new strings for SIL Global name instead of SIL International (#12327) + +## 18.0.104 alpha 2024-09-03 + +* fix(mac): display package info after keyboard installation (#12326) + +## 18.0.103 alpha 2024-09-02 + +* feat(windows): Remove hotkey related feature flags (#12252) +* feat(windows): update SIL logo for Windows UI (#12250) + ## 18.0.102 alpha 2024-08-30 * docs(web): add documentation comments for touch layout interfaces (#12314) @@ -20,7 +43,7 @@ * fix(android): Prioritize certain actions over multi-line for ENTER key (#12315) * fix(linux): add `keymanFacename` to .ldml file (#12277) * chore(common): Update crowdin strings for Czech (#12316) -* (#12313) +* fix(web): prevent unintuitive space-output blocking for mid-context suggestions (#12313) ## 18.0.100 alpha 2024-08-28 @@ -30,8 +53,8 @@ * feat(web): import the generator for the pred-text wordbreaker's Unicode-property data-table (#10690) * feat(web): optimize the wordbreaker data table for filesize and ease of first-load parsing (#10692) -* (#12297) -* (#12115) +* fix(web): fixes wordbreaker test import path (#12297) +* feat(web): enable utf8 charset encoding for the build artifacts (#12115) ## 18.0.98 alpha 2024-08-26 @@ -76,11 +99,11 @@ ## 18.0.93 alpha 2024-08-20 -* (#12188) +* refactor(web): remove engine/interfaces dependency on engine/js-processor (#12188) * fix(web): fix malformed reversion display strings (#12201) * feat(android): Add menu to specify long-press delay (#12170) * feat(android): Pass longpress delay to KeymanWeb (#12185) -* (#12223) +* fix(core): set mac build version for meson cli build to 10.13 (#12223) ## 18.0.92 alpha 2024-08-19 diff --git a/VERSION.md b/VERSION.md index 237f3b532e..f5c440f440 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -18.0.103 \ No newline at end of file +18.0.107 \ No newline at end of file diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java index 3806d5f4b8..161d966308 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java @@ -112,7 +112,8 @@ public class PackageActivity extends AppCompatActivity implements // Number of languages associated with the first keyboard in a keyboard package. // lexical-model packages will be 0 - final int languageCount = kmpProcessor.getLanguageCount(pkgInfo, PackageProcessor.PP_KEYBOARDS_KEY, 0); + final int languageCount = (keyboardCount > 0) ? + kmpProcessor.getLanguageCount(pkgInfo, PackageProcessor.PP_KEYBOARDS_KEY, 0) : 0; // Sanity check for keyboard packages if (pkgTarget.equals(PackageProcessor.PP_TARGET_KEYBOARDS)) { diff --git a/android/help/android_images/ic_timelapse.png b/android/help/android_images/ic_timelapse.png new file mode 100644 index 0000000000..9f948825b2 Binary files /dev/null and b/android/help/android_images/ic_timelapse.png differ diff --git a/android/help/android_images/longpress-slider.png b/android/help/android_images/longpress-slider.png new file mode 100644 index 0000000000..f1ab61f7b3 Binary files /dev/null and b/android/help/android_images/longpress-slider.png differ diff --git a/android/help/android_images/settings-screen-ap.png b/android/help/android_images/settings-screen-ap.png index ec85e24e81..f316fefd73 100644 Binary files a/android/help/android_images/settings-screen-ap.png and b/android/help/android_images/settings-screen-ap.png differ diff --git a/android/help/basic/config/adjust-longpress-delay.md b/android/help/basic/config/adjust-longpress-delay.md new file mode 100644 index 0000000000..0f3e740bdf --- /dev/null +++ b/android/help/basic/config/adjust-longpress-delay.md @@ -0,0 +1,13 @@ +--- +title: Adjust Longpress Delay - Keyman for Android Help +--- + +## Adjust Longpress Delay + +This menu is used to adjust the duration for triggering a longpress gesture. + +Drag the slider to set the delay between 0.3 seconds to 1.5 seconds. + +The default value is 0.5 seconds. + +![](../../android_images/longpress-slider.png) diff --git a/android/help/basic/config/index.md b/android/help/basic/config/index.md index 1c45d27508..92ac70afe5 100644 --- a/android/help/basic/config/index.md +++ b/android/help/basic/config/index.md @@ -44,6 +44,11 @@ Click on this to bring up the Android system configuration for setting Keyman as Click on this to [adjust the keyboard height](adjust-keyboard-height). +## Adjust longpress delay +![](../../android_images/ic_timelapse.png) + +Click on this to adjust the delay time for a longpress gesture. + ## Spacebar Caption Click on this to [change the displayed keyboard name](spacebar-caption) on the spacebar. diff --git a/common/windows/cpp/include/registry.h b/common/windows/cpp/include/registry.h index 56e8594078..2627d06522 100644 --- a/common/windows/cpp/include/registry.h +++ b/common/windows/cpp/include/registry.h @@ -110,7 +110,7 @@ #define REGSZ_KeyboardHotkeysAreToggle "hotkeys are toggles" #define REGSZ_DeadkeyConversionMode "deadkey conversion mode" // CU // I4552 #define REGSZ_ZapVirtualKeyCode "zap virtual key code" // LM, defaults to 0x0E (_VK_PREFIX_DEFAULT) -/* Non-chiral use of hotkeys instead of left-only hotkeys */ +/* Default is to only use left modifier in hotkeys trigger */ #define REGSZ_AllowRightModifierHotKey "allow right modifier for hotkey" diff --git a/common/windows/delphi/general/RegistryKeys.pas b/common/windows/delphi/general/RegistryKeys.pas index 1557de5865..e351b3860f 100644 --- a/common/windows/delphi/general/RegistryKeys.pas +++ b/common/windows/delphi/general/RegistryKeys.pas @@ -113,10 +113,11 @@ const SRegValue_ShowWelcome = 'show welcome'; // CU SRegValue_UseAdvancedInstall = 'use advanced install'; // CU - SRegValue_AltGrCtrlAlt = 'simulate altgr'; // CU - SRegValue_KeyboardHotKeysAreToggle = 'hotkeys are toggles'; // CU + SRegValue_AltGrCtrlAlt = 'simulate altgr'; // CU + SRegValue_KeyboardHotKeysAreToggle = 'hotkeys are toggles'; // CU + SRegValue_AllowRightModifierHotKey = 'allow right modifier for hotkey'; // CU SRegValue_ReleaseShiftKeysAfterKeyPress = 'release shift keys after key press'; // CU - SRegValue_TestKeymanFunctioning = 'test keyman functioning'; // CU, default true + SRegValue_TestKeymanFunctioning = 'test keyman functioning'; // CU, default true SRegValue_CreateStartMenuAsSubfolders = 'create start menu as subfolders'; // CU SRegValue_CreateUninstallEntries = 'create uninstall entries'; // CU diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m index efafbed11a..c99d632665 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m @@ -409,8 +409,8 @@ } - (void)removeAction:(id)sender { - NSButton *removeButton = (NSButton *)sender; - NSDictionary *info = [self.tableContents objectAtIndex:removeButton.tag]; + NSButton *deleteButton = (NSButton *)sender; + NSDictionary *info = [self.tableContents objectAtIndex:deleteButton.tag]; NSString *deleteKeyboardMessage = NSLocalizedString(@"message-confirm-delete-keyboard", nil); if ([info objectForKey:@"HeaderTitle"] != nil) @@ -418,10 +418,13 @@ 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])]; + [self.deleteAlertView beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) { + if (returnCode == NSAlertFirstButtonReturn) { + os_log_debug([KMLogs uiLog], "confirm delete keyboard alert dismissed"); + [self deleteFileAtIndex:[NSNumber numberWithInteger:deleteButton.tag]]; + } + self.deleteAlertView = nil; + }]; } - (IBAction)downloadAction:(id)sender { @@ -449,25 +452,30 @@ } - (void)handleRequestToInstallPackage:(KMPackage *) package { + os_log_debug([KMLogs dataLog], "handleRequestToInstallPackage"); NSString *keyboardInfoString = NSLocalizedString(@"info-install-keyboard-filename", nil); [self.confirmKmpInstallAlertView setInformativeText:[NSString localizedStringWithFormat:keyboardInfoString, package.getOrigKmpFilename]]; os_log_debug([KMLogs uiLog], "Asking user to confirm installation of %{public}@, KMP - temp file name: %{public}@", package.getOrigKmpFilename, package.getTempKmpFilename); - [self.confirmKmpInstallAlertView beginSheetModalForWindow:self.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:(__bridge void *)(package)]; + [self.confirmKmpInstallAlertView beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) { + os_log_debug([KMLogs uiLog], "confirm keyboard installation alert dismissed"); + if (returnCode == NSAlertFirstButtonReturn) { + [self installPackageFile: package.getTempKmpFilename]; + } + [package releaseTempKMPFile]; + self.confirmKmpInstallAlertView = nil; + }]; } - (void)installPackageFile:(NSString *)kmpFile { // kmpFile could be a temp file (in fact, it always is!), so don't display the name. - - os_log_debug([KMLogs dataLog], "KMP - Ready to unzip/install Package File: %{public}@", kmpFile); + os_log_debug([KMLogs dataLog], "kmpFile - ready to unzip/install Package File: %{public}@", kmpFile); BOOL didUnzip = [self.AppDelegate unzipFile:kmpFile]; if (!didUnzip) { + os_log_debug([KMLogs dataLog], "kmpFile, unzipFile failed"); NSAlert *failure = [[NSAlert alloc] init]; [failure addButtonWithTitle:NSLocalizedString(@"button-keyboard-file-unreadable", @"Alert button")]; @@ -476,13 +484,12 @@ [failure setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; [failure setAlertStyle:NSAlertStyleWarning]; - [failure beginSheetModalForWindow:self.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; + [failure beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) { + os_log_debug([KMLogs uiLog], "kmpFile, keyboard file unreadable alert dismissed with returnCode: %ld", (long)returnCode); + }]; } else { - os_log_debug([KMLogs dataLog], "Completed installation of KMP file."); + os_log_debug([KMLogs dataLog], "kmpFile, completed installation of KMP file"); } } @@ -558,28 +565,6 @@ return _confirmKmpInstallAlertView; } -- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { - os_log_debug([KMLogs uiLog], "User responded to NSAlert"); - if (alert == _deleteAlertView) { - if (returnCode == NSAlertFirstButtonReturn) { // Delete - [self deleteFileAtIndex:(__bridge NSNumber *)contextInfo]; - } - - _deleteAlertView = nil; - } - else if (alert == _confirmKmpInstallAlertView) { - KMPackage *package = (__bridge KMPackage *)contextInfo; - os_log_debug([KMLogs uiLog], "KMP - Temp file: %{public}@", package.getTempKmpFilename); - if (returnCode == NSAlertFirstButtonReturn) { // Install - [self installPackageFile: package.getTempKmpFilename]; - } - - [package releaseTempKMPFile]; - _confirmKmpInstallAlertView = nil; - } - // else, just a message - nothing to do. -} - - (void)deleteFileAtIndex:(NSNumber *) n { NSInteger index = [n integerValue]; NSString *path2Remove = nil; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m index 6be446ddd2..32a8377b64 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m @@ -85,8 +85,6 @@ // 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 = @"" diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index 26ecc717ef..78c6362de9 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -983,6 +983,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef return _configWindow; } +// TODO: rewrite confusing pattern, multiple methods differing only by underscore - (NSWindowController *)aboutWindow_ { return _aboutWindow; } @@ -1065,14 +1066,19 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef * TODO: this should really be refactored */ -- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { - NSButton *button = (NSButton *)[alert.buttons objectAtIndex:0]; - if (button.tag == -1) { +- (void)downloadComplete:(NSModalResponse) returnCode { + os_log_debug([KMLogs uiLog], "downloadComplete, NSModalResponse returnCode: %ld", (long)returnCode); + if (returnCode == NSModalResponseCancel) { + os_log_debug([KMLogs uiLog], "downloadComplete, returnCode == NSModalResponseCancel"); [_connection cancel]; } - else if (button.tag == 1) { + else if (returnCode == NSModalResponseOK) { + os_log_debug([KMLogs uiLog], "downloadComplete, returnCode == NSModalResponseOK"); + [_downloadKBWindow close]; + if (self.configWindow.window != nil) { + os_log_debug([KMLogs uiLog], "downloadComplete, 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]; @@ -1081,6 +1087,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [self.infoWindow.window makeKeyAndOrderFront:nil]; } else { + os_log_debug([KMLogs uiLog], "downloadComplete, self.configWindow.window == nil"); [self.infoWindow.window centerInParent]; [self.infoWindow.window makeKeyAndOrderFront:nil]; [self.infoWindow.window setLevel:NSFloatingWindowLevel]; @@ -1098,6 +1105,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (NSAlert *)downloadInfoView { + os_log_debug([KMLogs uiLog], "downloadInfoView"); if (_downloadInfoView == nil) { _downloadInfoView = [[NSAlert alloc] init]; [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)]; @@ -1111,6 +1119,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (NSProgressIndicator *)progressIndicator { + os_log_debug([KMLogs uiLog], "progressIndicator"); if (_progressIndicator == nil) { _progressIndicator = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0, 0, 300, 20)]; [_progressIndicator setIndeterminate:NO]; @@ -1130,38 +1139,51 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [self downloadKeyboardFromURL:url]; } + - (void)downloadKeyboardFromURL:(NSURL *)url { NSURL* downloadUrl = url; - + os_log_debug([KMLogs uiLog], "downloadKeyboardFromURL, url.path: %{public}@", url.path); + if (downloadUrl && _downloadFilename) { if (_infoWindow.window != nil) [_infoWindow close]; [self.downloadInfoView setInformativeText:self.downloadFilename]; + if (self.configWindow.window != nil) { + os_log_debug([KMLogs uiLog], "downloadKeyboardFromURL, 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]; + + /* + Open sheet off of config window, not the download window. + This is because, if the download is successful, + the download window will be closed by the sheet. + */ + [self.downloadInfoView beginSheetModalForWindow:self.configWindow.window completionHandler:^(NSModalResponse returnCode) { + [self downloadComplete:returnCode]; + }]; } else { + os_log_debug([KMLogs uiLog], "downloadKeyboardFromURL, self.configWindow.window == nil"); [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]; + /* + Open sheet off of config window, same as above. + */ + [self.downloadInfoView beginSheetModalForWindow:self.configWindow.window completionHandler:^(NSModalResponse returnCode) { + [self downloadComplete:returnCode]; + }]; } if (_connection == nil) { - [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)]; + os_log_debug([KMLogs uiLog], "downloadKeyboardFromURL, _connection == nil, set button title cancel downloading, tag = -1"); + [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)]; NSButton *button = (NSButton *)[_downloadInfoView.buttons objectAtIndex:0]; [button setTitle:NSLocalizedString(@"button-cancel-downloading", nil)]; [button setTag:-1]; @@ -1170,7 +1192,6 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef _receivedData = [[NSMutableData alloc] initWithLength:0]; _connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; } - } } @@ -1203,6 +1224,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { + os_log_debug([KMLogs uiLog], "connectionDidFinishLoading"); NSString *filePath = [self.keyboardsPath stringByAppendingPathComponent:self.downloadFilename]; [self.receivedData writeToFile:filePath atomically:YES]; [self unzipFile:filePath]; @@ -1210,6 +1232,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-download-complete", nil)]; NSButton *button = (NSButton *)[_downloadInfoView.buttons objectAtIndex:0]; + os_log_debug([KMLogs uiLog], "connectionDidFinishLoading, set button title download complete, tag = 1"); [button setTitle:NSLocalizedString(@"button-download-complete", nil)]; [button setTag:1]; [[NSNotificationCenter defaultCenter] postNotificationName:kKeymanKeyboardDownloadCompletedNotification @@ -1276,6 +1299,7 @@ extern const CGKeyCode kProcessPendingBuffer; NSError *error = nil; NSString *fileName = filePath.lastPathComponent; NSString *folderName = [fileName stringByDeletingPathExtension]; + os_log_debug([KMLogs keyboardLog], "unzipFile, folderName: %{public}@, fileName: %{public}@", folderName, fileName); // First we unzip into a temp folder, and check kmp.json for the fileVersion diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m index c557a4deaf..12c0b3c564 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m @@ -239,14 +239,12 @@ typedef enum { NSString *s = [line substringFromIndex:kName.length+1]; NSArray *vs = [s componentsSeparatedByString:@"\","]; 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]]) { @@ -261,14 +259,12 @@ typedef enum { 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; } @@ -282,20 +278,17 @@ typedef enum { NSString *s = [line substringFromIndex:x+2]; if ([[s lowercaseString] hasPrefix:[kFile lowercaseString]]) { NSArray *vs = [s componentsSeparatedByString:@"\","]; - NSString *v1 = [[[vs objectAtIndex:0] substringFromIndex:kFile.length+1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; NSString *fileName = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; [files addObject:fileName]; } else if ([[s lowercaseString] hasPrefix:[kFont lowercaseString]]) { NSArray *vs = [s componentsSeparatedByString:@"\","]; NSString *fontName = [[[vs objectAtIndex:0] substringFromIndex:kFont.length+1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *fontFileName = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; [fontArray addObject:fontName]; } else if ([[s lowercaseString] hasPrefix:[kKeyboard lowercaseString]]) { NSArray *vs = [s componentsSeparatedByString:@"\","]; NSString *keyboardName = [[[vs objectAtIndex:0] substringFromIndex:kKeyboard.length+1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *keyboardFileName = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; KMKeyboardInfoBuilder *builder = [[KMKeyboardInfoBuilder alloc] init]; builder.name = keyboardName; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h index 5a7f920c9f..8d7b114f2b 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.h @@ -1,4 +1,4 @@ -/** +/* * Keyman is copyright (C) SIL International. MIT License. * * KMSettingsRepository.h diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m index d8cca25f94..bbd87a40ec 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMSettingsRepository.m @@ -251,7 +251,6 @@ NSInteger const kCurrentDataModelVersionNumber = kVersionStoreDataInLibraryDirec } - (void)convertActiveKeyboardArrayForMigration { - NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; NSMutableArray *keyboards = [self activeKeyboards]; NSMutableArray *convertedActiveKeyboards = [[NSMutableArray alloc] initWithCapacity:0]; BOOL didConvert = NO; @@ -269,9 +268,9 @@ NSInteger const kCurrentDataModelVersionNumber = kVersionStoreDataInLibraryDirec } } - // only update array in UserDefaults if we actually converted something + // only write array to UserDefaults if we actually converted something if (didConvert) { - [[NSUserDefaults standardUserDefaults] setObject:convertedActiveKeyboards forKey:kActiveKeyboardsKey]; + [self writeActiveKeyboards:convertedActiveKeyboards]; } } diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m b/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m index 417475c777..dc73edc11b 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m @@ -1,9 +1,6 @@ /** * Keyman is copyright (C) SIL International. MIT License. * - * KeySender.m - * Keyman - * * Created by Shawn Schantz on 2023-04-17. * * Sends keydown events for the provided keycode to the frontmost application. @@ -56,15 +53,13 @@ const CGKeyCode kKeymanEventKeyCode = 0xFF; } /** - sendKeymanKeyCodeForEvent sends the kKeymanEventKeyCode to the - frontmost application to indicate that all the backspaces have been processed - and we can insert the queuedText to the client + * sendKeymanKeyCodeForEvent sends the kKeymanEventKeyCode to the + * frontmost application to indicate that all the backspaces have been processed + * and we can insert the queuedText to the client */ - (void)sendKeymanKeyCodeForEvent:(NSEvent *)event { os_log_debug([KMLogs keyLog], "KeySender sendKeymanKeyCodeForEvent"); - - ProcessSerialNumber psn; // Returns the frontmost app, which is the app that receives key events. NSRunningApplication *app = NSWorkspace.sharedWorkspace.frontmostApplication; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m b/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m index 057f401cbe..89e6338852 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m @@ -1,4 +1,4 @@ -/** +/* * Keyman is copyright (C) SIL International. MIT License. * * PrivacyConsent.m @@ -7,8 +7,8 @@ * Created by Shawn Schantz on 2022-09-22. * * Used to determine if the user has provided consent to the services it needs - * and, if not, to request that consent. For versions of macOS prior to 10.15, - * Keyman requires Accessibility access. For 10.15 and later, Keyman requires + * and, if not, to request that consent. For versions of macOS prior to 11.0, + * Keyman requires Accessibility access. For 11.0 and later, Keyman requires * PostEvent access. Both are presented to the user as a need for Accessibility * when prompted by the system and are listed under Accessibility in the Privacy * tab in System Preferences, Security & Privacy. Both Accessibility and @@ -16,7 +16,11 @@ * that access is not explicitly needed as long as one of the others is provided * first. * - * Access this functionality through the shared instance. Call + * Note that Apple's documentation states that the PostEvent access APIs are + * available with macOS 10.15 (Catalina) but testing showed that it was only + * available with macOS 11.0 (Big Sur). This is documented with issue #12295. + * + * To access this functionality, used the shared instance. Call * requestPrivacyAccess which will check whether access has been granted. If * not, then a dialog will be presented to the user to inform them that * Accessibility is required. Dismissing this dialog will trigger the API call @@ -24,7 +28,7 @@ * only happen once. If the user was prompted earlier and did not grant access, * they can still go to System Preferences and enable it there. So it is useful * to prompt with a dialog from Keyman at startup. Without Accessibility, the - * shift layer and the OSK do not work -- so Keyman is basically useless. + * shift layer and the OSK do not work. */ #import "PrivacyConsent.h" @@ -43,7 +47,7 @@ } /** - * For macOS earlier than 10.15: check for Accessibility access. + * For macOS earlier than 11.0: check for Accessibility access. */ - (BOOL)checkAccessibility { @@ -66,7 +70,7 @@ BOOL hasAccessibility = NO; // check if we already have accessibility - if (@available(macOS 10.15, *)) { + if (@available(macOS 11.0, *)) { hasAccessibility = [self checkPostEventAccess]; } else { hasAccessibility = [self checkAccessibility]; @@ -85,7 +89,7 @@ } /** - * For macOS earlier than 10.15: request Accessibility access. + * For macOS earlier than 11.0: request Accessibility access. */ - (void)requestAccessibility { @@ -113,18 +117,18 @@ */ - (void)configureDialogForOsVersion { - if (@available(macOS 10.15, *)) { - [self configureDialogForCatalinaAndLater]; + if (@available(macOS 11.0, *)) { + [self configureDialogForBigSurAndLater]; } else { - [self configureDialogForPreCatalina]; + [self configureDialogForPreBigSur]; } } /** - * Initialize privacy dialog for macOS versions prior to Catalina (10.15). + * Initialize privacy dialog for macOS versions prior to Big Sur (11.0). * In this case, request Accessibility access, not PostEvent. */ -- (void)configureDialogForPreCatalina { +- (void)configureDialogForPreBigSur { void (^consentPrompt)(void) = ^(void) { [self requestAccessibility]; @@ -136,10 +140,10 @@ } /** - * Initialize privacy dialog for macOS versions of Catalina (10.15) or later. + * Initialize privacy dialog for macOS versions of Big Sur (11.0) or later. * In this case, request PostEvent access, not Accessibility. */ -- (void)configureDialogForCatalinaAndLater { +- (void)configureDialogForBigSurAndLater { void (^consentPrompt)(void) = ^(void) { [self requestPostEventAccess]; @@ -160,7 +164,7 @@ /** * Check whether the user has allowed ListenEvent access. - * Only available with macOS Catalina (10.15) or later. + * Only available with macOS Big Sur (11.0) or later. * * If user has granted Accessibility or PostEvent access, then * ListenEvent access is also granted. @@ -170,18 +174,18 @@ BOOL hasAccess = NO; // below checks for ListenEvent access - if (@available(macOS 10.15, *)) { + if (@available(macOS 11.0, *)) { hasAccess = CGPreflightListenEventAccess(); os_log([KMLogs privacyLog], "CGPreflightListenEventAccess() returned %@", hasAccess ? @"YES" : @"NO"); } else { - os_log([KMLogs privacyLog], "CGPreflightListenEventAccess not available before macOS version 10.15"); + os_log([KMLogs privacyLog], "CGPreflightListenEventAccess not available before macOS version 11.0"); } return hasAccess; } /** * Check whether the user has allowed PostEvent access. - * Only available with macOS Catalina (10.15) or later. + * Only available with macOS Big Sur (11.0) or later. * * If user has granted Accessibility, then PostEvent access is also granted. */ @@ -190,46 +194,46 @@ BOOL hasAccess = NO; // below checks for PostEvent access - if (@available(macOS 10.15, *)) { + if (@available(macOS 11.0, *)) { hasAccess = CGPreflightPostEventAccess(); os_log([KMLogs privacyLog], "CGPreflightPostEventAccess() returned %@", hasAccess ? @"YES" : @"NO"); } else { - os_log([KMLogs privacyLog], "CGPreflightPostEventAccess not available before macOS version 10.15"); + os_log([KMLogs privacyLog], "CGPreflightPostEventAccess not available before macOS version 11.0"); } return hasAccess; } /** * Request ListenEvent access. - * Only available with macOS Catalina (10.15) or later. + * Only available with macOS Big Sur (11.0) or later. */ - (BOOL)requestListenEventAccess { BOOL granted = NO; - if (@available(macOS 10.15, *)) { + if (@available(macOS 11.0, *)) { granted = CGRequestListenEventAccess(); os_log([KMLogs privacyLog], "CGRequestListenEventAccess() returned %@", granted ? @"YES" : @"NO"); } else { - os_log([KMLogs privacyLog], "CGRequestListenEventAccess not available before macOS version 10.15"); + os_log([KMLogs privacyLog], "CGRequestListenEventAccess not available before macOS version 11.0"); } return granted; } /** * Request PostEvent access. - * Only available with macOS Catalina (10.15) or later. + * Only available with macOS Big Sur (11.0) or later. */ - (BOOL)requestPostEventAccess { BOOL granted = NO; - if (@available(macOS 10.15, *)) { + if (@available(macOS 11.0, *)) { granted = CGRequestPostEventAccess(); os_log([KMLogs privacyLog], "CGRequestPostEventAccess() returned %@", granted ? @"YES" : @"NO"); } else { - os_log([KMLogs privacyLog], "CGRequestPostEventAccess not available before macOS version 10.15"); + os_log([KMLogs privacyLog], "CGRequestPostEventAccess not available before macOS version 11.0"); } return granted; } diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m index c1dfa75a87..5b31cf8ffa 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m @@ -41,7 +41,10 @@ static CGFloat const kRelativeModifierLabelHeight = 0.30f; - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; if (self) { - os_log_debug([KMELogs oskLog], "KeyView initWithFrame: %{public}@, bounds: %{public}@, default clipsToBounds %{public}@", NSStringFromRect(frame), NSStringFromRect(self.bounds), self.clipsToBounds?@"YES":@"NO"); + /* + // usually too much logging, uncomment for debugging + os_log_debug([KMELogs oskLog], "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; @@ -70,7 +73,10 @@ static CGFloat const kRelativeModifierLabelHeight = 0.30f; } - (void)drawRect:(NSRect)rect { + /* + // usually too much logging, uncomment for debugging os_log_debug([KMELogs uiLog], "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); diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m index d81097d3e2..b1144a17fa 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m @@ -14,7 +14,10 @@ - (id)initWithKeyCode:(NSUInteger)keyCode caption:(NSString *)caption scale:(CGFloat)scale { self = [super init]; if (self) { - os_log_debug([KMELogs oskLog], "OSKKey initWithKeyCode: 0x%lx, caption: %{public}@, scale: %f", keyCode, caption, scale); + /* + // usually too much logging, uncomment for debugging + os_log_debug([KMELogs oskLog], "OSKKey initWithKeyCode: 0x%lx, caption: %{public}@, scale: %f", keyCode, caption, scale); + */ _keyCode = keyCode; if (caption == nil) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m index f5154fa76d..512920e052 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m @@ -43,7 +43,7 @@ } - (void)drawRect:(NSRect)rect { - os_log_debug([KMELogs uiLog], "OSKView drawRect: %{public}@", NSStringFromRect(rect)); + os_log_debug([KMELogs oskLog], "OSKView drawRect: %{public}@", NSStringFromRect(rect)); CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; CGContextSetLineJoin(context, kCGLineJoinRound); diff --git a/oem/firstvoices/keyboards.csv b/oem/firstvoices/keyboards.csv index 22812ec14d..d1f1b92180 100644 --- a/oem/firstvoices/keyboards.csv +++ b/oem/firstvoices/keyboards.csv @@ -12,40 +12,40 @@ fv,fv_dexwlesucid,Dəxʷləšucid,BC Coast,fv_dexwlesucid_kmw-9.0.js,9.2.1,lut-L fv,fv_diitiidatx,Diidiitidq,BC Coast,fv_diitiidatx_kmw-9.0.js,9.2.1,nuk-Latn,Nuu-chah-nulth (Latin) fv,fv_gitsenimx,Gitsenimx̱,BC Coast,fv_gitsenimx_kmw-9.0.js,10.1.2,git,Gitxsan (Latin) fv,fv_hailzaqvla,Haiɫzaqvla,BC Coast,fv_hailzaqvla_kmw-9.0.js,9.5.2,hei,Heiltsuk (Latin) -fv,fv_haisla,Haisla,BC Coast,fv_haisla.js,2.1.2,has-Latn,Haisla (Latin) -fv,fv_halqemeylem,Halq'eméylem,BC Coast,fv_halqemeylem_kmw-9.0.js,9.2,hur-Latn,Halkomelem (Latin) -fv,fv_henqeminem,Hǝn̓q̓ǝmin̓ǝm,BC Coast,fv_henqeminem_kmw-9.0.js,10.1,hur-Latn,Halkomelem (Latin) -fv,fv_klahoose,Homalco-Klahoose-Sliammon,BC Coast,fv_klahoose_kmw-9.0.js,10.1,coo,Comox -fv,fv_hulquminum,Hul’q’umi’num’,BC Coast,fv_hulquminum_kmw-9.0.js,9.1,hur-Latn,Halkomelem (Latin) +fv,fv_haisla,Haisla,BC Coast,fv_haisla.js,2.1.3,has-Latn,Haisla (Latin) +fv,fv_halqemeylem,Halq'eméylem,BC Coast,fv_halqemeylem_kmw-9.0.js,9.2.1,hur-Latn,Halkomelem (Latin) +fv,fv_henqeminem,Hǝn̓q̓ǝmin̓ǝm,BC Coast,fv_henqeminem_kmw-9.0.js,10.2.1,hur-Latn,Halkomelem (Latin) +fv,fv_klahoose,Homalco-Klahoose-Sliammon,BC Coast,fv_klahoose_kmw-9.0.js,10.2,coo,Comox +fv,fv_hulquminum,Hul’q’umi’num’,BC Coast,fv_hulquminum_kmw-9.0.js,9.1,hur,Halkomelem fv,fv_hulquminum_combine,Hul̓q̓umin̓um̓,BC Coast,fv_hulquminum_combine_kmw-9.0.js,2.0.1,hur-Latn,Halkomelem (Latin) fv,fv_kwakwala_liqwala,Kʷak̓ʷala,BC Coast,fv_kwakwala_liqwala_kmw-9.0.js,9.3,kwk-Latn,Kwakiutl (Latin) fv,fv_kwakwala,Kwak̕wala,BC Coast,fv_kwakwala_kmw-9.0.js,9.2,kwk-Latn,Kwakiutl (Latin) -fv,fv_lekwungen,Lək̓ʷəŋən,BC Coast,fv_lekwungen-9.0.js,1.0,str,Lekwungen -fv,fv_nexwslayemucen,Nəxʷsƛ̓ay̓əmúcən,BC Coast,fv_nexwslayemucen_kmw-9.0.js,10.0,clm-Latn,Clallam (Latin) -fv,fv_nisgaa,Nisg̱a'a,BC Coast,fv_nisgaa_kmw-9.0.js,9.2,ncg-Latn,Nisga'a (Latin) +fv,fv_lekwungen,Lekwungen (Lək̓ʷəŋən),BC Coast,fv_lekwungen_kmw-9.0.js,1.0.1,str,Straits Salish +fv,fv_nexwslayemucen,Nəxʷsƛ̓ay̓əmúcən,BC Coast,fv_nexwslayemucen_kmw-9.0.js,11.0,clm,Clallam +fv,fv_nisgaa,Nisg̱a'a,BC Coast,fv_nisgaa_kmw-9.0.js,9.2.1,ncg-Latn,Nisga'a (Latin) fv,fv_nuucaanul,Nuučaan̓uł,BC Coast,fv_nuucaanul_kmw-9.0.js,9.2,nuk-Latn,Nuu-chah-nulth (Latin) fv,fv_nuxalk,Nuxalk,BC Coast,fv_nuxalk_kmw-9.0.js,10.0.1,blc-Latn,Bella Coola (Latin) -fv,fv_sencoten,SENĆOŦEN,BC Coast,fv_sencoten_kmw-9.0.js,9.2.2,str,Straits Salish +fv,fv_sencoten,SENĆOŦEN,BC Coast,fv_sencoten_kmw-9.0.js,9.2.3,str,Straits Salish fv,fv_sguuxs,Sgüüx̱s,BC Coast,fv_sguuxs.js,1.1,tsi,Tsimshian -fv,fv_shashishalhem,Shashishalhem,BC Coast,fv_shashishalhem_kmw-9.0.js,9.2,sec-Latn,Sechelt (Latin) +fv,fv_shashishalhem,Shashishalhem,BC Coast,fv_shashishalhem_kmw-9.0.js,9.2.1,sec-Latn,Sechelt (Latin) fv,fv_skwxwumesh_snichim,Sḵwx̱wúmesh sníchim,BC Coast,fv_skwxwumesh_snichim_kmw-9.0.js,10.0,squ-Latn,Squamish (Latin) -fv,fv_smalgyax,Sm'algya̱x,BC Coast,fv_smalgyax_kmw-9.0.js,9.2,tsi-Latn,Tsimshian (Latin) +fv,fv_smalgyax,Sm'algya̱x,BC Coast,fv_smalgyax_kmw-9.0.js,9.3,tsi-Latn,Tsimshian (Latin) fv,fv_xaislakala,X̄a'ʼislak̓ala,BC Coast,fv_xaislakala_kmw-9.0.js,10.0,has-Latn,Haisla (Latin) fv,fv_hlgaagilda_xaayda_kil,X̱aayda-X̱aad Kil,BC Coast,fv_hlgaagilda_xaayda_kil_kmw-9.0.js,9.4,hax,Southern Haida fv,fv_dakelh,Dakelh,BC Interior,fv_dakelh_kmw-9.0.js,9.2.1,caf-Latn,Southern Carrier (Latin) fv,fv_ktunaxa,Ktunaxa,BC Interior,fv_ktunaxa_kmw-9.0.js,10.0,kut-Latn,Kutenai (Latin) fv,fv_kwadacha_tsekene,Kwadacha Tsek’ene,BC Interior,fv_kwadacha_tsekene_kmw-9.0.js,1.1,sek-Latn,Sekani -fv,fv_natwits,Nedut’en-Witsuwit'en,BC Interior,fv_natwits_kmw-9.0.js,9.1.3,caf-Latn,Southern Carrier (Latin) +fv,fv_natwits,Nedut’en-Witsuwit'en,BC Interior,fv_natwits_kmw-9.0.js,9.2,caf-Latn,Southern Carrier (Latin) fv,fv_nlekepmxcin,Nłeʔkepmxcin,BC Interior,fv_nlekepmxcin_kmw-9.0.js,9.5.1,thp-Latn,Thompson (Latin) -fv,fv_nlha7kapmxtsin,Nlha7kapmxtsin,BC Interior,fv_nlha7kapmxtsin_kmw-9.0.js,10.1.1,thp-Latn,Thompson (Latin) +fv,fv_nlha7kapmxtsin,Nlha7kapmxtsin,BC Interior,fv_nlha7kapmxtsin_kmw-9.0.js,10.1.2,thp,Thompson fv,fv_nlakapamuxcheen,Nlakapamuxcheen,BC Interior,fv_nlakapamuxcheen_kmw-9.0.js,1.1,thp,Thompson -fv,fv_nsilxcen,Nsilxcən,BC Interior,fv_nsilxcen_kmw-9.0.js,10.0,oka,Okanagan -fv,fv_secwepemctsin,Secwepemctsín,BC Interior,fv_secwepemctsin_kmw-9.0.js,9.2,shs-Latn,Shuswap (Latin) -fv,fv_stlatlimxec,Sƛ̓aƛ̓imxəc,BC Interior,fv_stlatlimxec_kmw-9.0.js,9.3,lil-Latn,Lillooet (Latin) +fv,fv_nsilxcen,Nsilxcən,BC Interior,fv_nsilxcen_kmw-9.0.js,10.0.1,oka,Okanagan +fv,fv_secwepemctsin,Secwepemctsín,BC Interior,fv_secwepemctsin_kmw-9.0.js,9.3,shs,Shuswap +fv,fv_stlatlimxec,Sƛ̓aƛ̓imxəc,BC Interior,fv_stlatlimxec_kmw-9.0.js,9.4,lil-Latn,Lillooet (Latin) fv,fv_statimcets,St̓át̓imcets,BC Interior,fv_statimcets_kmw-9.0.js,9.2,lil-Latn,Lillooet (Latin) fv,fv_taltan,Tāłtān,BC Interior,fv_taltan_kmw-9.0.js,9.2,tht-Latn,Tahltan (Latin) fv,fv_tsekehne,Tsek'ehne,BC Interior,fv_tsekehne_kmw-9.0.js,9.2,sek-Latn,Sekani (Latin) -fv,fv_tsilhqotin,Tŝilhqot'in,BC Interior,fv_tsilhqotin_kmw-9.0.js,9.2,clc-Latn,Chilcotin (Latin) +fv,fv_tsilhqotin,Tŝilhqot'in,BC Interior,fv_tsilhqotin_kmw-9.0.js,9.3,clc-Latn,Chilcotin (Latin) fv,fv_southern_carrier,ᑐᑊᘁᗕᑋᗸ (Southern Carrier),BC Interior,fv_southern_carrier_kmw-9.0.js,10.1,caf-Cans,Southern Carrier (Unified Canadian Aboriginal Syllabics) fv,fv_anicinapemi8in,Anicinapemi8in/Anishinàbemiwin,Eastern Subarctic,fv_anicinapemi8in_kmw-9.0.js,9.1.1,alq-Latn,Algonquin (Latin) fv,fv_atikamekw,Atikamekw,Eastern Subarctic,fv_atikamekw_kmw-9.0.js,9.1.1,atj-Latn,Atikamekw (Latin) @@ -53,16 +53,16 @@ fv,fv_ilnu_innu_aimun,Ilnu-Innu Aimun,Eastern Subarctic,fv_ilnu_innu_aimun_kmw-9 fv,fv_swampy_cree,ᐃᓂᓂᒧᐎᐣ (Swampy Cree),Eastern Subarctic,fv_swampy_cree_kmw-9.0.js,9.2.1,csw-Cans,Swampy Cree (Unified Canadian Aboriginal Syllabics) fv,fv_moose_cree,ᐃᓕᓖᒧᐎᓐ (Moose Cree),Eastern Subarctic,fv_moose_cree_kmw-9.0.js,9.2.1,crm-Cans,Moose Cree (Unified Canadian Aboriginal Syllabics) fv,fv_northern_east_cree,ᐄᔨᔫ-ᐄᓅ ᐊᔨᒨᓐ (Northern East Cree),Eastern Subarctic,fv_northern_east_cree_kmw-9.0.js,9.2.1,crl-Cans,Northern East Cree (Unified Canadian Aboriginal Syllabics) -fv,fv_severn_ojibwa,ᐊᓂᔑᓂᓂᒧᐎᐣ (Severn Ojibwa),Eastern Subarctic,fv_severn_ojibwa_kmw-9.0.js,10.1,ojs-Cans,Severn Ojibwa (Unified Canadian Aboriginal Syllabics) -fv,fv_severn_ojibwa_rdot,ᐊᓂᔑᓂᓂᒧᐏᐣ (Severn Ojibwa right w-dot),Eastern Subarctic,fv_severn_ojibwa_kmw-9.0.js,1.1,ojs,Oji-Cree +fv,fv_severn_ojibwa,ᐊᓂᔑᓂᓂᒧᐎᐣ (Severn Ojibwa),Eastern Subarctic,fv_severn_ojibwa_kmw-9.0.js,10.1.1,ojs-Cans,Severn Ojibwa (Unified Canadian Aboriginal Syllabics) +fv,fv_severn_ojibwa_rdot,ᐊᓂᔑᓂᓂᒧᐏᐣ (Severn Ojibwa right w-dot),Eastern Subarctic,fv_severn_ojibwa_kmw-9.0.js,1.1.1,ojs,Oji-Cree fv,fv_ojibwa,ᐊᓂᔑᓇᐯᒧᐎᓐ (a-finals),Eastern Subarctic,fv_ojibwa_kmw-9.0.js,10.1,ojb-Cans,Northwestern Ojibwa (Unified Canadian Aboriginal Syllabics) -fv,fv_ojibwa_rdot,ᐁᓂᔑᓇᐯᒧᐏᓐ (a-finals right w-dot),Eastern Subarctic,fv_ojibwa_rdot_kmw-9.0.js,1.0.2,oj,Ojibwa -fv,fv_ojibwa_ifinal,ᐊᓂᔑᓇᐯᒧᐎᣙ (i-finals),Eastern Subarctic,fv_ojibwa_ifinal_kmw-9.0.js,1.0.1,oj,Ojibwa -fv,fv_ojibwa_ifinal_rdot,ᐊᓂᔑᓇᐯᒧᐏᣙ (i-finals right w-dot),Eastern Subarctic,fv_ojibwa_ifinal_rdot_kmw-9.0.js,1.0.1,oj,Ojibwa +fv,fv_ojibwa_rdot,ᐁᓂᔑᓇᐯᒧᐏᓐ (a-finals right w-dot),Eastern Subarctic,fv_ojibwa_rdot_kmw-9.0.js,1.0.3,oj,Ojibwa +fv,fv_ojibwa_ifinal,ᐊᓂᔑᓇᐯᒧᐎᣙ (i-finals),Eastern Subarctic,fv_ojibwa_ifinal_kmw-9.0.js,1.0.2,oj,Ojibwa +fv,fv_ojibwa_ifinal_rdot,ᐊᓂᔑᓇᐯᒧᐏᣙ (i-finals right w-dot),Eastern Subarctic,fv_ojibwa_ifinal_rdot_kmw-9.0.js,1.0.2,oj,Ojibwa fv,fv_naskapi,ᓇᔅᑲᐱ (Naskapi),Eastern Subarctic,fv_naskapi_kmw-9.0.js,9.3.1,nsk-Cans,Naskapi (Unified Canadian Aboriginal Syllabics) sil,sil_euro_latin,English,European,european2-1.6.js,3.0.2,en,English basic,basic_kbdcan,Français,European,canadian_french-1.0.js,1.1.1,fr-CA,French (Canada) -fv,fv_anishinaabemowin,Anishinaabemowin,Great Lakes - St. Lawrence,fv_anishinaabemowin_kmw-9.0.js,10.1,oj,Ojibwa +fv,fv_anishinaabemowin,Anishinaabemowin,Great Lakes - St. Lawrence,fv_anishinaabemowin_kmw-9.0.js,10.2,oj,Ojibwa fv,fv_bodewadminwen,Bodéwadminwen-Nishnabémwen,Great Lakes - St. Lawrence,fv_bodewadminwen_kmw-9.0.js,9.1.1,pot-Latn,Potawatomi (Latin) fv,fv_goyogohono,Goyogo̱hó:nǫ',Great Lakes - St. Lawrence,fv_goyogohono_kmw-9.0.js,9.2.1,cay-Latn,Cayuga (Latin) fv,fv_kanienkeha_e,Kanien'kéha-Kanyen'kéha,Great Lakes - St. Lawrence,fv_kanienkeha_e_kmw-9.0.js,9.1.3,moh-Latn,Mohawk (Latin) @@ -85,7 +85,7 @@ fv,fv_nakoda,Nakoda,Prairies,fv_nakoda_kmw-9.0.js,9.1.1,asb-Latn,Assiniboine (La fv,fv_tsuutina,Tsúùt'ínà,Prairies,fv_tsuutina_kmw-9.0.js,9.1.1,srs-Latn,Sarsi (Latin) fv,fv_plains_cree,ᓀᐦᐃᔭᐍᐏᐣ (Plains Cree),Prairies,fv_plains_cree_kmw-9.0.js,11.1,crk-Cans,ᓀᐦᐃᔭᐍᐏᐣ (Cree syllabics) fv,fv_dine_bizaad,Diné Bizaad,South West,fv_dine_bizaad_kmw-9.0.js,9.1.1,nv-Latn,Navajo (Latin) -fv,fv_dane_zaa_zaage,Dane-Z̲aa Z̲áágéʔ,Western Subarctic,fv_dane_zaa_zaage_kmw-9.0.js,9.4,bea,Beaver +fv,fv_dane_zaa_zaage,Dane-Z̲aa Z̲áágéʔ,Western Subarctic,fv_dane_zaa_zaage_kmw-9.0.js,9.4.1,bea,Beaver fv,fv_dene_dzage,Dene Dzage,Western Subarctic,fv_dene_dzage_kmw-9.0.js,11.0.1,kkz-Latn,Kaska (Latin) fv,fv_dene_zhatie,Dene Zhatié,Western Subarctic,fv_dene_zhatie_kmw-9.0.js,10.2.1,den,Dene Zhatıé fv,fv_denesuline_epsilon,Dënesųłıné,Western Subarctic,fv_denesuline_epsilon_kmw-9.0.js,10.0.1,chp,Chipewyan @@ -100,7 +100,7 @@ fv,fv_northern_tutchone,Northern Tutchone,Western Subarctic,fv_northern_tutchone fv,fv_sahugotine_yati,Sahtúgot'ı̨nę́ Yatı̨́,Western Subarctic,fv_sahugotine_yati_kmw-9.0.js,9.1.1,scs-Latn,North Slavey (Latin) fv,fv_shihgotine_yati,Shıhgot'ı̨nę́ Yatı̨́,Western Subarctic,fv_shihgotine_yati_kmw-9.0.js,9.1.1,scs-Latn,North Slavey (Latin) fv,fv_southern_tutchone,Southern Tutchone,Western Subarctic,fv_southern_tutchone_kmw-9.0.js,9.3,tce-Latn,Southern Tutchone (Latin) -fv,fv_tagizi_dene,Tāgizi Dene,Western Subarctic,fv_tagizi_dene_kmw-9.0.js,9.3,tgx-Latn,Tagish (Latin) +fv,fv_tagizi_dene,Tāgizi Dene,Western Subarctic,fv_tagizi_dene_kmw-9.0.js,9.4,tgx-Latn,Tagish (Latin) fv,fv_tlicho_yatii,Tłı̨chǫ Yatıı̀,Western Subarctic,fv_tlicho_yatii_kmw-9.0.js,9.1.1,dgr-Latn,Dogrib (Latin) fv,fv_dene_mb,ᑌᓀ ᔭᕠᐁ (Dene MB),Western Subarctic,fv_dene_mb_kmw-9.0.js,9.2.1,chp-Cans,Chipewyan (Unified Canadian Aboriginal Syllabics) fv,fv_dene_nt,ᑌᓀ ᔭᕱᐁ (Dene NT),Western Subarctic,fv_dene_nt_kmw-9.0.js,9.2.1,chp-Cans,Chipewyan (Unified Canadian Aboriginal Syllabics) diff --git a/oem/firstvoices/windows/src/xml/keyman_support.xsl b/oem/firstvoices/windows/src/xml/keyman_support.xsl index dfd8c8445b..81f72fdb66 100644 --- a/oem/firstvoices/windows/src/xml/keyman_support.xsl +++ b/oem/firstvoices/windows/src/xml/keyman_support.xsl @@ -32,11 +32,19 @@
- + + + + +