Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | #include <qconfig.h> |
42 | #include <qglobal.h> |
43 | #ifndef QT_NO_IM |
44 | #include <qvarlengtharray.h> |
45 | #include <qwidget.h> |
46 | #include <private/qmacinputcontext_p.h> |
47 | #include "qtextformat.h" |
48 | #include <qdebug.h> |
49 | #include <private/qapplication_p.h> |
50 | #include <private/qkeymapper_p.h> |
51 | |
52 | QT_BEGIN_NAMESPACE |
53 | |
54 | extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); |
55 | |
56 | #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) |
57 | # define typeRefCon typeSInt32 |
58 | # define typeByteCount typeSInt32 |
59 | #endif |
60 | |
61 | QMacInputContext::QMacInputContext(QObject *parent) |
62 | : QInputContext(parent), composing(false), recursionGuard(false), textDocument(0), |
63 | keydownEvent(0), lastFocusWid(0) |
64 | { |
65 | // createTextDocument(); |
66 | } |
67 | |
68 | QMacInputContext::~QMacInputContext() |
69 | { |
70 | #ifndef QT_MAC_USE_COCOA |
71 | if(textDocument) |
72 | DeleteTSMDocument(textDocument); |
73 | #endif |
74 | } |
75 | |
76 | void |
77 | QMacInputContext::createTextDocument() |
78 | { |
79 | #ifndef QT_MAC_USE_COCOA |
80 | if(!textDocument) { |
81 | InterfaceTypeList itl = { kUnicodeDocument }; |
82 | NewTSMDocument(1, itl, &textDocument, SRefCon(this)); |
83 | } |
84 | #endif |
85 | } |
86 | |
87 | |
88 | QString QMacInputContext::language() |
89 | { |
90 | return QString(); |
91 | } |
92 | |
93 | |
94 | void QMacInputContext::mouseHandler(int pos, QMouseEvent *e) |
95 | { |
96 | #ifndef QT_MAC_USE_COCOA |
97 | if(e->type() != QEvent::MouseButtonPress) |
98 | return; |
99 | |
100 | if (!composing) |
101 | return; |
102 | if (pos < 0 || pos > currentText.length()) |
103 | reset(); |
104 | // ##### handle mouse position |
105 | #else |
106 | Q_UNUSED(pos); |
107 | Q_UNUSED(e); |
108 | #endif |
109 | } |
110 | |
111 | #if !defined QT_MAC_USE_COCOA |
112 | |
113 | static QTextFormat qt_mac_compose_format() |
114 | { |
115 | QTextCharFormat ret; |
116 | ret.setFontUnderline(true); |
117 | return ret; |
118 | } |
119 | |
120 | void QMacInputContext::reset() |
121 | { |
122 | if (recursionGuard) |
123 | return; |
124 | if (!currentText.isEmpty()){ |
125 | QInputMethodEvent e; |
126 | e.setCommitString(currentText); |
127 | qt_sendSpontaneousEvent(focusWidget(), &e); |
128 | currentText = QString(); |
129 | } |
130 | recursionGuard = true; |
131 | createTextDocument(); |
132 | composing = false; |
133 | ActivateTSMDocument(textDocument); |
134 | FixTSMDocument(textDocument); |
135 | recursionGuard = false; |
136 | } |
137 | |
138 | bool QMacInputContext::isComposing() const |
139 | { |
140 | return composing; |
141 | } |
142 | #endif |
143 | |
144 | void QMacInputContext::setFocusWidget(QWidget *w) |
145 | { |
146 | if (!w) |
147 | lastFocusWid = focusWidget(); |
148 | createTextDocument(); |
149 | #ifndef QT_MAC_USE_COCOA |
150 | if(w) |
151 | ActivateTSMDocument(textDocument); |
152 | else |
153 | DeactivateTSMDocument(textDocument); |
154 | #endif |
155 | QInputContext::setFocusWidget(w); |
156 | } |
157 | |
158 | |
159 | #ifndef QT_MAC_USE_COCOA |
160 | static EventTypeSpec input_events[] = { |
161 | { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, |
162 | { kEventClassTextInput, kEventTextInputOffsetToPos }, |
163 | { kEventClassTextInput, kEventTextInputUpdateActiveInputArea } |
164 | }; |
165 | static EventHandlerUPP input_proc_handlerUPP = 0; |
166 | static EventHandlerRef input_proc_handler = 0; |
167 | #endif |
168 | |
169 | void |
170 | QMacInputContext::initialize() |
171 | { |
172 | #ifndef QT_MAC_USE_COCOA |
173 | if(!input_proc_handler) { |
174 | input_proc_handlerUPP = NewEventHandlerUPP(QMacInputContext::globalEventProcessor); |
175 | InstallEventHandler(GetApplicationEventTarget(), input_proc_handlerUPP, |
176 | GetEventTypeCount(input_events), input_events, |
177 | 0, &input_proc_handler); |
178 | } |
179 | #endif |
180 | } |
181 | |
182 | void |
183 | QMacInputContext::cleanup() |
184 | { |
185 | #ifndef QT_MAC_USE_COCOA |
186 | if(input_proc_handler) { |
187 | RemoveEventHandler(input_proc_handler); |
188 | input_proc_handler = 0; |
189 | } |
190 | if(input_proc_handlerUPP) { |
191 | DisposeEventHandlerUPP(input_proc_handlerUPP); |
192 | input_proc_handlerUPP = 0; |
193 | } |
194 | #endif |
195 | } |
196 | |
197 | void QMacInputContext::setLastKeydownEvent(EventRef event) |
198 | { |
199 | EventRef tmpEvent = keydownEvent; |
200 | keydownEvent = event; |
201 | if (keydownEvent) |
202 | RetainEvent(keydownEvent); |
203 | if (tmpEvent) |
204 | ReleaseEvent(tmpEvent); |
205 | } |
206 | |
207 | OSStatus |
208 | QMacInputContext::globalEventProcessor(EventHandlerCallRef, EventRef event, void *) |
209 | { |
210 | #ifndef QT_MAC_USE_COCOA |
211 | QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData); |
212 | |
213 | SRefCon refcon = 0; |
214 | GetEventParameter(event, kEventParamTextInputSendRefCon, typeRefCon, 0, |
215 | sizeof(refcon), 0, &refcon); |
216 | QMacInputContext *context = reinterpret_cast<QMacInputContext*>(refcon); |
217 | |
218 | bool handled_event=true; |
219 | UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event); |
220 | switch(eclass) { |
221 | case kEventClassTextInput: { |
222 | handled_event = false; |
223 | QWidget *widget = QApplicationPrivate::focus_widget; |
224 | bool canCompose = widget && (!context || widget->inputContext() == context) |
225 | && !(widget->inputMethodHints() & Qt::ImhDigitsOnly |
226 | || widget->inputMethodHints() & Qt::ImhFormattedNumbersOnly |
227 | || widget->inputMethodHints() & Qt::ImhHiddenText); |
228 | if(!canCompose) { |
229 | handled_event = false; |
230 | } else if(ekind == kEventTextInputOffsetToPos) { |
231 | if(!widget->testAttribute(Qt::WA_InputMethodEnabled)) { |
232 | handled_event = false; |
233 | break; |
234 | } |
235 | |
236 | QRect mr(widget->inputMethodQuery(Qt::ImMicroFocus).toRect()); |
237 | QPoint mp(widget->mapToGlobal(QPoint(mr.topLeft()))); |
238 | Point pt; |
239 | pt.h = mp.x(); |
240 | pt.v = mp.y() + mr.height(); |
241 | SetEventParameter(event, kEventParamTextInputReplyPoint, typeQDPoint, |
242 | sizeof(pt), &pt); |
243 | handled_event = true; |
244 | } else if(ekind == kEventTextInputUpdateActiveInputArea) { |
245 | if(!widget->testAttribute(Qt::WA_InputMethodEnabled)) { |
246 | handled_event = false; |
247 | break; |
248 | } |
249 | |
250 | if (context->recursionGuard) |
251 | break; |
252 | |
253 | ByteCount unilen = 0; |
254 | GetEventParameter(event, kEventParamTextInputSendText, typeUnicodeText, |
255 | 0, 0, &unilen, 0); |
256 | UniChar *unicode = (UniChar*)NewPtr(unilen); |
257 | GetEventParameter(event, kEventParamTextInputSendText, typeUnicodeText, |
258 | 0, unilen, 0, unicode); |
259 | QString text((QChar*)unicode, unilen / sizeof(UniChar)); |
260 | DisposePtr((char*)unicode); |
261 | |
262 | ByteCount fixed_length = 0; |
263 | GetEventParameter(event, kEventParamTextInputSendFixLen, typeByteCount, 0, |
264 | sizeof(fixed_length), 0, &fixed_length); |
265 | if(fixed_length == ULONG_MAX || fixed_length == unilen) { |
266 | QInputMethodEvent e; |
267 | e.setCommitString(text); |
268 | context->currentText = QString(); |
269 | qt_sendSpontaneousEvent(context->focusWidget(), &e); |
270 | handled_event = true; |
271 | context->reset(); |
272 | } else { |
273 | ByteCount rngSize = 0; |
274 | OSStatus err = GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray, 0, |
275 | 0, &rngSize, 0); |
276 | QVarLengthArray<TextRangeArray> highlight(rngSize); |
277 | if (noErr == err) { |
278 | err = GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray, 0, |
279 | rngSize, &rngSize, highlight.data()); |
280 | } |
281 | context->composing = true; |
282 | if(fixed_length > 0) { |
283 | const int qFixedLength = fixed_length / sizeof(UniChar); |
284 | QList<QInputMethodEvent::Attribute> attrs; |
285 | attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, |
286 | qFixedLength, text.length()-qFixedLength, |
287 | qt_mac_compose_format()); |
288 | QInputMethodEvent e(text, attrs); |
289 | context->currentText = text; |
290 | e.setCommitString(text.left(qFixedLength), 0, qFixedLength); |
291 | qt_sendSpontaneousEvent(widget, &e); |
292 | handled_event = true; |
293 | } else { |
294 | /* Apple's enums that they have removed from Tiger :( |
295 | enum { |
296 | kCaretPosition = 1, |
297 | kRawText = 2, |
298 | kSelectedRawText = 3, |
299 | kConvertedText = 4, |
300 | kSelectedConvertedText = 5, |
301 | kBlockFillText = 6, |
302 | kOutlineText = 7, |
303 | kSelectedText = 8 |
304 | }; |
305 | */ |
306 | #ifndef kConvertedText |
307 | #define kConvertedText 4 |
308 | #endif |
309 | #ifndef kCaretPosition |
310 | #define kCaretPosition 1 |
311 | #endif |
312 | QList<QInputMethodEvent::Attribute> attrs; |
313 | if (!highlight.isEmpty()) { |
314 | TextRangeArray *data = highlight.data(); |
315 | for (int i = 0; i < data->fNumOfRanges; ++i) { |
316 | int start = data->fRange[i].fStart / sizeof(UniChar); |
317 | int len = (data->fRange[i].fEnd - data->fRange[i].fStart) / sizeof(UniChar); |
318 | if (data->fRange[i].fHiliteStyle == kCaretPosition) { |
319 | attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, start, 0, QVariant()); |
320 | continue; |
321 | } |
322 | QTextCharFormat format; |
323 | format.setFontUnderline(true); |
324 | if (data->fRange[i].fHiliteStyle == kConvertedText) |
325 | format.setUnderlineColor(Qt::gray); |
326 | else |
327 | format.setUnderlineColor(Qt::black); |
328 | attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, start, len, format); |
329 | } |
330 | } else { |
331 | attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, |
332 | 0, text.length(), qt_mac_compose_format()); |
333 | } |
334 | context->currentText = text; |
335 | QInputMethodEvent e(text, attrs); |
336 | qt_sendSpontaneousEvent(widget, &e); |
337 | handled_event = true; |
338 | } |
339 | } |
340 | #if 0 |
341 | if(!context->composing) |
342 | handled_event = false; |
343 | #endif |
344 | |
345 | extern bool qt_mac_eat_unicode_key; //qapplication_mac.cpp |
346 | qt_mac_eat_unicode_key = handled_event; |
347 | } else if(ekind == kEventTextInputUnicodeForKeyEvent) { |
348 | EventRef key_ev = 0; |
349 | GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, typeEventRef, 0, |
350 | sizeof(key_ev), 0, &key_ev); |
351 | QString text; |
352 | ByteCount unilen = 0; |
353 | if(GetEventParameter(key_ev, kEventParamKeyUnicodes, typeUnicodeText, 0, 0, &unilen, 0) == noErr) { |
354 | UniChar *unicode = (UniChar*)NewPtr(unilen); |
355 | GetEventParameter(key_ev, kEventParamKeyUnicodes, typeUnicodeText, 0, unilen, 0, unicode); |
356 | text = QString((QChar*)unicode, unilen / sizeof(UniChar)); |
357 | DisposePtr((char*)unicode); |
358 | } |
359 | unsigned char chr = 0; |
360 | GetEventParameter(key_ev, kEventParamKeyMacCharCodes, typeChar, 0, sizeof(chr), 0, &chr); |
361 | if(!chr || chr >= 128 || (text.length() > 0 && (text.length() > 1 || text.at(0) != QLatin1Char(chr)))) |
362 | handled_event = !widget->testAttribute(Qt::WA_InputMethodEnabled); |
363 | QMacInputContext *context = qobject_cast<QMacInputContext*>(qApp->inputContext()); |
364 | if (context && context->lastKeydownEvent()) { |
365 | qt_keymapper_private()->translateKeyEvent(widget, 0, context->lastKeydownEvent(), |
366 | 0, false); |
367 | context->setLastKeydownEvent(0); |
368 | } |
369 | } |
370 | break; } |
371 | default: |
372 | break; |
373 | } |
374 | if(!handled_event) //let the event go through |
375 | return eventNotHandledErr; |
376 | #else |
377 | Q_UNUSED(event); |
378 | #endif |
379 | return noErr; //we eat the event |
380 | } |
381 | |
382 | QT_END_NAMESPACE |
383 | #endif // QT_NO_IM |
384 |
Warning: That file was not part of the compilation database. It may have many parsing errors.