diff options
author | Tasuku Suzuki <tasuku.suzuki@nokia.com> | 2012-02-29 13:32:20 +0900 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-03-12 21:38:51 +0100 |
commit | 412dbdf410c765e75c60d1f48143dd6c02a69493 (patch) | |
tree | 565cfebe0ad28bc378479093ae84e54e464a3764 /src/plugins/platforms/cocoa/qnsview.mm | |
parent | 01e8e9136dfa5d3260de0d318da6aece7214f85a (diff) |
Input method on Mac
Restore input method implimentation in Qt4
Task-number: QTBUG-23867
Change-Id: I5d405ccc8b0a73c399d992f6474a0cc38d191157
Reviewed-by: Morten Johan Sørvig <morten.sorvig@nokia.com>
Diffstat (limited to 'src/plugins/platforms/cocoa/qnsview.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.mm | 233 |
1 files changed, 229 insertions, 4 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 9ed3332ba5..6206d53423 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -51,6 +51,7 @@ #include "qcocoadrag.h" #include <QtGui/QWindowSystemInterface> +#include <QtGui/QTextFormat> #include <QtCore/QDebug> #ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR @@ -94,6 +95,7 @@ static QTouchDevice *touchDevice = 0; m_window = window; m_platformWindow = platformWindow; m_accessibleRoot = 0; + m_keyEventsAccepted = false; #ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR // prevent rift in space-time continuum, disable @@ -272,8 +274,15 @@ static QTouchDevice *touchDevice = 0; - (void)mouseDown:(NSEvent *)theEvent { - m_buttons |= Qt::LeftButton; - [self handleMouseEvent:theEvent]; + if ([self hasMarkedText]) { + NSInputManager* inputManager = [NSInputManager currentInputManager]; + if ([inputManager wantsToHandleMouseEvents]) { + [inputManager handleMouseEvent:theEvent]; + } + } else { + m_buttons |= Qt::LeftButton; + [self handleMouseEvent:theEvent]; + } } - (void)mouseDragged:(NSEvent *)theEvent @@ -467,12 +476,228 @@ static QTouchDevice *touchDevice = 0; - (void)keyDown:(NSEvent *)theEvent { - [self handleKeyEvent : theEvent eventType :int(QEvent::KeyPress)]; + QObject *fo = QGuiApplication::focusObject(); + m_keyEventsAccepted = false; + if (fo) { + QInputMethodQueryEvent queryEvent(Qt::ImHints); + if (QCoreApplication::sendEvent(fo, &queryEvent)) { + Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt()); + if (!(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || hints & Qt::ImhHiddenText)) { + [self interpretKeyEvents:[NSArray arrayWithObject: theEvent]]; + } + } + } + + if (!m_keyEventsAccepted && m_composingText.isEmpty()) { + [self handleKeyEvent : theEvent eventType :int(QEvent::KeyPress)]; + } } - (void)keyUp:(NSEvent *)theEvent { - [self handleKeyEvent : theEvent eventType :int(QEvent::KeyRelease)]; + if (!m_keyEventsAccepted && m_composingText.isEmpty()) { + [self handleKeyEvent : theEvent eventType :int(QEvent::KeyRelease)]; + } +} + +- (void) doCommandBySelector:(SEL)aSelector +{ + [self tryToPerform:aSelector with:self]; +} + +- (void) insertText:(id)aString +{ + QString commitString; + if ([aString length]) { + if ([aString isKindOfClass:[NSAttributedString class]]) { + commitString = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string])); + } else { + commitString = QCFString::toQString(reinterpret_cast<CFStringRef>(aString)); + }; + } + QObject *fo = QGuiApplication::focusObject(); + if (fo) { + QInputMethodEvent e; + e.setCommitString(commitString); + QCoreApplication::sendEvent(fo, &e); + m_keyEventsAccepted = true; + } + + m_composingText.clear(); + } + +- (void) setMarkedText:(id)aString selectedRange:(NSRange)selRange +{ + QString preeditString; + + QList<QInputMethodEvent::Attribute> attrs; + attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, selRange.location + selRange.length, 1, QVariant()); + + if ([aString isKindOfClass:[NSAttributedString class]]) { + // Preedit string has attribution + preeditString = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string])); + int composingLength = preeditString.length(); + int index = 0; + // Create attributes for individual sections of preedit text + while (index < composingLength) { + NSRange effectiveRange; + NSRange range = NSMakeRange(index, composingLength-index); + NSDictionary *attributes = [aString attributesAtIndex:index + longestEffectiveRange:&effectiveRange + inRange:range]; + NSNumber *underlineStyle = [attributes objectForKey:NSUnderlineStyleAttributeName]; + if (underlineStyle) { + QColor clr (Qt::black); + NSColor *color = [attributes objectForKey:NSUnderlineColorAttributeName]; + if (color) { + clr = qt_mac_toQColor(color); + } + QTextCharFormat format; + format.setFontUnderline(true); + format.setUnderlineColor(clr); + attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, + effectiveRange.location, + effectiveRange.length, + format); + } + index = effectiveRange.location + effectiveRange.length; + } + } else { + // No attributes specified, take only the preedit text. + preeditString = QCFString::toQString(reinterpret_cast<CFStringRef>(aString)); + } + + if (attrs.isEmpty()) { + QTextCharFormat format; + format.setFontUnderline(true); + attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, + 0, preeditString.length(), format); + } + + m_composingText = preeditString; + + QObject *fo = QGuiApplication::focusObject(); + if (fo) { + QInputMethodEvent e(preeditString, attrs); + QCoreApplication::sendEvent(fo, &e); + m_keyEventsAccepted = true; + } +} + +- (void) unmarkText +{ + if (!m_composingText.isEmpty()) { + QObject *fo = QGuiApplication::focusObject(); + if (fo) { + QInputMethodEvent e; + e.setCommitString(m_composingText); + QCoreApplication::sendEvent(fo, &e); + } + } + m_composingText.clear(); +} + +- (BOOL) hasMarkedText +{ + return (m_composingText.isEmpty() ? NO: YES); +} + +- (NSInteger) conversationIdentifier +{ + return (NSInteger)self; +} + +- (NSAttributedString *) attributedSubstringFromRange:(NSRange)theRange +{ + QObject *fo = QGuiApplication::focusObject(); + if (!fo) + return nil; + QInputMethodQueryEvent queryEvent(Qt::ImCurrentSelection); + if (!QCoreApplication::sendEvent(fo, &queryEvent)) + return nil; + + QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString(); + if (selectedText.isEmpty()) + return nil; + + QCFString string(selectedText.mid(theRange.location, theRange.length)); + const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string); + return [[[NSAttributedString alloc] initWithString:const_cast<NSString *>(tmpString)] autorelease]; +} + +- (NSRange) markedRange +{ + NSRange range; + if (!m_composingText.isEmpty()) { + range.location = 0; + range.length = m_composingText.length(); + } else { + range.location = NSNotFound; + range.length = 0; + } + return range; +} + + +- (NSRange) selectedRange +{ + NSRange selRange = {NSNotFound, 0}; + selRange.location = NSNotFound; + selRange.length = 0; + + QObject *fo = QGuiApplication::focusObject(); + if (!fo) + return selRange; + QInputMethodQueryEvent queryEvent(Qt::ImCurrentSelection); + if (!QCoreApplication::sendEvent(fo, &queryEvent)) + return selRange; + QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString(); + + if (!selectedText.isEmpty()) { + selRange.location = 0; + selRange.length = selectedText.length(); + } + return selRange; +} + +- (NSRect) firstRectForCharacterRange:(NSRange)theRange +{ + Q_UNUSED(theRange); + QObject *fo = QGuiApplication::focusObject(); + if (!fo) + return NSZeroRect; + + if (!m_window) + return NSZeroRect; + + // The returned rect is always based on the internal cursor. + QRect mr = qApp->inputMethod()->cursorRectangle().toRect(); + QPoint mp = m_window->mapToGlobal(mr.bottomLeft()); + + NSRect rect; + rect.origin.x = mp.x(); + rect.origin.y = qt_mac_flipYCoordinate(mp.y()); + rect.size.width = mr.width(); + rect.size.height = mr.height(); + return rect; +} + +- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint +{ + // We dont support cursor movements using mouse while composing. + Q_UNUSED(thePoint); + return NSNotFound; +} + +- (NSArray*) validAttributesForMarkedText +{ + QObject *fo = QGuiApplication::focusObject(); + if (!fo) + return nil; + + // Support only underline color/style. + return [NSArray arrayWithObjects:NSUnderlineColorAttributeName, + NSUnderlineStyleAttributeName, nil]; } -(void)registerDragTypes |