-
-
Notifications
You must be signed in to change notification settings - Fork 133
fix(mac): improved adherence to backspace rules for compliant apps #15561
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
introduces an alternative to approach to backspace for compliant apps by using the insertText API to replace a character to be deleted and the preceding character from the context with only the character from the context Fixes: #15543
Test Specs
Test Results
|
mcdurdin
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really good -- it's a clear and easy to follow function. I think we need to cover off the surrogate pair scenario for completeness.
I have tried to write a background description in the function header comment because the 'why' for this I think will be unclear to future maintainers. Feel free to adapt especially if I have gotten any details wrong.
| if ((self.apiCompliance.canReplaceText) && ([context length] > codePointsToDelete)) { | ||
| int codePointsToReplace = codePointsToDelete + 1; | ||
| NSRange replacementStringRange = NSMakeRange([context length] - codePointsToReplace, 1); | ||
| NSString *replacementString = [context substringWithRange:replacementStringRange]; | ||
|
|
||
| // replace only works for non-control characters | ||
| // if replacementString contains control characters, then return without handling event | ||
| NSString *message = nil; | ||
| if ([self containsControlCharacter:replacementString]) { | ||
| message = @"handleDeleteByReplace, replacementString contains control characters, cannot delete with replace"; | ||
| os_log_debug([KMLogs keyTraceLog], "%@", message); | ||
| [KMSentryHelper addDebugBreadCrumb:@"event" message:message]; | ||
| return NO; | ||
| } else { | ||
| message = @"handleDeleteByReplace, canReplaceText == true"; | ||
| os_log_debug([KMLogs keyTraceLog], "%@", message); | ||
| [KMSentryHelper addDebugBreadCrumb:@"event" message:message]; | ||
| handledEvent = YES; | ||
| } | ||
|
|
||
| NSRange replacementRange = NSMakeRange(replacementStringRange.location, codePointsToReplace); | ||
| [client insertText:replacementString replacementRange:replacementRange]; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry to make your life more difficult here, but I think we need to make sure this works even with non-BMP characters (U+10000 - U+10FFFF) because it's not clear to me that splitting a surrogate pair in the replacement will work consistently -- even though it's effectively not changing, some apps may reject the transform due to encoding boundaries or safety concerns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was a worthwhile test! I tried with the Malar Tirhuta keyboard, and after typing 𑒏𑒹 (U+1148F U+114B9) and hitting backspace, it only deleted the second half of the surrogate pair, leaving me with U+1148F U+FFFD
I could check the character that core tells me to delete and behave differently if it is a surrogate pair: either resort to the passthrough/generate backspace or, probably riskier, look for a match between the delete string returned from core and the context and try to replace more of the string.
I tried finding APIs that know more about the Unicode string without checking for specific character ranges, but what I found didn't work. There may be better support with the Swift Unicode APIs, so we may have better options when we move the Input Method to Swift in Keyman 20+.
Co-authored-by: Marc Durdin <marc@durdin.net>
Co-authored-by: Marc Durdin <marc@durdin.net>
Introduces an alternative to approach to backspace for compliant apps by using the insertText API to
replace a character to be deleted and the preceding character from the context with only the character from the context
Fixes: #15543
Build-bot: release:mac
User Testing
Preparation: install the keyboard bksp_ldml.zip
All tests should be using compliant apps such as Apple's Pages, TextEdit or Stickies.
abc d/
Select the text, copy and paste it into a character viewer and verify that the last two characters are
U+0064 U+0301.abc d/
Then press bksp. The result should be
abc d.caf'e
The result should be
café.Then press bksp. The result should be
caf.abcreturnab
Then press bksp four times. The result should be
ab.