source: trunk/src/gui/inputmethod/qmacinputcontext_mac.cpp@ 352

Last change on this file since 352 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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