Additional IME support. LLPreeditor is largely good to go at this point, but there's still some work to do in getSegments.

master
Geenz 2013-03-25 05:26:55 -04:00
parent 6c200a94f7
commit 258b77b647
9 changed files with 254 additions and 38 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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]);
}
- (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

View File

@ -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();

View File

@ -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)

View File

@ -381,17 +381,6 @@ void callQuitHandler()
}
}
std::basic_string<wchar_t> getPreeditString()
{
std::basic_string<wchar_t> str;
if (gWindowImplementation->getPreeditor())
{
str = gWindowImplementation->getPreeditor()->getPreeditString();
}
return str;
}
void getPreeditSelectionRange(int *position, int *length)
{
if (gWindowImplementation->getPreeditor())
@ -408,6 +397,14 @@ void getPreeditMarkedRange(int *position, int *length)
}
}
void setPreeditMarkedRange(int position, int length)
{
if (gWindowImplementation->getPreeditor())
{
gWindowImplementation->getPreeditor()->markAsPreedit(position, length);
}
}
void handleUnicodeCharacter(wchar_t c)
{
if (gWindowImplementation->getPreeditor())
@ -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()

View File

@ -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>

View File

@ -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;

View File

@ -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();