Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qcocoainputcontext.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <AppKit/AppKit.h>
6
7#include "qnsview.h"
10#include "qcocoawindow.h"
11#include "qcocoahelpers.h"
12
13#include <Carbon/Carbon.h>
14
15#include <QtCore/QRect>
16#include <QtGui/QGuiApplication>
17#include <QtGui/QWindow>
18
19QT_BEGIN_NAMESPACE
20
21/*!
22 \class QCocoaInputContext
23 \brief Cocoa Input context implementation
24
25 Handles input of languages that support character composition,
26 for example East Asian languages.
27
28 \section1 Testing
29
30 \list
31 \o Select input sources like 'Kotoeri' in Language & Text Preferences
32 \o Compile the \a mainwindows/mdi example and open a text window.
33 \o In the language bar, switch to 'Hiragana'.
34 \o In a text editor control, type the syllable \a 'la'.
35 Underlined characters show up, indicating that there is completion
36 available. Press the Space key two times. A completion popup occurs
37 which shows the options.
38 \endlist
39
40 \section1 Interaction
41
42 Input method support in Cocoa is based on the NSTextInputClient protocol,
43 therefore almost all functionality is in QNSView (qnsview_complextext.mm).
44*/
45
46QCocoaInputContext::QCocoaInputContext()
47 : QPlatformInputContext()
48 , m_focusWindow(QGuiApplication::focusWindow())
49{
50 m_inputSourceObserver = QMacNotificationObserver(nil,
51 NSTextInputContextKeyboardSelectionDidChangeNotification, [&]() {
52 qCDebug(lcQpaInputMethods) << "Text input source changed";
53 updateLocale();
54 });
55
56 updateLocale();
57}
58
59QCocoaInputContext::~QCocoaInputContext()
60{
61}
62
63/*!
64 Commits the current composition if there is one,
65 by "unmarking" the text in the edit buffer, and
66 informing the system input context of this fact.
67*/
68void QCocoaInputContext::commit()
69{
70 qCDebug(lcQpaInputMethods) << "Committing composition";
71
72 if (!m_focusWindow)
73 return;
74
75 auto *platformWindow = m_focusWindow->handle();
76 if (!platformWindow)
77 return;
78
79 auto *cocoaWindow = static_cast<QCocoaWindow *>(platformWindow);
80 QNSView *view = qnsview_cast(cocoaWindow->view());
81 if (!view)
82 return;
83
84 [view unmarkText];
85
86 [view.inputContext discardMarkedText];
87 if (view.inputContext != NSTextInputContext.currentInputContext) {
88 // discardMarkedText will activate the TSM document of the given input context,
89 // which may not match the current input context. To ensure the current input
90 // context is not left in an inconsistent state with a deactivated document
91 // we need to manually activate it here.
92 [NSTextInputContext.currentInputContext activate];
93 }
94}
95
96
97/*!
98 \brief Cancels a composition.
99*/
100void QCocoaInputContext::reset()
101{
102 qCDebug(lcQpaInputMethods) << "Resetting input method";
103
104 if (!m_focusWindow)
105 return;
106
107 QCocoaWindow *window = static_cast<QCocoaWindow *>(m_focusWindow->handle());
108 QNSView *view = qnsview_cast(window->view());
109 if (!view)
110 return;
111
112 if (NSTextInputContext *ctxt = [NSTextInputContext currentInputContext]) {
113 [ctxt discardMarkedText];
114 [view unmarkText];
115 }
116}
117
118void QCocoaInputContext::setFocusObject(QObject *focusObject)
119{
120 qCDebug(lcQpaInputMethods) << "Focus object changed to" << focusObject;
121
122 if (m_focusWindow == QGuiApplication::focusWindow()) {
123 if (!m_focusWindow)
124 return;
125
126 QCocoaWindow *window = static_cast<QCocoaWindow *>(m_focusWindow->handle());
127 if (!window)
128 return;
129 QNSView *view = qnsview_cast(window->view());
130 if (!view)
131 return;
132
133 if (NSTextInputContext *ctxt = [NSTextInputContext currentInputContext]) {
134 [ctxt discardMarkedText];
135 [view cancelComposingText];
136 }
137 } else {
138 m_focusWindow = QGuiApplication::focusWindow();
139 }
140}
141
142void QCocoaInputContext::updateLocale()
143{
144 QCFType<TISInputSourceRef> source = TISCopyCurrentKeyboardInputSource();
145 NSArray *languages = static_cast<NSArray*>(TISGetInputSourceProperty(source,
146 kTISPropertyInputSourceLanguages));
147
148 qCDebug(lcQpaInputMethods) << "Input source supports" << languages;
149 if (!languages.count)
150 return;
151
152 QString language = QString::fromNSString(languages.firstObject);
153 QLocale locale(language);
154
155 bool localeUpdated = m_locale != locale;
156 static bool firstUpdate = true;
157
158 m_locale = locale;
159
160 if (localeUpdated && !firstUpdate) {
161 qCDebug(lcQpaInputMethods) << "Reporting new locale" << locale;
162 emitLocaleChanged();
163 }
164
165 firstUpdate = false;
166}
167
168QT_END_NAMESPACE