summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeenz <geenz@geenzo.com>2013-03-25 05:26:55 -0400
committerGeenz <geenz@geenzo.com>2013-03-25 05:26:55 -0400
commit258b77b64777a5ce5fef0ef066aa52b34b43ba65 (patch)
treea36e8ecdea32a932c74dde044336014f63368d7a
parent6c200a94f705667201bcaf0753986da90a2748eb (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.cpp1
-rw-r--r--indra/llwindow/llopenglview-objc.h4
-rw-r--r--indra/llwindow/llopenglview-objc.mm97
-rw-r--r--indra/llwindow/llwindowmacosx-objc.h11
-rw-r--r--indra/llwindow/llwindowmacosx-objc.mm45
-rw-r--r--indra/llwindow/llwindowmacosx.cpp126
-rw-r--r--indra/newview/Info-SecondLife.plist2
-rw-r--r--indra/newview/llviewerkeyboard.cpp1
-rwxr-xr-xindra/newview/llviewerwindow.cpp1
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();