Additional IME support. LLPreeditor is largely good to go at this point, but there's still some work to do in getSegments.
parent
6c200a94f7
commit
258b77b647
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue