mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-06-05 22:30:29 +00:00
Track uncommitted input text so an IME (CJK input) can query it back
In CJK input, keystrokes are rendered into text provisionally and may not be in the final form that will be committed to the text input widget. For example, in Korean input, a syllable is typed in using Hangeul, but the user may then decide to replace it with a Hanja character. In order for such translation to happen, the IME must be able to query back the current uncommitted text.
This commit is contained in:
parent
738b1e4f47
commit
04d42d3815
1 changed files with 70 additions and 11 deletions
|
|
@ -38,6 +38,7 @@
|
|||
NSRange _markedRange;
|
||||
NSRange _selectedRange;
|
||||
SDL_Rect _inputRect;
|
||||
NSMutableString *_committedText;
|
||||
}
|
||||
- (void)doCommandBySelector:(SEL)myselector;
|
||||
- (void)setInputRect:(const SDL_Rect *)rect;
|
||||
|
|
@ -52,11 +53,10 @@
|
|||
|
||||
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
/* TODO: Make use of replacementRange? */
|
||||
|
||||
const char *str;
|
||||
|
||||
DEBUG_IME(@"insertText: %@", aString);
|
||||
DEBUG_IME(@"insertText: %@ replacementRange: (%d, %d)", aString,
|
||||
replacementRange.location, replacementRange.length);
|
||||
|
||||
/* Could be NSString or NSAttributedString, so we have
|
||||
* to test and convert it before return as SDL event */
|
||||
|
|
@ -71,15 +71,36 @@
|
|||
[self unmarkText];
|
||||
}
|
||||
|
||||
/* Track committed text so the IME can query it back
|
||||
(e.g., Korean IME needs this for Hanja candidate lookup). */
|
||||
{
|
||||
NSString *s = [aString isKindOfClass:[NSAttributedString class]]
|
||||
? [aString string] : aString;
|
||||
if (!_committedText) {
|
||||
_committedText = [s mutableCopy];
|
||||
} else {
|
||||
[_committedText appendString:s];
|
||||
}
|
||||
_selectedRange = NSMakeRange([_committedText length], 0);
|
||||
}
|
||||
|
||||
SDL_SendKeyboardText(str);
|
||||
}
|
||||
|
||||
- (void)doCommandBySelector:(SEL)myselector
|
||||
{
|
||||
/* No need to do anything since we are not using Cocoa
|
||||
selectors to handle special keys, instead we use SDL
|
||||
key events to do the same job.
|
||||
*/
|
||||
/* Key actions are handled via SDL key events, but we still need to keep
|
||||
_committedText in sync so the IME can query it (e.g., Hanja lookup). */
|
||||
if (myselector == @selector(deleteBackward:) && _committedText) {
|
||||
NSUInteger len = [_committedText length];
|
||||
if (len > 0) {
|
||||
/* Remove the last character (composed character sequence). */
|
||||
NSRange last;
|
||||
last = [_committedText rangeOfComposedCharacterSequenceAtIndex:len - 1];
|
||||
[_committedText deleteCharactersInRange:last];
|
||||
_selectedRange = NSMakeRange([_committedText length], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)hasMarkedText
|
||||
|
|
@ -103,11 +124,35 @@
|
|||
aString = [aString string];
|
||||
}
|
||||
|
||||
DEBUG_IME(@"setMarkedText: %@, (%d, %d) replacementRange: (%d, %d)", aString,
|
||||
selectedRange.location, selectedRange.length,
|
||||
replacementRange.location, replacementRange.length);
|
||||
|
||||
if ([aString length] == 0) {
|
||||
[self unmarkText];
|
||||
return;
|
||||
}
|
||||
|
||||
/* Delete committed text being replaced by this composition (e.g., Hanja
|
||||
candidate replacing a previously committed Hangul syllable).
|
||||
Clear modifier state so the backspaces aren't interpreted as
|
||||
Option+Backspace (delete-word) by the application. */
|
||||
if (replacementRange.location != NSNotFound && replacementRange.length > 0 &&
|
||||
_committedText) {
|
||||
NSUInteger end = replacementRange.location + replacementRange.length;
|
||||
if (end <= [_committedText length]) {
|
||||
SDL_Keymod saved = SDL_GetModState();
|
||||
SDL_SetModState(KMOD_NONE);
|
||||
for (NSUInteger i = 0; i < replacementRange.length; i++) {
|
||||
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE);
|
||||
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE);
|
||||
}
|
||||
SDL_SetModState(saved);
|
||||
[_committedText replaceCharactersInRange:replacementRange withString:@""];
|
||||
_selectedRange = NSMakeRange(replacementRange.location, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (_markedText != aString) {
|
||||
_markedText = aString;
|
||||
}
|
||||
|
|
@ -117,9 +162,6 @@
|
|||
|
||||
SDL_SendEditingText([aString UTF8String],
|
||||
(int) selectedRange.location, (int) selectedRange.length);
|
||||
|
||||
DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText,
|
||||
selectedRange.location, selectedRange.length);
|
||||
}
|
||||
|
||||
- (void)unmarkText
|
||||
|
|
@ -153,6 +195,18 @@
|
|||
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
|
||||
{
|
||||
DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", aRange.location, aRange.length);
|
||||
|
||||
if (_committedText) {
|
||||
NSUInteger len = [_committedText length];
|
||||
NSRange clipped = NSIntersectionRange(aRange, NSMakeRange(0, len));
|
||||
if (clipped.length > 0) {
|
||||
if (actualRange) {
|
||||
*actualRange = clipped;
|
||||
}
|
||||
return [[NSAttributedString alloc]
|
||||
initWithString:[_committedText substringWithRange:clipped]];
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
|
@ -424,7 +478,12 @@ void Cocoa_HandleKeyEvent(_THIS, NSEvent *event)
|
|||
#endif
|
||||
if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
|
||||
/* FIXME CW 2007-08-16: only send those events to the field editor for which we actually want text events, not e.g. esc or function keys. Arrow keys in particular seem to produce crashes sometimes. */
|
||||
[data.fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||
/* Let the input context handle IME events like candidate selection
|
||||
(e.g., Option+Return for Hanja in Korean IME). Fall back to
|
||||
interpretKeyEvents if the input context doesn't consume the event. */
|
||||
if (![[data.fieldEdit inputContext] handleEvent:event]) {
|
||||
[data.fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||
}
|
||||
#if 0
|
||||
text = [[event characters] UTF8String];
|
||||
if(text && *text) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue