summaryrefslogtreecommitdiffstats
path: root/scintilla/macosx/ExtInput.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'scintilla/macosx/ExtInput.cxx')
-rw-r--r--scintilla/macosx/ExtInput.cxx608
1 files changed, 608 insertions, 0 deletions
diff --git a/scintilla/macosx/ExtInput.cxx b/scintilla/macosx/ExtInput.cxx
new file mode 100644
index 0000000..a26b487
--- /dev/null
+++ b/scintilla/macosx/ExtInput.cxx
@@ -0,0 +1,608 @@
+/*******************************************************************************
+
+Copyright (c) 2007 Adobe Systems Incorporated
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+********************************************************************************/
+
+#include "ScintillaMacOSX.h"
+#include "ExtInput.h"
+
+using namespace Scintilla;
+
+// uncomment this for a log to /dev/console
+// #define LOG_TSM 1
+
+#if LOG_TSM
+FILE* logFile = NULL;
+#endif
+
+static EventHandlerUPP tsmHandler;
+
+static EventTypeSpec tsmSpecs[] = {
+ { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
+// { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
+ { kEventClassTextInput, kEventTextInputOffsetToPos },
+ { kEventClassTextInput, kEventTextInputPosToOffset },
+ { kEventClassTextInput, kEventTextInputGetSelectedText }
+};
+
+#define kScintillaTSM 'ScTs'
+
+// The following structure is attached to the HIViewRef as property kScintillaTSM
+
+struct TSMData
+{
+ HIViewRef view; // this view
+ TSMDocumentID docid; // the TSM document ID
+ EventHandlerRef handler; // the event handler
+ ScintillaMacOSX* scintilla; // the Scintilla pointer
+ int styleMask; // the document style mask
+ int indicStyle [3]; // indicator styles save
+ int indicColor [3]; // indicator colors save
+ int selStart; // starting position of selection (Scintilla offset)
+ int selLength; // UTF-8 number of characters
+ int selCur; // current position (Scintilla offset)
+ int inhibitRecursion; // true to stop recursion
+ bool active; // true if this is active
+};
+
+static const int numSpecs = 5;
+
+
+// Fetch a range of text as UTF-16; delete the buffer after use
+
+static char* getTextPortion (TSMData* data, UInt32 start, UInt32 size)
+{
+ Scintilla::TextRange range;
+ range.chrg.cpMin = start;
+ range.chrg.cpMax = start + size;
+ range.lpstrText = new char [size + 1];
+ range.lpstrText [size] = 0;
+ data->scintilla->WndProc (SCI_GETTEXTRANGE, 0, (uptr_t) &range);
+ return range.lpstrText;
+}
+
+static pascal OSStatus doHandleTSM (EventHandlerCallRef, EventRef inEvent, void* userData);
+
+void ExtInput::attach (HIViewRef viewRef)
+{
+ if (NULL == tsmHandler)
+ tsmHandler = NewEventHandlerUPP (doHandleTSM);
+ ::UseInputWindow (NULL, FALSE);
+
+#ifdef LOG_TSM
+ if (NULL == logFile)
+ logFile = fopen ("/dev/console", "a");
+#endif
+
+ // create and attach the TSM data
+ TSMData* data = new TSMData;
+
+ data->view = viewRef;
+ data->active = false;
+ data->inhibitRecursion = 0;
+
+ ::GetControlProperty (viewRef, scintillaMacOSType, 0, sizeof( data->scintilla ), NULL, &data->scintilla);
+
+ if (NULL != data->scintilla)
+ {
+ // create the TSM document ref
+ InterfaceTypeList interfaceTypes;
+ interfaceTypes[0] = kUnicodeDocumentInterfaceType;
+ ::NewTSMDocument (1, interfaceTypes, &data->docid, (long) viewRef);
+ // install my event handler
+ ::InstallControlEventHandler (viewRef, tsmHandler, numSpecs, tsmSpecs, data, &data->handler);
+
+ ::SetControlProperty (viewRef, kScintillaTSM, 0, sizeof (data), &data);
+ }
+ else
+ delete data;
+}
+
+static TSMData* getTSMData (HIViewRef viewRef)
+{
+ TSMData* data = NULL;
+ UInt32 n;
+ ::GetControlProperty (viewRef, kScintillaTSM, 0, sizeof (data), &n, (UInt32*) &data);
+ return data;
+}
+
+void ExtInput::detach (HIViewRef viewRef)
+{
+ TSMData* data = getTSMData (viewRef);
+ if (NULL != data)
+ {
+ ::DeleteTSMDocument (data->docid);
+ ::RemoveEventHandler (data->handler);
+ delete data;
+ }
+}
+
+void ExtInput::activate (HIViewRef viewRef, bool on)
+{
+ TSMData* data = getTSMData (viewRef);
+ if (NULL == data)
+ return;
+
+ if (on)
+ {
+ ::ActivateTSMDocument (data->docid);
+ HIRect bounds;
+ ::HIViewGetBounds (viewRef, &bounds);
+ ::HIViewConvertRect (&bounds, viewRef, NULL);
+ RgnHandle hRgn = ::NewRgn();
+ ::SetRectRgn (hRgn, (short) bounds.origin.x, (short) bounds.origin.y,
+ (short) (bounds.origin.x + bounds.size.width),
+ (short) (bounds.origin.y + bounds.size.height));
+#if LOG_TSM
+ fprintf (logFile, "TSMSetInlineInputRegion (%08lX, %ld:%ld-%ld:%ld)\n",
+ (long) data->docid, (long) bounds.origin.x, (long) bounds.origin.y,
+ (long) (bounds.origin.x + bounds.size.width), (long) (bounds.origin.y + bounds.size.height));
+ fflush (logFile);
+#endif
+ ::TSMSetInlineInputRegion (data->docid, HIViewGetWindow (data->view), hRgn);
+ ::DisposeRgn (hRgn);
+ ::UseInputWindow (NULL, FALSE);
+ }
+ else
+ {
+#if LOG_TSM
+ fprintf (logFile, "DeactivateTSMDocument (%08lX)\n", (long) data->docid);
+ fflush (logFile);
+#endif
+ ::DeactivateTSMDocument (data->docid);
+ }
+}
+
+static void startInput (TSMData* data, bool delSelection = true)
+{
+ if (!data->active && 0 == data->inhibitRecursion)
+ {
+ data->active = true;
+
+ // Delete any selection
+ if( delSelection )
+ data->scintilla->WndProc (SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(""));
+
+ // need all style bits because we do indicators
+ data->styleMask = data->scintilla->WndProc (SCI_GETSTYLEBITS, 0, 0);
+ data->scintilla->WndProc (SCI_SETSTYLEBITS, 5, 0);
+
+ // Set the target range for successive replacements
+ data->selStart =
+ data->selCur = data->scintilla->WndProc (SCI_GETCURRENTPOS, 0, 0);
+ data->selLength = 0;
+
+ // save needed styles
+ for (int i = 0; i < 2; i++)
+ {
+ data->indicStyle [i] = data->scintilla->WndProc (SCI_INDICGETSTYLE, i, 0);
+ data->indicColor [i] = data->scintilla->WndProc (SCI_INDICGETFORE, i, 0);
+ }
+ // set styles and colors
+ data->scintilla->WndProc (SCI_INDICSETSTYLE, 0, INDIC_SQUIGGLE);
+ data->scintilla->WndProc (SCI_INDICSETFORE, 0, 0x808080);
+ data->scintilla->WndProc (SCI_INDICSETSTYLE, 1, INDIC_PLAIN); // selected converted
+ data->scintilla->WndProc (SCI_INDICSETFORE, 1, 0x808080);
+ data->scintilla->WndProc (SCI_INDICSETSTYLE, 2, INDIC_PLAIN); // selected raw
+ data->scintilla->WndProc (SCI_INDICSETFORE, 2, 0x0000FF);
+ // stop Undo
+ data->scintilla->WndProc (SCI_BEGINUNDOACTION, 0, 0);
+ }
+}
+
+static void stopInput (TSMData* data, int pos)
+{
+ if (data->active && 0 == data->inhibitRecursion)
+ {
+ // First fix the doc - this may cause more messages
+ // but do not fall into recursion
+ data->inhibitRecursion++;
+ ::FixTSMDocument (data->docid);
+ data->inhibitRecursion--;
+ data->active = false;
+
+ // Remove indicator styles
+ data->scintilla->WndProc (SCI_STARTSTYLING, data->selStart, INDICS_MASK);
+ data->scintilla->WndProc (SCI_SETSTYLING, pos - data->selStart, 0);
+ // Restore old indicator styles and colors
+ data->scintilla->WndProc (SCI_SETSTYLEBITS, data->styleMask, 0);
+ for (int i = 0; i < 2; i++)
+ {
+ data->scintilla->WndProc (SCI_INDICSETSTYLE, i, data->indicStyle [i]);
+ data->scintilla->WndProc (SCI_INDICSETFORE, i, data->indicColor [i]);
+ }
+
+ // remove selection and re-allow selections to display
+ data->scintilla->WndProc (SCI_SETSEL, pos, pos);
+ data->scintilla->WndProc (SCI_TARGETFROMSELECTION, 0, 0);
+ data->scintilla->WndProc (SCI_HIDESELECTION, 0, 0);
+
+ // move the caret behind the current area
+ data->scintilla->WndProc (SCI_SETCURRENTPOS, pos, 0);
+ // re-enable Undo
+ data->scintilla->WndProc (SCI_ENDUNDOACTION, 0, 0);
+ // re-colorize
+ int32_t startLine = data->scintilla->WndProc (SCI_LINEFROMPOSITION, data->selStart, 0);
+ int32_t startPos = data->scintilla->WndProc (SCI_POSITIONFROMLINE, startLine, 0);
+ int32_t endLine = data->scintilla->WndProc (SCI_LINEFROMPOSITION, pos, 0);
+ if (endLine == startLine)
+ endLine++;
+ int32_t endPos = data->scintilla->WndProc (SCI_POSITIONFROMLINE, endLine, 0);
+
+ data->scintilla->WndProc (SCI_COLOURISE, startPos, endPos);
+ }
+}
+
+void ExtInput::stop (HIViewRef viewRef)
+{
+ TSMData* data = getTSMData (viewRef);
+ if (NULL != data)
+ stopInput (data, data->selStart + data->selLength);
+}
+
+static char* UTF16toUTF8 (const UniChar* buf, int len, int& utf8len)
+{
+ CFStringRef str = CFStringCreateWithCharactersNoCopy (NULL, buf, (UInt32) len, kCFAllocatorNull);
+ CFRange range = { 0, len };
+ CFIndex bufLen;
+ CFStringGetBytes (str, range, kCFStringEncodingUTF8, '?', false, NULL, 0, &bufLen);
+ UInt8* utf8buf = new UInt8 [bufLen+1];
+ CFStringGetBytes (str, range, kCFStringEncodingUTF8, '?', false, utf8buf, bufLen, NULL);
+ utf8buf [bufLen] = 0;
+ CFRelease (str);
+ utf8len = (int) bufLen;
+ return (char*) utf8buf;
+}
+
+static int UCS2Length (const char* buf, int len)
+{
+ int n = 0;
+ while (len > 0)
+ {
+ int bytes = 0;
+ char ch = *buf;
+ while (ch & 0x80)
+ bytes++, ch <<= 1;
+ len -= bytes;
+ n += bytes;
+ }
+ return n;
+}
+
+static int UTF8Length (const UniChar* buf, int len)
+{
+ int n = 0;
+ while (len > 0)
+ {
+ UInt32 uch = *buf++;
+ len--;
+ if (uch >= 0xD800 && uch <= 0xDBFF && len > 0)
+ {
+ UInt32 uch2 = *buf;
+ if (uch2 >= 0xDC00 && uch2 <= 0xDFFF)
+ {
+ buf++;
+ len--;
+ uch = ((uch & 0x3FF) << 10) + (uch2 & 0x3FF);
+ }
+ }
+ n++;
+ if (uch > 0x7F)
+ n++;
+ if (uch > 0x7FF)
+ n++;
+ if (uch > 0xFFFF)
+ n++;
+ if (uch > 0x1FFFFF)
+ n++;
+ if (uch > 0x3FFFFFF)
+ n++;
+ }
+ return n;
+}
+
+static OSStatus handleTSMUpdateActiveInputArea (TSMData* data, EventRef inEvent)
+{
+ UInt32 fixLength;
+ int caretPos = -1;
+ UInt32 actualSize;
+ ::TextRangeArray* hiliteRanges = NULL;
+ char* hiliteBuffer = NULL;
+ bool done;
+
+ // extract the text
+ UniChar* buffer = NULL;
+ UniChar temp [128];
+ UniChar* text = temp;
+
+ // get the fix length (in bytes)
+ OSStatus err = ::GetEventParameter (inEvent, kEventParamTextInputSendFixLen,
+ typeLongInteger, NULL, sizeof (long), NULL, &fixLength);
+ // need the size (in bytes)
+ if (noErr == err)
+ err = ::GetEventParameter (inEvent, kEventParamTextInputSendText,
+ typeUnicodeText, NULL, 256, &actualSize, temp);
+
+ // then allocate and fetch if necessary
+ UInt32 textLength = actualSize / sizeof (UniChar);
+ fixLength /= sizeof (UniChar);
+
+ if (noErr == err)
+ {
+ // this indicates that we are completely done
+ done = (fixLength == textLength || fixLength < 0);
+ if (textLength >= 128)
+ {
+ buffer = text = new UniChar [textLength];
+ err = ::GetEventParameter (inEvent, kEventParamTextInputSendText,
+ typeUnicodeText, NULL, actualSize, NULL, (void*) text);
+ }
+
+ // set the text now, but convert it to UTF-8 first
+ int utf8len;
+ char* utf8 = UTF16toUTF8 (text, textLength, utf8len);
+ data->scintilla->WndProc (SCI_SETTARGETSTART, data->selStart, 0);
+ data->scintilla->WndProc (SCI_SETTARGETEND, data->selStart + data->selLength, 0);
+ data->scintilla->WndProc (SCI_HIDESELECTION, 1, 0);
+ data->scintilla->WndProc (SCI_REPLACETARGET, utf8len, (sptr_t) utf8);
+ data->selLength = utf8len;
+ delete [] utf8;
+ }
+
+ // attempt to extract the array of hilite ranges
+ if (noErr == err)
+ {
+ ::TextRangeArray tempTextRangeArray;
+ OSStatus tempErr = ::GetEventParameter (inEvent, kEventParamTextInputSendHiliteRng,
+ typeTextRangeArray, NULL, sizeof (::TextRangeArray), &actualSize, &tempTextRangeArray);
+ if (noErr == tempErr)
+ {
+ // allocate memory and get the stuff!
+ hiliteBuffer = new char [actualSize];
+ hiliteRanges = (::TextRangeArray*) hiliteBuffer;
+ err = ::GetEventParameter (inEvent, kEventParamTextInputSendHiliteRng,
+ typeTextRangeArray, NULL, actualSize, NULL, hiliteRanges);
+ if (noErr != err)
+ {
+ delete [] hiliteBuffer;
+ hiliteBuffer = NULL;
+ hiliteRanges = NULL;
+ }
+ }
+ }
+#if LOG_TSM
+ fprintf (logFile, "kEventTextInputUpdateActiveInputArea:\n"
+ " TextLength = %ld\n"
+ " FixLength = %ld\n",
+ (long) textLength, (long) fixLength);
+ fflush (logFile);
+#endif
+
+ if (NULL != hiliteRanges)
+ {
+ for (int i = 0; i < hiliteRanges->fNumOfRanges; i++)
+ {
+#if LOG_TSM
+ fprintf (logFile, " Range #%d: %ld-%ld (%d)\n",
+ i+1,
+ hiliteRanges->fRange[i].fStart,
+ hiliteRanges->fRange[i].fEnd,
+ hiliteRanges->fRange[i].fHiliteStyle);
+ fflush (logFile);
+#endif
+ // start and end of range, zero based
+ long bgn = long (hiliteRanges->fRange[i].fStart) / sizeof (UniChar);
+ long end = long (hiliteRanges->fRange[i].fEnd) / sizeof (UniChar);
+ if (bgn >= 0 && end >= 0)
+ {
+ // move the caret if this is requested
+ if (hiliteRanges->fRange[i].fHiliteStyle == kTSMHiliteCaretPosition)
+ caretPos = bgn;
+ else
+ {
+ // determine which style to use
+ int style;
+ switch (hiliteRanges->fRange[i].fHiliteStyle)
+ {
+ case kTSMHiliteRawText: style = INDIC0_MASK; break;
+ case kTSMHiliteSelectedRawText: style = INDIC0_MASK; break;
+ case kTSMHiliteConvertedText: style = INDIC1_MASK; break;
+ case kTSMHiliteSelectedConvertedText: style = INDIC2_MASK; break;
+ default: style = INDIC0_MASK;
+ }
+ // bgn and end are Unicode offsets from the starting pos
+ // use the text buffer to determine the UTF-8 offsets
+ long utf8bgn = data->selStart + UTF8Length (text, bgn);
+ long utf8size = UTF8Length (text + bgn, end - bgn);
+ // set indicators
+ int oldEnd = data->scintilla->WndProc (SCI_GETENDSTYLED, 0, 0);
+ data->scintilla->WndProc (SCI_STARTSTYLING, utf8bgn, INDICS_MASK);
+ data->scintilla->WndProc (SCI_SETSTYLING, utf8size, style & ~1);
+ data->scintilla->WndProc (SCI_STARTSTYLING, oldEnd, 31);
+ }
+ }
+ }
+ }
+ if (noErr == err)
+ {
+ // if the fixed length is == to the new text, we are done
+ if (done)
+ stopInput (data, data->selStart + UTF8Length (text, textLength));
+ else if (caretPos >= 0)
+ {
+ data->selCur = data->selStart + UTF8Length (text, caretPos);
+ data->scintilla->WndProc (SCI_SETCURRENTPOS, data->selCur, 0);
+ }
+ }
+
+ delete [] hiliteBuffer;
+ delete [] buffer;
+ return err;
+}
+
+struct MacPoint {
+ short v;
+ short h;
+};
+
+static OSErr handleTSMOffset2Pos (TSMData* data, EventRef inEvent)
+{
+ long offset;
+
+ // get the offfset to convert
+ OSStatus err = ::GetEventParameter (inEvent, kEventParamTextInputSendTextOffset,
+ typeLongInteger, NULL, sizeof (long), NULL, &offset);
+ if (noErr == err)
+ {
+ // where is the caret now?
+ HIPoint where;
+
+ int line = (int) data->scintilla->WndProc (SCI_LINEFROMPOSITION, data->selCur, 0);
+ where.x = data->scintilla->WndProc (SCI_POINTXFROMPOSITION, 0, data->selCur);
+ where.y = data->scintilla->WndProc (SCI_POINTYFROMPOSITION, 0, data->selCur)
+ + data->scintilla->WndProc (SCI_TEXTHEIGHT, line, 0);
+ // convert to window coords
+ ::HIViewConvertPoint (&where, data->view, NULL);
+ // convert to screen coords
+ Rect global;
+ GetWindowBounds (HIViewGetWindow (data->view), kWindowStructureRgn, &global);
+ MacPoint pt;
+ pt.h = (short) where.x + global.left;
+ pt.v = (short) where.y + global.top;
+
+ // set the result
+ err = ::SetEventParameter (inEvent, kEventParamTextInputReplyPoint, typeQDPoint, sizeof (MacPoint), &pt);
+#if LOG_TSM
+ fprintf (logFile, "kEventTextInputOffsetToPos:\n"
+ " Offset: %ld\n"
+ " Pos: %ld:%ld (orig = %ld:%ld)\n", offset,
+ (long) pt.h, (long) pt.v,
+ (long) where.x, (long) where.y);
+ fflush (logFile);
+#endif
+ }
+ return err;
+}
+
+static OSErr handleTSMPos2Offset (TSMData* data, EventRef inEvent)
+{
+ MacPoint qdPosition;
+ long offset;
+ short regionClass;
+
+ // retrieve the global point to convert
+ OSStatus err = ::GetEventParameter (inEvent, kEventParamTextInputSendCurrentPoint,
+ typeQDPoint, NULL, sizeof (MacPoint), NULL, &qdPosition);
+ if (noErr == err)
+ {
+#if LOG_TSM
+ fprintf (logFile, "kEventTextInputPosToOffset:\n"
+ " Pos: %ld:%ld\n", (long) qdPosition.v, (long) qdPosition.h);
+ fflush (logFile);
+#endif
+ // convert to local coordinates
+ HIRect rect;
+ rect.origin.x = qdPosition.h;
+ rect.origin.y = qdPosition.v;
+ rect.size.width =
+ rect.size.height = 1;
+ ::HIViewConvertRect (&rect, NULL, data->view);
+
+ // we always report the position to be within the composition;
+ // coords inside the same pane are clipped to the composition,
+ // and if the position is outside, then we deactivate this instance
+ // this leaves the edit open and active so we can edit multiple panes
+ regionClass = kTSMInsideOfActiveInputArea;
+
+ // compute the offset (relative value)
+ offset = data->scintilla->WndProc (SCI_POSITIONFROMPOINTCLOSE, (uptr_t) rect.origin.x, (sptr_t) rect.origin.y);
+ if (offset >= 0)
+ {
+ // convert to a UTF-16 offset (Brute Force)
+ char* buf = getTextPortion (data, 0, offset);
+ offset = UCS2Length (buf, offset);
+ delete [] buf;
+
+#if LOG_TSM
+ fprintf (logFile, " Offset: %ld (class %ld)\n", offset, (long) regionClass);
+ fflush (logFile);
+#endif
+ // store the offset
+ err = ::SetEventParameter (inEvent, kEventParamTextInputReplyTextOffset, typeLongInteger, sizeof (long), &offset);
+ if (noErr == err)
+ err = ::SetEventParameter (inEvent, kEventParamTextInputReplyRegionClass, typeShortInteger, sizeof (short), &regionClass);
+ }
+ else
+ {
+ // not this pane!
+ err = eventNotHandledErr;
+ ExtInput::activate (data->view, false);
+ }
+
+ }
+ return err;
+}
+
+static OSErr handleTSMGetText (TSMData* data, EventRef inEvent)
+{
+ char* buf = getTextPortion (data, data->selStart, data->selLength);
+
+#if LOG_TSM
+ fprintf (logFile, "kEventTextInputGetSelectedText:\n"
+ " Text: \"%s\"\n", buf);
+ fflush (logFile);
+#endif
+ OSStatus status = ::SetEventParameter (inEvent, kEventParamTextInputReplyText, typeUTF8Text, data->selLength, buf);
+ delete [] buf;
+ return status;
+}
+
+static pascal OSStatus doHandleTSM (EventHandlerCallRef, EventRef inEvent, void* userData)
+{
+ TSMData* data = (TSMData*) userData;
+
+ OSStatus err = eventNotHandledErr;
+
+ switch (::GetEventKind (inEvent))
+ {
+ case kEventTextInputUpdateActiveInputArea:
+ // Make sure that input has been started
+ startInput (data);
+ err = handleTSMUpdateActiveInputArea (data, inEvent);
+ break;
+// case kEventTextInputUnicodeForKeyEvent:
+// err = handleTSMUnicodeInput (inEvent);
+// break;
+ case kEventTextInputOffsetToPos:
+ err = handleTSMOffset2Pos (data, inEvent);
+ break;
+ case kEventTextInputPosToOffset:
+ err = handleTSMPos2Offset (data, inEvent);
+ break;
+ case kEventTextInputGetSelectedText:
+ // Make sure that input has been started
+ startInput (data, false);
+ err = handleTSMGetText (data, inEvent);
+ break;
+ }
+ return err;
+}
+