mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-05 15:17:40 +00:00
eliminate some unneeded properties
This commit is contained in:
parent
af25f2b466
commit
cd037c0b8d
1 changed files with 38 additions and 128 deletions
|
|
@ -6,19 +6,28 @@
|
|||
*
|
||||
* Created by Shawn Schantz on 2023-05-05.
|
||||
*
|
||||
* Check whether the current text input client is compatibility with APIs.
|
||||
* Compliance is determined by attempting the current selection (location and length),
|
||||
* but this is not a surefire indicator. For some apps, a valid but incorrect selection of
|
||||
* {0, 0} is returned regardless of the real selection.
|
||||
* Check whether the current text input client is compliant with APIs.
|
||||
* Compliance is determined by getting the current selection (location and length) with
|
||||
* the selectionRange API and evaluating the results.
|
||||
* But this is not a surefire indicator. For several apps, a valid but incorrect selection of
|
||||
* {0, 0}, or possibly something else, is returned regardless of the real selection.
|
||||
*
|
||||
* When {0, 0} is returned, then we can check to see if a subsequent insert results in a
|
||||
* change in the location. It always should, because it cannot replace at location 0.
|
||||
* If the location does change, then the selection API is compliant.
|
||||
* When {0, 0} is returned, then we can check to see if a later call to the insertText API
|
||||
* results in a change in the location. It always should, because there is no text to
|
||||
* replace if the client truly is at location 0.
|
||||
* If the location does change, then we assume the selection API is compliant.
|
||||
*
|
||||
* Even worse for some apps, the selection API works, but attempts
|
||||
* to replace during an insert do not work. There is no way to detect this behavior,
|
||||
* so these apps must be hard-coded as non-compliant. A couple of known apps
|
||||
* that behave this way are Brackets (Adobe OS project) and MacVIM
|
||||
* Even worse for some apps, the selection API returns a non-zero location, but attempts
|
||||
* to replace text during a call to insertText do not function properly. There is no way to
|
||||
* detect this behavior, so these apps must be hard-coded as non-compliant. A couple
|
||||
* of known apps that behave this way are Brackets (Adobe OS project) and MacVIM
|
||||
*
|
||||
* We really only have the ability to test the selection API, and if it does not work, then
|
||||
* Keyman functionality is limited. Lacking the current location
|
||||
* - we cannot pass a range for reading the context
|
||||
* - we cannot pass a replacement range when calling insertText
|
||||
* The result is that we are limited in key processing, using only locally cached context, and
|
||||
* we can only delete by sending backspace events.
|
||||
*/
|
||||
|
||||
#import "TextCompatibilityCheck.h"
|
||||
|
|
@ -31,8 +40,6 @@ NSString *const kKMLegacyApps = @"KMLegacyApps";
|
|||
@property (readonly) id client;
|
||||
@property BOOL apiComplianceUncertain;
|
||||
@property BOOL hasCompliantSelectionApi;
|
||||
@property (readonly) BOOL hasReadApi;
|
||||
@property (readonly) BOOL hasInsertApi;
|
||||
|
||||
@end
|
||||
|
||||
|
|
@ -45,27 +52,17 @@ NSString *const kKMLegacyApps = @"KMLegacyApps";
|
|||
_clientApplicationId = appId;
|
||||
_apiComplianceUncertain = YES;
|
||||
|
||||
// first check in the noncompliant app lists
|
||||
// TODO: uncomment after testing
|
||||
//BOOL isUncompliantApp = ![self containedInNoncompliantAppLists:clientAppId];
|
||||
BOOL isUncompliantApp = NO;
|
||||
|
||||
if (isUncompliantApp) {
|
||||
_apiComplianceUncertain = NO;
|
||||
self.hasCompliantSelectionApi = NO;
|
||||
} else {
|
||||
// if we do not have hard-coded noncompliance, then test the app
|
||||
if (![self applyNoncompliantAppLists:appId]) {
|
||||
[self testApiCompliance:client];
|
||||
}
|
||||
|
||||
_hasReadApi = [client respondsToSelector:@selector(attributedSubstringFromRange:)];
|
||||
_hasInsertApi = [client respondsToSelector:@selector(insertText:replacementRange:)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"apiComplianceUncertain: %d, hasWorkingSelectionApi: %d, hasReadAPI: %d, hasInsertAPI: %d, canGetSelection: %d, canReadText: %d, canInsertText: %d, canReplaceText: %d, mustBackspaceUsingEvents: %d, clientAppId: %@, client: %@", self.apiComplianceUncertain, self.hasCompliantSelectionApi, self.hasReadApi, self.hasInsertApi, [self canGetSelection], [self canReadText], [self canInsertText], [self canReplaceText], [self mustBackspaceUsingEvents], _clientApplicationId, _client];
|
||||
return [NSString stringWithFormat:@"apiComplianceUncertain: %d, hasCompliantSelectionApi: %d, canReadText: %d, canReplaceText: %d, mustBackspaceUsingEvents: %d, clientAppId: %@, client: %@", self.apiComplianceUncertain, self.hasCompliantSelectionApi, [self canReadText], [self canReplaceText], [self mustBackspaceUsingEvents], _clientApplicationId, _client];
|
||||
}
|
||||
|
||||
/** test to see if the API selectedRange functions properly for the text input client */
|
||||
|
|
@ -136,16 +133,22 @@ return [NSString stringWithFormat:@"apiComplianceUncertain: %d, hasWorkingSelect
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks if the client app is known to be non-complian, first by checking the hard-coded non-compliant app list
|
||||
* and then by checking the user-managed (via user defaults) non-compliant app list
|
||||
* Apply the hard-coded non-compliant app list and the user-managed (via user defaults) non-compliant app list.
|
||||
* If true, mark the app as non-compliant and certain (not apiComplianceUncertain).
|
||||
*/
|
||||
- (BOOL)containedInNoncompliantAppLists:(NSString *)clientAppId {
|
||||
- (BOOL)applyNoncompliantAppLists:(NSString *)clientAppId {
|
||||
BOOL isAppNonCompliant = [self containedInHardCodedNoncompliantAppList:clientAppId];
|
||||
if (!isAppNonCompliant) {
|
||||
isAppNonCompliant = [self containedInUserManagedNoncompliantAppList:clientAppId];
|
||||
}
|
||||
|
||||
NSLog(@"containedInNoncompliantAppLists: for app %@: %@", clientAppId, isAppNonCompliant?@"yes":@"no");
|
||||
|
||||
if (isAppNonCompliant) {
|
||||
self.apiComplianceUncertain = NO;
|
||||
self.hasCompliantSelectionApi = NO;
|
||||
}
|
||||
|
||||
return isAppNonCompliant;
|
||||
}
|
||||
|
||||
|
|
@ -157,6 +160,8 @@ return [NSString stringWithFormat:@"apiComplianceUncertain: %d, hasWorkingSelect
|
|||
BOOL isAppNonCompliant = ([clientAppId isEqual: @"com.github.atom"] ||
|
||||
[clientAppId isEqual: @"com.collabora.libreoffice-free"] ||
|
||||
[clientAppId isEqual: @"org.libreoffice.script"] ||
|
||||
[clientAppId isEqual: @"org.vim.MacVim"] ||
|
||||
[clientAppId isEqual: @"io.brackets.appshell"] ||
|
||||
[clientAppId isEqual: @"com.axosoft.gitkraken"] ||
|
||||
[clientAppId isEqual: @"org.sil.app.builder.scripture.ScriptureAppBuilder"] ||
|
||||
[clientAppId isEqual: @"org.sil.app.builder.reading.ReadingAppBuilder"] ||
|
||||
|
|
@ -201,53 +206,6 @@ return [NSString stringWithFormat:@"apiComplianceUncertain: %d, hasWorkingSelect
|
|||
return isAppNonCompliant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the client app requires legacy input mode, first by checking the user defaults, if they exist,
|
||||
* then, by our hard-coded list.
|
||||
*/
|
||||
/*
|
||||
- (BOOL)isClientAppLegacy:(NSString *)clientAppId {
|
||||
BOOL isAppNonCompliant = NO;
|
||||
|
||||
NSArray *legacyAppsUserDefaults = self.legacyAppsUserDefaults;
|
||||
|
||||
BOOL result = NO;
|
||||
|
||||
if(legacyAppsUserDefaults != nil) {
|
||||
result = [self isClientAppLegacy:clientAppId fromArray:legacyAppsUserDefaults];
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
// TODO: Pages and Keynote (and possibly lots of other undiscovered apps that are otherwise compliant
|
||||
// with Apple's IM framework) have a problem in that if the user selects a different font (or other
|
||||
// formatting) and then types a sequence that causes characters to be added to the document and then
|
||||
// subsequently replaced, the replacement causes the formatting decision to be forgotten. This can be
|
||||
// "fixed" by treating them as legacy apps, but it causes other problems.
|
||||
result = ([clientAppId isEqual: @"com.github.atom"] ||
|
||||
[clientAppId isEqual: @"com.collabora.libreoffice-free"] ||
|
||||
[clientAppId isEqual: @"org.libreoffice.script"] ||
|
||||
[clientAppId isEqual: @"com.axosoft.gitkraken"] ||
|
||||
[clientAppId isEqual: @"org.sil.app.builder.scripture.ScriptureAppBuilder"] ||
|
||||
[clientAppId isEqual: @"org.sil.app.builder.reading.ReadingAppBuilder"] ||
|
||||
[clientAppId isEqual: @"org.sil.app.builder.dictionary.DictionaryAppBuilder"] ||
|
||||
//[clientAppId isEqual: @"com.microsoft.Word"] || // 2020-11-24[mcd]: Appears to work well in Word 16.43, disable legacy by default
|
||||
[clientAppId isEqual: @"org.openoffice.script"] ||
|
||||
[clientAppId isEqual: @"com.adobe.illustrator"] ||
|
||||
[clientAppId isEqual: @"com.adobe.InDesign"] ||
|
||||
[clientAppId isEqual: @"com.adobe.Photoshop"] ||
|
||||
[clientAppId isEqual: @"com.adobe.AfterEffects"] ||
|
||||
[clientAppId isEqual: @"com.microsoft.VSCode"] ||
|
||||
[clientAppId isEqual: @"com.google.Chrome"] ||
|
||||
[clientAppId hasPrefix: @"net.java"] ||
|
||||
[clientAppId isEqual: @"com.Keyman.test.legacyInput"]
|
||||
//||[clientAppId isEqual: @"ro.sync.exml.Oxygen"] - Oxygen has worse problems
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks array for a list of possible regexes to match a client app id
|
||||
*/
|
||||
|
|
@ -275,25 +233,16 @@ return [NSString stringWithFormat:@"apiComplianceUncertain: %d, hasWorkingSelect
|
|||
return self.apiComplianceUncertain;
|
||||
}
|
||||
|
||||
|
||||
-(BOOL) canGetSelection {
|
||||
return self.hasCompliantSelectionApi;
|
||||
}
|
||||
|
||||
-(BOOL) canReadText {
|
||||
// seems simple, but every application tested that returned the selection also successfully read the text using attributedSubstringFromRange
|
||||
BOOL canReadText = self.hasReadApi && self.canGetSelection;
|
||||
return canReadText;
|
||||
}
|
||||
|
||||
-(BOOL) canInsertText {
|
||||
// all applications tested can insertText (though replacement may not work)
|
||||
return self.hasInsertApi;
|
||||
|
||||
BOOL hasReadApi = [self.client respondsToSelector:@selector(attributedSubstringFromRange:)];
|
||||
return hasReadApi && self.hasCompliantSelectionApi;
|
||||
}
|
||||
|
||||
-(BOOL) canReplaceText {
|
||||
// testing shows that every application that returns the selection, can also replace text
|
||||
return self.hasInsertApi && self.canGetSelection;
|
||||
return self.hasCompliantSelectionApi;
|
||||
}
|
||||
|
||||
-(BOOL) mustBackspaceUsingEvents {
|
||||
|
|
@ -301,43 +250,4 @@ return [NSString stringWithFormat:@"apiComplianceUncertain: %d, hasWorkingSelect
|
|||
return !self.canReplaceText;
|
||||
}
|
||||
|
||||
/*
|
||||
-(void) experiment {
|
||||
NSRange notFoundRange = NSMakeRange(NSNotFound, NSNotFound);
|
||||
NSRange zeroRange = NSMakeRange(0, 0);
|
||||
NSRange selectionRange = [self.client selectedRange];
|
||||
|
||||
if (NSEqualRanges(selectionRange, notFoundRange)) {
|
||||
NSLog(@"**compatibility** ERROR selectedRange = {NSNotFound, NSNotFound}");
|
||||
} else if (NSEqualRanges(selectionRange, notFoundRange)) {
|
||||
NSLog(@"**compatibility** ERROR selectedRange = {0,0}");
|
||||
} else {
|
||||
NSLog(@"**compatibility** selectedRange = %@", NSStringFromRange(selectionRange));
|
||||
}
|
||||
|
||||
NSRange contextRange = NSMakeRange(1, 0);
|
||||
NSLog(@"**compatibility** get string of empty range, location 1, length 0");
|
||||
|
||||
NSAttributedString *attributedText = [self.client attributedSubstringFromRange:contextRange];
|
||||
|
||||
if (attributedText == nil) {
|
||||
NSLog(@" **compatibility** attributedSubstringFromRange({1,0}) is nil");
|
||||
} else {
|
||||
NSString *context = attributedText.string;
|
||||
NSLog(@" **compatibility** attributedSubstringFromRange = %@", context);
|
||||
}
|
||||
|
||||
contextRange = NSMakeRange(1, 1);
|
||||
NSLog(@"**compatibility** get string at location 1, length 1");
|
||||
|
||||
attributedText = [self.client attributedSubstringFromRange:contextRange];
|
||||
|
||||
if (attributedText == nil) {
|
||||
NSLog(@" **compatibility** attributedSubstringFromRange({1,1}) is nil");
|
||||
} else {
|
||||
NSString *context = attributedText.string;
|
||||
NSLog(@" **compatibility** attributedSubstringFromRange = %@", context);
|
||||
}
|
||||
}
|
||||
*/
|
||||
@end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue