Merge branch 'master' into feat/developer/kmc-generate

This commit is contained in:
Marc Durdin 2024-09-09 01:20:07 +02:00 committed by GitHub
commit 64c8bce011
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 288 additions and 165 deletions

View file

@ -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

View file

@ -1 +1 @@
18.0.103
18.0.107

View file

@ -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)) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View file

@ -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)

View file

@ -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.

View file

@ -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"

View file

@ -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

View file

@ -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;

View file

@ -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 =
@"<html>"

View file

@ -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

View file

@ -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;

View file

@ -1,4 +1,4 @@
/**
/*
* Keyman is copyright (C) SIL International. MIT License.
*
* KMSettingsRepository.h

View file

@ -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];
}
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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)

View file

@ -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);

View file

@ -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,Hulquminum,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,Hulquminum,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 Tsekene,BC Interior,fv_kwadacha_tsekene_kmw-9.0.js,1.1,sek-Latn,Sekani
fv,fv_natwits,Neduten-Witsuwit'en,BC Interior,fv_natwits_kmw-9.0.js,9.1.3,caf-Latn,Southern Carrier (Latin)
fv,fv_natwits,Neduten-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,ı̨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)

1 Shortname ID Name Region 9.0 Web Keyboard Version Language ID Language Name
12 fv fv_diitiidatx Diidiitidq BC Coast fv_diitiidatx_kmw-9.0.js 9.2.1 nuk-Latn Nuu-chah-nulth (Latin)
13 fv fv_gitsenimx Gitsenimx̱ BC Coast fv_gitsenimx_kmw-9.0.js 10.1.2 git Gitxsan (Latin)
14 fv fv_hailzaqvla Haiɫzaqvla BC Coast fv_hailzaqvla_kmw-9.0.js 9.5.2 hei Heiltsuk (Latin)
15 fv fv_haisla Haisla BC Coast fv_haisla.js 2.1.2 2.1.3 has-Latn Haisla (Latin)
16 fv fv_halqemeylem Halq'eméylem BC Coast fv_halqemeylem_kmw-9.0.js 9.2 9.2.1 hur-Latn Halkomelem (Latin)
17 fv fv_henqeminem Hǝn̓q̓ǝmin̓ǝm BC Coast fv_henqeminem_kmw-9.0.js 10.1 10.2.1 hur-Latn Halkomelem (Latin)
18 fv fv_klahoose Homalco-Klahoose-Sliammon BC Coast fv_klahoose_kmw-9.0.js 10.1 10.2 coo Comox
19 fv fv_hulquminum Hul’q’umi’num’ BC Coast fv_hulquminum_kmw-9.0.js 9.1 hur-Latn hur Halkomelem (Latin) Halkomelem
20 fv fv_hulquminum_combine Hul̓q̓umin̓um̓ BC Coast fv_hulquminum_combine_kmw-9.0.js 2.0.1 hur-Latn Halkomelem (Latin)
21 fv fv_kwakwala_liqwala Kʷak̓ʷala BC Coast fv_kwakwala_liqwala_kmw-9.0.js 9.3 kwk-Latn Kwakiutl (Latin)
22 fv fv_kwakwala Kwak̕wala BC Coast fv_kwakwala_kmw-9.0.js 9.2 kwk-Latn Kwakiutl (Latin)
23 fv fv_lekwungen Lək̓ʷəŋən Lekwungen (Lək̓ʷəŋən) BC Coast fv_lekwungen-9.0.js fv_lekwungen_kmw-9.0.js 1.0 1.0.1 str Lekwungen Straits Salish
24 fv fv_nexwslayemucen Nəxʷsƛ̓ay̓əmúcən BC Coast fv_nexwslayemucen_kmw-9.0.js 10.0 11.0 clm-Latn clm Clallam (Latin) Clallam
25 fv fv_nisgaa Nisg̱a'a BC Coast fv_nisgaa_kmw-9.0.js 9.2 9.2.1 ncg-Latn Nisga'a (Latin)
26 fv fv_nuucaanul Nuučaan̓uł BC Coast fv_nuucaanul_kmw-9.0.js 9.2 nuk-Latn Nuu-chah-nulth (Latin)
27 fv fv_nuxalk Nuxalk BC Coast fv_nuxalk_kmw-9.0.js 10.0.1 blc-Latn Bella Coola (Latin)
28 fv fv_sencoten SENĆOŦEN BC Coast fv_sencoten_kmw-9.0.js 9.2.2 9.2.3 str Straits Salish
29 fv fv_sguuxs Sgüüx̱s BC Coast fv_sguuxs.js 1.1 tsi Tsimshian
30 fv fv_shashishalhem Shashishalhem BC Coast fv_shashishalhem_kmw-9.0.js 9.2 9.2.1 sec-Latn Sechelt (Latin)
31 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)
32 fv fv_smalgyax Sm'algya̱x BC Coast fv_smalgyax_kmw-9.0.js 9.2 9.3 tsi-Latn Tsimshian (Latin)
33 fv fv_xaislakala X̄a'ʼislak̓ala BC Coast fv_xaislakala_kmw-9.0.js 10.0 has-Latn Haisla (Latin)
34 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
35 fv fv_dakelh Dakelh BC Interior fv_dakelh_kmw-9.0.js 9.2.1 caf-Latn Southern Carrier (Latin)
36 fv fv_ktunaxa Ktunaxa BC Interior fv_ktunaxa_kmw-9.0.js 10.0 kut-Latn Kutenai (Latin)
37 fv fv_kwadacha_tsekene Kwadacha Tsek’ene BC Interior fv_kwadacha_tsekene_kmw-9.0.js 1.1 sek-Latn Sekani
38 fv fv_natwits Nedut’en-Witsuwit'en BC Interior fv_natwits_kmw-9.0.js 9.1.3 9.2 caf-Latn Southern Carrier (Latin)
39 fv fv_nlekepmxcin Nłeʔkepmxcin BC Interior fv_nlekepmxcin_kmw-9.0.js 9.5.1 thp-Latn Thompson (Latin)
40 fv fv_nlha7kapmxtsin Nlha7kapmxtsin BC Interior fv_nlha7kapmxtsin_kmw-9.0.js 10.1.1 10.1.2 thp-Latn thp Thompson (Latin) Thompson
41 fv fv_nlakapamuxcheen Nlakapamuxcheen BC Interior fv_nlakapamuxcheen_kmw-9.0.js 1.1 thp Thompson
42 fv fv_nsilxcen Nsilxcən BC Interior fv_nsilxcen_kmw-9.0.js 10.0 10.0.1 oka Okanagan
43 fv fv_secwepemctsin Secwepemctsín BC Interior fv_secwepemctsin_kmw-9.0.js 9.2 9.3 shs-Latn shs Shuswap (Latin) Shuswap
44 fv fv_stlatlimxec Sƛ̓aƛ̓imxəc BC Interior fv_stlatlimxec_kmw-9.0.js 9.3 9.4 lil-Latn Lillooet (Latin)
45 fv fv_statimcets St̓át̓imcets BC Interior fv_statimcets_kmw-9.0.js 9.2 lil-Latn Lillooet (Latin)
46 fv fv_taltan Tāłtān BC Interior fv_taltan_kmw-9.0.js 9.2 tht-Latn Tahltan (Latin)
47 fv fv_tsekehne Tsek'ehne BC Interior fv_tsekehne_kmw-9.0.js 9.2 sek-Latn Sekani (Latin)
48 fv fv_tsilhqotin Tŝilhqot'in BC Interior fv_tsilhqotin_kmw-9.0.js 9.2 9.3 clc-Latn Chilcotin (Latin)
49 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)
50 fv fv_anicinapemi8in Anicinapemi8in/Anishinàbemiwin Eastern Subarctic fv_anicinapemi8in_kmw-9.0.js 9.1.1 alq-Latn Algonquin (Latin)
51 fv fv_atikamekw Atikamekw Eastern Subarctic fv_atikamekw_kmw-9.0.js 9.1.1 atj-Latn Atikamekw (Latin)
53 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)
54 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)
55 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)
56 fv fv_severn_ojibwa ᐊᓂᔑᓂᓂᒧᐎᐣ (Severn Ojibwa) Eastern Subarctic fv_severn_ojibwa_kmw-9.0.js 10.1 10.1.1 ojs-Cans Severn Ojibwa (Unified Canadian Aboriginal Syllabics)
57 fv fv_severn_ojibwa_rdot ᐊᓂᔑᓂᓂᒧᐏᐣ (Severn Ojibwa right w-dot) Eastern Subarctic fv_severn_ojibwa_kmw-9.0.js 1.1 1.1.1 ojs Oji-Cree
58 fv fv_ojibwa ᐊᓂᔑᓇᐯᒧᐎᓐ (a-finals) Eastern Subarctic fv_ojibwa_kmw-9.0.js 10.1 ojb-Cans Northwestern Ojibwa (Unified Canadian Aboriginal Syllabics)
59 fv fv_ojibwa_rdot ᐁᓂᔑᓇᐯᒧᐏᓐ (a-finals right w-dot) Eastern Subarctic fv_ojibwa_rdot_kmw-9.0.js 1.0.2 1.0.3 oj Ojibwa
60 fv fv_ojibwa_ifinal ᐊᓂᔑᓇᐯᒧᐎᣙ (i-finals) Eastern Subarctic fv_ojibwa_ifinal_kmw-9.0.js 1.0.1 1.0.2 oj Ojibwa
61 fv fv_ojibwa_ifinal_rdot ᐊᓂᔑᓇᐯᒧᐏᣙ (i-finals right w-dot) Eastern Subarctic fv_ojibwa_ifinal_rdot_kmw-9.0.js 1.0.1 1.0.2 oj Ojibwa
62 fv fv_naskapi ᓇᔅᑲᐱ (Naskapi) Eastern Subarctic fv_naskapi_kmw-9.0.js 9.3.1 nsk-Cans Naskapi (Unified Canadian Aboriginal Syllabics)
63 sil sil_euro_latin English European european2-1.6.js 3.0.2 en English
64 basic basic_kbdcan Français European canadian_french-1.0.js 1.1.1 fr-CA French (Canada)
65 fv fv_anishinaabemowin Anishinaabemowin Great Lakes - St. Lawrence fv_anishinaabemowin_kmw-9.0.js 10.1 10.2 oj Ojibwa
66 fv fv_bodewadminwen Bodéwadminwen-Nishnabémwen Great Lakes - St. Lawrence fv_bodewadminwen_kmw-9.0.js 9.1.1 pot-Latn Potawatomi (Latin)
67 fv fv_goyogohono Goyogo̱hó:nǫ' Great Lakes - St. Lawrence fv_goyogohono_kmw-9.0.js 9.2.1 cay-Latn Cayuga (Latin)
68 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 fv fv_tsuutina Tsúùt'ínà Prairies fv_tsuutina_kmw-9.0.js 9.1.1 srs-Latn Sarsi (Latin)
86 fv fv_plains_cree ᓀᐦᐃᔭᐍᐏᐣ (Plains Cree) Prairies fv_plains_cree_kmw-9.0.js 11.1 crk-Cans ᓀᐦᐃᔭᐍᐏᐣ (Cree syllabics)
87 fv fv_dine_bizaad Diné Bizaad South West fv_dine_bizaad_kmw-9.0.js 9.1.1 nv-Latn Navajo (Latin)
88 fv fv_dane_zaa_zaage Dane-Z̲aa Z̲áágéʔ Western Subarctic fv_dane_zaa_zaage_kmw-9.0.js 9.4 9.4.1 bea Beaver
89 fv fv_dene_dzage Dene Dzage Western Subarctic fv_dene_dzage_kmw-9.0.js 11.0.1 kkz-Latn Kaska (Latin)
90 fv fv_dene_zhatie Dene Zhatié Western Subarctic fv_dene_zhatie_kmw-9.0.js 10.2.1 den Dene Zhatıé
91 fv fv_denesuline_epsilon Dënesųłıné Western Subarctic fv_denesuline_epsilon_kmw-9.0.js 10.0.1 chp Chipewyan
100 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)
101 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)
102 fv fv_southern_tutchone Southern Tutchone Western Subarctic fv_southern_tutchone_kmw-9.0.js 9.3 tce-Latn Southern Tutchone (Latin)
103 fv fv_tagizi_dene Tāgizi Dene Western Subarctic fv_tagizi_dene_kmw-9.0.js 9.3 9.4 tgx-Latn Tagish (Latin)
104 fv fv_tlicho_yatii Tłı̨chǫ Yatıı̀ Western Subarctic fv_tlicho_yatii_kmw-9.0.js 9.1.1 dgr-Latn Dogrib (Latin)
105 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)
106 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)

View file

@ -32,11 +32,19 @@
</div>
<div class="support_sil">
<xsl:value-of select="$locale/string[@name='S_Support_CreatedBySIL']"/>
<xsl:variable name="originalText" select="$locale/string[@name='S_Support_CreatedBySILGlobal']"/>
<xsl:variable name="replacement" select="'SIL Global'"/>
<xsl:variable name="beforePlaceholder" select="substring-before($originalText, '%0:s')"/>
<xsl:variable name="afterPlaceholder" select="substring-after($originalText, '%0:s')"/>
<xsl:value-of select="concat($beforePlaceholder, $replacement, $afterPlaceholder)"/>
</div>
<div class="support_copyright">
<xsl:value-of select="$locale/string[@name='S_Support_Copyright']"/>
<xsl:variable name="originalText" select="$locale/string[@name='S_Support_CopyrightSILGlobal']"/>
<xsl:variable name="replacement" select="'SIL Global'"/>
<xsl:variable name="beforePlaceholder" select="substring-before($originalText, '%0:s')"/>
<xsl:variable name="afterPlaceholder" select="substring-after($originalText, '%0:s')"/>
<xsl:value-of select="concat($beforePlaceholder, $replacement, $afterPlaceholder)"/>
</div>
<div class="support_links">

View file

@ -512,6 +512,16 @@
<!-- Introduced: 7.0.230.0 -->
<string name="S_Support_Copyright" comment="Support - Product Copyright">Copyright © SIL International. All Rights Reserved.</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 18.0.94.0 -->
<string name="S_Support_CreatedBySILGlobal" comment="Created by {SIL Global} ">Created by %1$s</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 18.0.94.0 -->
<string name="S_Support_CopyrightSILGlobal" comment="Copyright © {SIL Global}. All Rights Reserved.">Copyright © %1$s. All Rights Reserved.</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->

View file

@ -660,7 +660,7 @@ export default class KeymanEngine extends KeymanEngineBase<BrowserConfiguration,
* @param {(string)=} argLayerId name or index of layer to show, defaulting to 'default'
* @return {Object} DIV object with filled keyboard layer content
*
* See https://help.keyman.com/developer/engine/web/current-version/reference/osk/BuildVisualKeyboard
* See https://help.keyman.com/developer/engine/web/current-version/reference/core/BuildVisualKeyboard
*/
public BuildVisualKeyboard(
PInternalName: string,

View file

@ -29,11 +29,19 @@
</div>
<div class="support_sil">
<xsl:value-of select="$locale/string[@name='S_Support_CreatedBySIL']"/>
<xsl:variable name="originalText" select="$locale/string[@name='S_Support_CreatedBySILGlobal']"/>
<xsl:variable name="replacement" select="'SIL Global'"/>
<xsl:variable name="beforePlaceholder" select="substring-before($originalText, '%0:s')"/>
<xsl:variable name="afterPlaceholder" select="substring-after($originalText, '%0:s')"/>
<xsl:value-of select="concat($beforePlaceholder, $replacement, $afterPlaceholder)"/>
</div>
<div class="support_copyright">
<xsl:value-of select="$locale/string[@name='S_Support_Copyright']"/>
<xsl:variable name="originalText" select="$locale/string[@name='S_Support_CopyrightSILGlobal']"/>
<xsl:variable name="replacement" select="'SIL Global'"/>
<xsl:variable name="beforePlaceholder" select="substring-before($originalText, '%0:s')"/>
<xsl:variable name="afterPlaceholder" select="substring-after($originalText, '%0:s')"/>
<xsl:value-of select="concat($beforePlaceholder, $replacement, $afterPlaceholder)"/>
</div>
<div class="support_links">

View file

@ -377,6 +377,11 @@
<!-- Introduced: 7.0.230.0 -->
<string name="koAltGrCtrlAlt" comment="General options - Ctrl+Alt simulates AltGr on computers without AltGr">Simulate AltGr with Ctrl+Alt</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 18.0.95 -->
<string name="koRightModifierHK" comment="General options - Right Ctrl Alt and Shift trigger hotkey">Allow right modifier for hotkeys</string>
<!-- Context: Configuration Dialog - Options tab -->
<!-- String Type: FormatString -->
<!-- Introduced: 9.0.480.0 -->
@ -536,6 +541,16 @@
<!-- Introduced: 7.0.230.0 -->
<string name="S_Support_Copyright" comment="Support - Product Copyright">Copyright © SIL International. All Rights Reserved.</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 18.0.94.0 -->
<string name="S_Support_CreatedBySILGlobal" comment="Created by {SIL Global} ">Created by %1$s</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 18.0.94.0 -->
<string name="S_Support_CopyrightSILGlobal" comment="Copyright © {SIL Global}. All Rights Reserved.">Copyright © %1$s. All Rights Reserved.</string>
<!-- Context: Configuration Dialog - Support tab -->
<!-- String Type: PlainText -->
<!-- Introduced: 7.0.230.0 -->

View file

@ -139,8 +139,6 @@ Hotkey *Hotkeys::GetHotkey(DWORD hotkey)
{
for (int i = 0; i < m_nHotkeys; i++) {
if (m_hotkeys[i].HotkeyValue == hotkey) {
SendDebugMessageFormat(
"LanguageHotkey[%d] = {HotkeyValue: %x, hkl: %x} passed in: %x", i, m_hotkeys[i].HotkeyValue, m_hotkeys[i].hkl, hotkey);
return &m_hotkeys[i];
}
}

View file

@ -129,6 +129,25 @@ BOOL IsTouchPanelVisible() {
return touchPanelVisible;
}
/*
Cache AllowRightModifierHotKey for this session
*/
BOOL AllowRightModifierHotKey() {
static BOOL flag_AllowRightModifierHotKey = FALSE;
static BOOL loaded = FALSE;
if (!loaded) {
RegistryReadOnly reg(HKEY_CURRENT_USER);
if (reg.OpenKeyReadOnly(REGSZ_KeymanCU)) {
if (reg.ValueExists(REGSZ_AllowRightModifierHotKey)) {
flag_AllowRightModifierHotKey = !!reg.ReadInteger(REGSZ_AllowRightModifierHotKey);
}
}
loaded = TRUE; // Set loaded to TRUE whether or not the key exists
}
return flag_AllowRightModifierHotKey;
}
LRESULT _kmnLowLevelKeyboardProc(
_In_ int nCode,
_In_ WPARAM wParam,
@ -150,16 +169,33 @@ LRESULT _kmnLowLevelKeyboardProc(
// #5190: Don't cache modifier state because sometimes we won't receive
// modifier change events (e.g. on lock screen)
FHotkeyShiftState = 0;
if (GetKeyState(VK_LCONTROL) < 0) FHotkeyShiftState |= HK_CTRL;
if (GetKeyState(VK_RCONTROL) < 0) FHotkeyShiftState |= HK_RCTRL_INVALID;
if (GetKeyState(VK_LMENU) < 0) FHotkeyShiftState |= HK_ALT;
if (GetKeyState(VK_RMENU) < 0) FHotkeyShiftState |= HK_RALT_INVALID;
if (GetKeyState(VK_LSHIFT) < 0) FHotkeyShiftState |= HK_SHIFT;
if (GetKeyState(VK_RSHIFT) < 0) FHotkeyShiftState |= HK_RSHIFT_INVALID;
//TODO: #8064. Can remove debug message once issue #8064 is resolved
SendDebugMessageFormat("!UseCachedHotkeyModifierState [FHotkeyShiftState:%x]", FHotkeyShiftState);
FHotkeyShiftState = 0;
if (GetKeyState(VK_LCONTROL) < 0) {
FHotkeyShiftState |= HK_CTRL;
}
if (GetKeyState(VK_RCONTROL) < 0) {
FHotkeyShiftState |= AllowRightModifierHotKey() ? HK_CTRL : HK_RCTRL_INVALID;
}
if (GetKeyState(VK_LMENU) < 0) {
FHotkeyShiftState |= HK_ALT;
}
if (GetKeyState(VK_RMENU) < 0) {
FHotkeyShiftState |= AllowRightModifierHotKey() ? HK_ALT : HK_RALT_INVALID;
}
if (GetKeyState(VK_LSHIFT) < 0) {
FHotkeyShiftState |= HK_SHIFT;
}
if (GetKeyState(VK_RSHIFT) < 0) {
FHotkeyShiftState |= AllowRightModifierHotKey() ? HK_SHIFT : HK_RSHIFT_INVALID;
}
//TODO: #8064. Can remove debug message once issue #8064 is resolved
SendDebugMessageFormat("[FHotkeyShiftState:%x]", FHotkeyShiftState);
// #7337 Post the modifier state ensuring the serialized queue is in sync
// Note that the modifier key may be posted again with WM_KEYMAN_KEY_EVENT,
@ -243,30 +279,24 @@ BOOL ProcessHotkey(UINT vkCode, BOOL isUp, DWORD ShiftState) {
Hotkeys *hotkeys = Hotkeys::Instance(); // I4641
if (!hotkeys) {
SendDebugMessageFormat("Failed to get Instance");
return FALSE;
}
Hotkey *hotkey = hotkeys->GetHotkey(ShiftState | vkCode); // I4641
if (!hotkey) {
SendDebugMessageFormat("GetHotkey Null");
return FALSE;
}
if (isUp) {
SendDebugMessageFormat("Is Up");
return TRUE;
}
if (hotkey->HotkeyType == hktInterface) {
SendDebugMessageFormat("PostMasterController");
Globals::PostMasterController(wm_keyman_control, MAKELONG(KMC_INTERFACEHOTKEY, hotkey->Target), 0);
}
else {
SendDebugMessageFormat("ReportKeyboardChanged");
ReportKeyboardChanged(PC_HOTKEYCHANGE, hotkey->hkl == 0 ? TF_PROFILETYPE_INPUTPROCESSOR : TF_PROFILETYPE_KEYBOARDLAYOUT, 0, hotkey->hkl, GUID_NULL, hotkey->profileGUID);
}
SendDebugMessageFormat("PostDummyKeyEvent");
/* Generate a dummy keystroke to block menu activations, etc but let the shift key through */
PostDummyKeyEvent(); // I3301 - this is imperfect because we don't deal with HC_NOREMOVE. But good enough? // I3534 // I4844

View file

@ -121,12 +121,13 @@ type
GroupName: string;
end;
const KeymanOptionInfo: array[0..15] of TKeymanOptionInfo = ( // I3331 // I3620 // I4552
const KeymanOptionInfo: array[0..16] of TKeymanOptionInfo = ( // I3331 // I3620 // I4552
// Global options
(opt: koKeyboardHotkeysAreToggle; RegistryName: SRegValue_KeyboardHotkeysAreToggle; OptionType: kotBool; BoolValue: False; GroupName: 'kogGeneral'),
(opt: koSwitchLanguageForAllApplications; RegistryName: SRegValue_SwitchLanguageForAllApplications; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'), // I2277 // I4393
(opt: koAltGrCtrlAlt; RegistryName: SRegValue_AltGrCtrlAlt; OptionType: kotBool; BoolValue: False; GroupName: 'kogGeneral'),
(opt: koRightModifierHK; RegistryName: SRegValue_AllowRightModifierHotKey; OptionType: kotBool; BoolValue: False; GroupName: 'kogGeneral'),
(opt: koShowHints; RegistryName: SRegValue_EnableHints; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'),
(opt: koBaseLayout; RegistryName: SRegValue_UnderlyingLayout; OptionType: kotLong; IntValue: 0; GroupName: 'kogGeneral'),

View file

@ -5,7 +5,10 @@ interface
type
TUtilKeymanOption = (
// General options
koKeyboardHotkeysAreToggle, koAltGrCtrlAlt, koReleaseShiftKeysAfterKeyPress,
koKeyboardHotkeysAreToggle,
koAltGrCtrlAlt,
koRightModifierHK,
koReleaseShiftKeysAfterKeyPress,
koShowHints, // I1256
// Startup options
koTestKeymanFunctioning,