diff options
author | Geenz <geenz@geenzo.com> | 2013-03-25 05:26:55 -0400 |
---|---|---|
committer | Geenz <geenz@geenzo.com> | 2013-03-25 05:26:55 -0400 |
commit | 258b77b64777a5ce5fef0ef066aa52b34b43ba65 (patch) | |
tree | a36e8ecdea32a932c74dde044336014f63368d7a | |
parent | 6c200a94f705667201bcaf0753986da90a2748eb (diff) |
Additional IME support. LLPreeditor is largely good to go at this point, but there's still some work to do in getSegments.
-rw-r--r-- | indra/llwindow/llkeyboardmacosx.cpp | 1 | ||||
-rw-r--r-- | indra/llwindow/llopenglview-objc.h | 4 | ||||
-rw-r--r-- | indra/llwindow/llopenglview-objc.mm | 97 | ||||
-rw-r--r-- | indra/llwindow/llwindowmacosx-objc.h | 11 | ||||
-rw-r--r-- | indra/llwindow/llwindowmacosx-objc.mm | 45 | ||||
-rw-r--r-- | indra/llwindow/llwindowmacosx.cpp | 126 | ||||
-rw-r--r-- | indra/newview/Info-SecondLife.plist | 2 | ||||
-rw-r--r-- | indra/newview/llviewerkeyboard.cpp | 1 | ||||
-rwxr-xr-x | indra/newview/llviewerwindow.cpp | 1 |
9 files changed, 252 insertions, 36 deletions
diff --git a/indra/llwindow/llkeyboardmacosx.cpp b/indra/llwindow/llkeyboardmacosx.cpp index 274e92c225..85bb7b9aeb 100644 --- a/indra/llwindow/llkeyboardmacosx.cpp +++ b/indra/llwindow/llkeyboardmacosx.cpp @@ -253,7 +253,6 @@ BOOL LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) if(translateNumpadKey(key, &translated_key)) { - LL_INFOS("Keyboard") << "Handled key!" << LL_ENDL; handled = handleTranslatedKeyUp(translated_key, translated_mask); } diff --git a/indra/llwindow/llopenglview-objc.h b/indra/llwindow/llopenglview-objc.h index 5134063193..8140421e44 100644 --- a/indra/llwindow/llopenglview-objc.h +++ b/indra/llwindow/llopenglview-objc.h @@ -20,6 +20,8 @@ std::string mLastDraggedUrl; unsigned int mModifiers; float mMousePos[2]; + bool mHasMarkedText; + unsigned int mMarkedTextLength; } - (id) initWithSamples:(NSUInteger)samples; - (id) initWithSamples:(NSUInteger)samples andVsync:(BOOL)vsync; @@ -40,6 +42,8 @@ - (unsigned long) getVramSize; +- (segment_t) getSegments:(NSAttributedString*)str; + @end @interface LLNSWindow : NSWindow diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index de159816e0..31b0e02ad8 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -281,15 +281,18 @@ - (void) keyDown:(NSEvent *)theEvent { [[self inputContext] handleEvent:theEvent]; - uint keycode = [theEvent keyCode]; - callKeyDown(keycode, mModifiers); - - // OS X intentionally does not send us key-up information on cmd-key combinations. - // This behaviour is not a bug, and only applies to cmd-combinations (no others). - // Since SL assumes we receive those, we fake it here. - if (mModifiers & NSCommandKeyMask) + if (!mHasMarkedText) { - callKeyUp([theEvent keyCode], mModifiers); + uint keycode = [theEvent keyCode]; + callKeyDown(keycode, mModifiers); + + // OS X intentionally does not send us key-up information on cmd-key combinations. + // This behaviour is not a bug, and only applies to cmd-combinations (no others). + // Since SL assumes we receive those, we fake it here. + if (mModifiers & NSCommandKeyMask) + { + callKeyUp([theEvent keyCode], mModifiers); + } } } @@ -348,7 +351,7 @@ - (BOOL)hasMarkedText { - return NO; + return mHasMarkedText; } - (NSRange)markedRange @@ -365,21 +368,73 @@ return NSMakeRange(range[0], range[1]); } -- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange +- (segment_t) getSegments:(NSAttributedString*)str { + segment_t segments; + + int segment = 0; + + NSRange l; + NSRange r = NSMakeRange(0, [str length]); + + while (r.length > 0) + { + NSNumber *segmentAttrib = [str attribute:NSUnderlineStyleAttributeName atIndex:r.location longestEffectiveRange:&l inRange:r]; + + r = NSMakeRange(NSMaxRange(l), NSMaxRange(r) - NSMaxRange(l)); + bool standout; + if ([segmentAttrib integerValue] == 1) + { + standout = false; + } else { + standout = true; + } + segments.insert(std::pair<int, bool>(l.length, standout)); + + segment++; + } + return segments; +} + +- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange +{ + if ([aString class] == NSClassFromString(@"NSConcreteMutableAttributedString")) + { + unsigned int selected[2] = { + selectedRange.location, + selectedRange.length + }; + + unsigned int replacement[2] = { + replacementRange.location, + replacementRange.length + }; + + NSLog(@"Attributed string: %@", aString); + + unichar text[[aString length]]; + [[aString mutableString] getCharacters:text range:NSMakeRange(0, [aString length])]; + segment_t segments = [self getSegments:(NSAttributedString *)aString]; + setMarkedText(text, selected, replacement, [aString length], segments); + mHasMarkedText = TRUE; + mMarkedTextLength = [aString length]; + } } - (void)unmarkText { - + resetPreedit(); + mHasMarkedText = FALSE; } +// We don't support attributed strings. - (NSArray *)validAttributesForMarkedText { return [NSArray array]; } +// See above. - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { return nil; @@ -387,9 +442,21 @@ - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange { - for (NSInteger i = 0; i < [aString length]; i++) + if (!mHasMarkedText) { - callUnicodeCallback([aString characterAtIndex:i], mModifiers); + for (NSInteger i = 0; i < [aString length]; i++) + { + callUnicodeCallback([aString characterAtIndex:i], mModifiers); + } + } else { + // We may never get this point since unmarkText may be called before insertText ever gets called once we submit our text. + // But just in case... + resetPreedit(); + for (NSInteger i = 0; i < [aString length]; i++) + { + handleUnicodeCharacter([aString characterAtIndex:i]); + } + mHasMarkedText = FALSE; } } @@ -412,7 +479,9 @@ - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { - return NSZeroRect; + float pos[4] = {0, 0, 0, 0}; + getPreeditLocation(pos, mMarkedTextLength); + return NSMakeRect(pos[0], pos[1], pos[2], pos[3]); } - (void)doCommandBySelector:(SEL)aSelector diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index 57bb071690..2de185fed3 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -25,6 +25,10 @@ * $/LicenseInfo$ */ +#include <map> + +typedef std::map<int, bool> segment_t; + // This will actually hold an NSCursor*, but that type is only available in objective C. typedef void *CursorRef; typedef void *NSWindowRef; @@ -71,6 +75,8 @@ void makeWindowOrderFront(NSWindowRef window); void convertScreenToWindow(NSWindowRef window, float *coord); void convertWindowToScreen(NSWindowRef window, float *coord); void convertScreenToView(NSWindowRef window, float *coord); +void convertRectToScreen(NSWindowRef window, float *coord); +void convertRectFromScreen(NSWindowRef window, float *coord); void setWindowPos(NSWindowRef window, float* pos); void closeWindow(NSWindowRef window); void removeGLView(GLViewRef view); @@ -113,6 +119,11 @@ void getPreeditSelectionRange(int *position, int *length); void getPreeditMarkedRange(int *position, int *length); void handleUnicodeCharacter(wchar_t c); void updatePreeditor(unsigned short *str); +void setPreeditMarkedRange(int position, int length); +void resetPreedit(); +int wstring_length(const std::basic_string<wchar_t> & wstr, const int woffset, const int utf16_length, int *unaligned); +void setMarkedText(unsigned short *text, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, segment_t segments); +void getPreeditLocation(float *location, unsigned int length); NSWindowRef getMainAppWindow(); GLViewRef getGLView(); diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 9530785b83..1a0647485c 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -119,6 +119,7 @@ CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY) void setArrowCursor() { NSCursor *cursor = [NSCursor arrowCursor]; + [NSCursor unhide]; [cursor set]; } @@ -290,12 +291,44 @@ void makeWindowOrderFront(NSWindowRef window) void convertScreenToWindow(NSWindowRef window, float *coord) { - NSPoint point; - point.x = coord[0]; - point.y = coord[1]; - point = [(LLNSWindow*)window convertScreenToBase:point]; - coord[0] = point.x; - coord[1] = point.y; + NSRect point; + point.origin.x = coord[0]; + point.origin.y = coord[1]; + point = [(LLNSWindow*)window convertRectFromScreen:point]; + coord[0] = point.origin.x; + coord[1] = point.origin.y; +} + +void convertRectToScreen(NSWindowRef window, float *coord) +{ + NSRect point; + point.origin.x = coord[0]; + point.origin.y = coord[1]; + point.size.width = coord[2]; + point.size.height = coord[3]; + + point = [(LLNSWindow*)window convertRectToScreen:point]; + + coord[0] = point.origin.x; + coord[1] = point.origin.y; + coord[2] = point.size.width; + coord[3] = point.size.height; +} + +void convertRectFromScreen(NSWindowRef window, float *coord) +{ + NSRect point; + point.origin.x = coord[0]; + point.origin.y = coord[1]; + point.size.width = coord[2]; + point.size.height = coord[3]; + + point = [(LLNSWindow*)window convertRectFromScreen:point]; + + coord[0] = point.origin.x; + coord[1] = point.origin.y; + coord[2] = point.size.width; + coord[3] = point.size.height; } void convertScreenToView(NSWindowRef window, float *coord) diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 7e4b9a84a1..4e8934b149 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -381,30 +381,27 @@ void callQuitHandler() } } -std::basic_string<wchar_t> getPreeditString() +void getPreeditSelectionRange(int *position, int *length) { - std::basic_string<wchar_t> str; if (gWindowImplementation->getPreeditor()) { - str = gWindowImplementation->getPreeditor()->getPreeditString(); + gWindowImplementation->getPreeditor()->getSelectionRange(position, length); } - - return str; } -void getPreeditSelectionRange(int *position, int *length) +void getPreeditMarkedRange(int *position, int *length) { if (gWindowImplementation->getPreeditor()) { - gWindowImplementation->getPreeditor()->getSelectionRange(position, length); + gWindowImplementation->getPreeditor()->getPreeditRange(position, length); } } -void getPreeditMarkedRange(int *position, int *length) +void setPreeditMarkedRange(int position, int length) { if (gWindowImplementation->getPreeditor()) { - gWindowImplementation->getPreeditor()->getPreeditRange(position, length); + gWindowImplementation->getPreeditor()->markAsPreedit(position, length); } } @@ -416,6 +413,69 @@ void handleUnicodeCharacter(wchar_t c) } } +void resetPreedit() +{ + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->resetPreedit(); + } +} + +// For reasons of convenience, handle IME updates here. +// This largely mirrors the old implementation, only sans the carbon parameters. +void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, segment_t segments) +{ + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + + // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter. + if (replacementRange[0] < replacementRange[1]) + { + const LLWString& text = preeditor->getPreeditString(); + const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]); + const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]); + preeditor->markAsPreedit(location, length); + } + + preeditor->resetPreedit(); + + LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len)); + + LLPreeditor::segment_lengths_t preedit_segment_lengths; + LLPreeditor::standouts_t preedit_standouts; + S32 caret_position = fix_str.length(); + + for (segment_t::iterator i = segments.begin(); i != segments.end(); i++) + { + preedit_segment_lengths.push_back(i->first); + preedit_standouts.push_back(i->second); + } + + preeditor->updatePreedit(fix_str, preedit_segment_lengths, preedit_standouts, caret_position); + } +} + +void getPreeditLocation(float *location, unsigned int length) +{ + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + LLCoordGL coord; + LLCoordScreen screen; + LLRect rect; + + preeditor->getPreeditLocation(length, &coord, &rect, NULL); + + float c[4] = {coord.mX, coord.mY, 0, 0}; + + convertRectToScreen(gWindowImplementation->getWindow(), c); + + location[0] = c[0]; + location[1] = c[1]; + } +} + void LLWindowMacOSX::updateMouseDeltas(float* deltas) { if (mCursorDecoupled) @@ -1295,8 +1355,22 @@ BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) { LLCoordWindow window_coord; + if (mFullscreen) + { + to->mX = from.mX; + to->mY = from.mY; + return TRUE; + } else if (mWindow) + { + convertCoords(from, &window_coord); + convertCoords(window_coord, to); + + LL_INFOS("Coords") << to->mX << ", " << to->mY << LL_ENDL; + + return TRUE; + } - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return FALSE; } @@ -1425,7 +1499,7 @@ void LLWindowMacOSX::updateCursor() // Find out what they look like and replicate them. // These are essentially correct - case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. */ break; + case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break; case UI_CURSOR_IBEAM: setIBeamCursor(); break; case UI_CURSOR_CROSS: setCrossCursor(); break; case UI_CURSOR_HAND: setPointingHandCursor(); break; @@ -1810,7 +1884,35 @@ static long getDictLong (CFDictionaryRef refDict, CFStringRef key) void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) { - // TODO: IME support + if (preeditor != mPreeditor && !b) + { + // This condition may occur by a call to + // setEnabled(BOOL) against LLTextEditor or LLLineEditor + // when the control is not focused. + // We need to silently ignore the case so that + // the language input status of the focused control + // is not disturbed. + return; + } + + // Take care of old and new preeditors. + if (preeditor != mPreeditor || !b) + { + // We need to interrupt before updating mPreeditor, + // so that the fix string from input method goes to + // the old preeditor. + if (mLanguageTextInputAllowed) + { + interruptLanguageTextInput(); + } + mPreeditor = (b ? preeditor : NULL); + } + + if (b == mLanguageTextInputAllowed) + { + return; + } + mLanguageTextInputAllowed = b; } void LLWindowMacOSX::interruptLanguageTextInput() diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist index 5db52f040f..8fb4e88bc3 100644 --- a/indra/newview/Info-SecondLife.plist +++ b/indra/newview/Info-SecondLife.plist @@ -13,7 +13,7 @@ <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> - <string>Second Life</string> + <string>SecondLife</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleSignature</key> diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp index 92d8f2937e..f3b7c0fad4 100644 --- a/indra/newview/llviewerkeyboard.cpp +++ b/indra/newview/llviewerkeyboard.cpp @@ -653,7 +653,6 @@ BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode) BOOL LLViewerKeyboard::handleKey(KEY translated_key, MASK translated_mask, BOOL repeated) { - LL_INFOS("Keyboard Handling") << "Handling key " << translated_key << LL_ENDL; // check for re-map EKeyboardMode mode = gViewerKeyboard.getMode(); U32 keyidx = (translated_mask<<16) | translated_key; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ccaa9245cf..48a69129eb 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2429,7 +2429,6 @@ void LLViewerWindow::draw() // Takes a single keydown event, usually when UI is visible BOOL LLViewerWindow::handleKey(KEY key, MASK mask) { - LL_INFOS("Keyboard Handling") << "Handling key " << key << LL_ENDL; // hide tooltips on keypress LLToolTipMgr::instance().blockToolTips(); |