From c1fbe6996a29bc05a5f8889c138f2bf3895de253 Mon Sep 17 00:00:00 2001 From: Neil Hodgson Date: Sun, 22 Feb 2015 10:12:28 +1100 Subject: Implement additional methods from the NSTextInputClient protocol so that more features of the IME work. attributedSubstringForProposedRange:actualRange: and characterIndexForPoint: now have full implementations. This required using UTF-16 document indexes in many places as that is what Cocoa wants. Tentative undo is used for the composition text instead of turning off undo as that is safer and similar to IME code on other platforms. --- cocoa/ScintillaCocoa.mm | 109 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 92 insertions(+), 17 deletions(-) (limited to 'cocoa/ScintillaCocoa.mm') diff --git a/cocoa/ScintillaCocoa.mm b/cocoa/ScintillaCocoa.mm index f248f3bb0..ced7be3d6 100644 --- a/cocoa/ScintillaCocoa.mm +++ b/cocoa/ScintillaCocoa.mm @@ -2102,22 +2102,42 @@ bool ScintillaCocoa::KeyboardInput(NSEvent* event) int ScintillaCocoa::InsertText(NSString* input) { CFStringEncoding encoding = EncodingFromCharacterSet(IsUnicodeMode(), - vs.styles[STYLE_DEFAULT].characterSet); - CFRange rangeAll = {0, static_cast([input length])}; - CFIndex usedLen = 0; - CFStringGetBytes((CFStringRef)input, rangeAll, encoding, '?', - false, NULL, 0, &usedLen); - - if (usedLen > 0) + vs.styles[STYLE_DEFAULT].characterSet); + std::string encoded = EncodedBytesString((CFStringRef)input, encoding); + + if (encoded.length() > 0) { - std::vector buffer(usedLen); + AddCharUTF((char*) encoded.c_str(), static_cast(encoded.length()), false); + } + return static_cast(encoded.length()); +} - CFStringGetBytes((CFStringRef)input, rangeAll, encoding, '?', - false, buffer.data(),usedLen, NULL); +//-------------------------------------------------------------------------------------------------- - AddCharUTF((char*) buffer.data(), static_cast(usedLen), false); - } - return static_cast(usedLen); +/** + * Convert from a range of characters to a range of bytes. + */ +NSRange ScintillaCocoa::PositionsFromCharacters(NSRange range) const +{ + long start = pdoc->GetRelativePositionUTF16(0, range.location); + if (start == INVALID_POSITION) + start = pdoc->Length(); + long end = pdoc->GetRelativePositionUTF16(start, range.length); + if (end == INVALID_POSITION) + end = pdoc->Length(); + return NSMakeRange(start, end - start); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Convert from a range of characters from a range of bytes. + */ +NSRange ScintillaCocoa::CharactersFromPositions(NSRange range) const +{ + const long start = pdoc->CountUTF16(0, range.location); + const long len = pdoc->CountUTF16(range.location, NSMaxRange(range)); + return NSMakeRange(start, len); } //-------------------------------------------------------------------------------------------------- @@ -2125,16 +2145,71 @@ int ScintillaCocoa::InsertText(NSString* input) /** * Used to ensure that only one selection is active for input composition as composition * does not support multi-typing. - * Also drop virtual space as that is not supported by composition. */ void ScintillaCocoa::SelectOnlyMainSelection() { - SelectionRange mainSel = sel.RangeMain(); - mainSel.ClearVirtualSpace(); - sel.SetSelection(mainSel); + sel.SetSelection(sel.RangeMain()); Redraw(); } +//-------------------------------------------------------------------------------------------------- + +/** + * Convert virtual space before selection into real space. + */ +void ScintillaCocoa::ConvertSelectionVirtualSpace() +{ + FillVirtualSpace(); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Erase all selected text and return whether the selection is now empty. + * The selection may not be empty if the selection contained protected text. + */ +bool ScintillaCocoa::ClearAllSelections() +{ + ClearSelection(true); + return sel.Empty(); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Start composing for IME. + */ +void ScintillaCocoa::CompositionStart() +{ + if (!sel.Empty()) + { + NSLog(@"Selection not empty when starting composition"); + } + pdoc->TentativeStart(); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Commit the IME text. + */ +void ScintillaCocoa::CompositionCommit() +{ + pdoc->TentativeCommit(); + pdoc->decorations.SetCurrentIndicator(INDIC_IME); + pdoc->DecorationFillRange(0, 0, pdoc->Length()); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Remove the IME text. + */ +void ScintillaCocoa::CompositionUndo() +{ + pdoc->TentativeUndo(); +} + //-------------------------------------------------------------------------------------------------- /** * When switching documents discard any incomplete character composition state as otherwise tries to -- cgit v1.2.3