|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the test suite of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qnativeevents.h" |
|
43 #include <Carbon/Carbon.h> |
|
44 #include <QtCore> |
|
45 |
|
46 // ************************************************************ |
|
47 // Quartz |
|
48 // ************************************************************ |
|
49 |
|
50 static Qt::KeyboardModifiers getModifiersFromQuartzEvent(CGEventRef inEvent) |
|
51 { |
|
52 Qt::KeyboardModifiers m; |
|
53 CGEventFlags flags = CGEventGetFlags(inEvent); |
|
54 if (flags & kCGEventFlagMaskShift || flags & kCGEventFlagMaskAlphaShift) |
|
55 m |= Qt::ShiftModifier; |
|
56 if (flags & kCGEventFlagMaskControl) |
|
57 m |= Qt::MetaModifier; |
|
58 if (flags & kCGEventFlagMaskAlternate) |
|
59 m |= Qt::AltModifier; |
|
60 if (flags & kCGEventFlagMaskCommand) |
|
61 m |= Qt::ControlModifier; |
|
62 return m; |
|
63 } |
|
64 |
|
65 static void setModifiersFromQNativeEvent(CGEventRef inEvent, const QNativeEvent &event) |
|
66 { |
|
67 CGEventFlags flags = 0; |
|
68 if (event.modifiers.testFlag(Qt::ShiftModifier)) |
|
69 flags |= kCGEventFlagMaskShift; |
|
70 if (event.modifiers.testFlag(Qt::MetaModifier)) |
|
71 flags |= kCGEventFlagMaskControl; |
|
72 if (event.modifiers.testFlag(Qt::AltModifier)) |
|
73 flags |= kCGEventFlagMaskAlternate; |
|
74 if (event.modifiers.testFlag(Qt::ControlModifier)) |
|
75 flags |= kCGEventFlagMaskCommand; |
|
76 CGEventSetFlags(inEvent, flags); |
|
77 } |
|
78 |
|
79 static QPoint getMouseLocationFromQuartzEvent(CGEventRef inEvent) |
|
80 { |
|
81 CGPoint pos = CGEventGetLocation(inEvent); |
|
82 QPoint tmp; |
|
83 tmp.setX(pos.x); |
|
84 tmp.setY(pos.y); |
|
85 return tmp; |
|
86 } |
|
87 |
|
88 static QChar getCharFromQuartzEvent(CGEventRef inEvent) |
|
89 { |
|
90 UniCharCount count = 0; |
|
91 UniChar c; |
|
92 CGEventKeyboardGetUnicodeString(inEvent, 1, &count, &c); |
|
93 return QChar(c); |
|
94 } |
|
95 |
|
96 static CGEventRef EventHandler_Quartz(CGEventTapProxy proxy, CGEventType type, CGEventRef inEvent, void *refCon) |
|
97 { |
|
98 Q_UNUSED(proxy); |
|
99 QNativeInput *nativeInput = static_cast<QNativeInput *>(refCon); |
|
100 switch (type){ |
|
101 case kCGEventKeyDown:{ |
|
102 QNativeKeyEvent e; |
|
103 e.modifiers = getModifiersFromQuartzEvent(inEvent); |
|
104 e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode); |
|
105 e.character = getCharFromQuartzEvent(inEvent); |
|
106 e.press = true; |
|
107 nativeInput->notify(&e); |
|
108 break; |
|
109 } |
|
110 case kCGEventKeyUp:{ |
|
111 QNativeKeyEvent e; |
|
112 e.modifiers = getModifiersFromQuartzEvent(inEvent); |
|
113 e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode); |
|
114 e.character = getCharFromQuartzEvent(inEvent); |
|
115 e.press = false; |
|
116 nativeInput->notify(&e); |
|
117 break; |
|
118 } |
|
119 case kCGEventLeftMouseDown:{ |
|
120 QNativeMouseButtonEvent e; |
|
121 e.modifiers = getModifiersFromQuartzEvent(inEvent); |
|
122 e.globalPos = getMouseLocationFromQuartzEvent(inEvent); |
|
123 e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState); |
|
124 e.button = Qt::LeftButton; |
|
125 nativeInput->notify(&e); |
|
126 break; |
|
127 } |
|
128 case kCGEventLeftMouseUp:{ |
|
129 QNativeMouseButtonEvent e; |
|
130 e.modifiers = getModifiersFromQuartzEvent(inEvent); |
|
131 e.globalPos = getMouseLocationFromQuartzEvent(inEvent); |
|
132 e.clickCount = 0; |
|
133 e.button = Qt::LeftButton; |
|
134 nativeInput->notify(&e); |
|
135 break; |
|
136 } |
|
137 case kCGEventRightMouseDown:{ |
|
138 QNativeMouseButtonEvent e; |
|
139 e.modifiers = getModifiersFromQuartzEvent(inEvent); |
|
140 e.globalPos = getMouseLocationFromQuartzEvent(inEvent); |
|
141 e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState); |
|
142 e.button = Qt::RightButton; |
|
143 nativeInput->notify(&e); |
|
144 break; |
|
145 } |
|
146 case kCGEventRightMouseUp:{ |
|
147 QNativeMouseButtonEvent e; |
|
148 e.modifiers = getModifiersFromQuartzEvent(inEvent); |
|
149 e.globalPos = getMouseLocationFromQuartzEvent(inEvent); |
|
150 e.clickCount = 0; |
|
151 e.button = Qt::RightButton; |
|
152 nativeInput->notify(&e); |
|
153 break; |
|
154 } |
|
155 case kCGEventMouseMoved:{ |
|
156 QNativeMouseMoveEvent e; |
|
157 e.modifiers = getModifiersFromQuartzEvent(inEvent); |
|
158 e.globalPos = getMouseLocationFromQuartzEvent(inEvent); |
|
159 nativeInput->notify(&e); |
|
160 break; |
|
161 } |
|
162 case kCGEventLeftMouseDragged:{ |
|
163 QNativeMouseDragEvent e; |
|
164 e.modifiers = getModifiersFromQuartzEvent(inEvent); |
|
165 e.globalPos = getMouseLocationFromQuartzEvent(inEvent); |
|
166 e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState); |
|
167 e.button = Qt::LeftButton; |
|
168 nativeInput->notify(&e); |
|
169 break; |
|
170 } |
|
171 case kCGEventScrollWheel:{ |
|
172 QNativeMouseWheelEvent e; |
|
173 e.modifiers = getModifiersFromQuartzEvent(inEvent); |
|
174 e.delta = CGEventGetIntegerValueField(inEvent, kCGScrollWheelEventDeltaAxis1); |
|
175 e.globalPos = getMouseLocationFromQuartzEvent(inEvent); |
|
176 nativeInput->notify(&e); |
|
177 break; |
|
178 } |
|
179 case kCGEventFlagsChanged:{ |
|
180 QNativeModifierEvent e; |
|
181 e.modifiers = getModifiersFromQuartzEvent(inEvent); |
|
182 e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode); |
|
183 nativeInput->notify(&e); |
|
184 break; |
|
185 } |
|
186 |
|
187 } |
|
188 |
|
189 return inEvent; |
|
190 } |
|
191 |
|
192 Qt::Native::Status insertEventHandler_Quartz(QNativeInput *nativeInput, int pid = 0) |
|
193 { |
|
194 uid_t uid = geteuid(); |
|
195 if (uid != 0) |
|
196 qWarning("MacNativeEvents: You must be root to listen for key events!"); |
|
197 |
|
198 CFMachPortRef port; |
|
199 if (!pid){ |
|
200 port = CGEventTapCreate(kCGHIDEventTap, |
|
201 kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, |
|
202 kCGEventMaskForAllEvents, EventHandler_Quartz, nativeInput); |
|
203 } else { |
|
204 ProcessSerialNumber psn; |
|
205 GetProcessForPID(pid, &psn); |
|
206 port = CGEventTapCreateForPSN(&psn, |
|
207 kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, |
|
208 kCGEventMaskForAllEvents, EventHandler_Quartz, nativeInput); |
|
209 } |
|
210 |
|
211 CFRunLoopSourceRef eventSrc = CFMachPortCreateRunLoopSource(NULL, port, 0); |
|
212 CFRunLoopAddSource((CFRunLoopRef) GetCFRunLoopFromEventLoop(GetMainEventLoop()), |
|
213 eventSrc, kCFRunLoopCommonModes); |
|
214 |
|
215 return Qt::Native::Success; |
|
216 } |
|
217 |
|
218 Qt::Native::Status removeEventHandler_Quartz() |
|
219 { |
|
220 return Qt::Native::Success; // ToDo: |
|
221 } |
|
222 |
|
223 Qt::Native::Status sendNativeKeyEventToProcess_Quartz(const QNativeKeyEvent &event, int pid) |
|
224 { |
|
225 ProcessSerialNumber psn; |
|
226 GetProcessForPID(pid, &psn); |
|
227 |
|
228 CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, event.press); |
|
229 setModifiersFromQNativeEvent(e, event); |
|
230 SetFrontProcess(&psn); |
|
231 CGEventPostToPSN(&psn, e); |
|
232 CFRelease(e); |
|
233 return Qt::Native::Success; |
|
234 } |
|
235 |
|
236 Qt::Native::Status sendNativeKeyEvent_Quartz(const QNativeKeyEvent &event) |
|
237 { |
|
238 CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, event.press); |
|
239 setModifiersFromQNativeEvent(e, event); |
|
240 CGEventPost(kCGHIDEventTap, e); |
|
241 CFRelease(e); |
|
242 return Qt::Native::Success; |
|
243 } |
|
244 |
|
245 Qt::Native::Status sendNativeMouseMoveEvent_Quartz(const QNativeMouseMoveEvent &event) |
|
246 { |
|
247 CGPoint pos; |
|
248 pos.x = event.globalPos.x(); |
|
249 pos.y = event.globalPos.y(); |
|
250 |
|
251 CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0); |
|
252 setModifiersFromQNativeEvent(e, event); |
|
253 CGEventPost(kCGHIDEventTap, e); |
|
254 CFRelease(e); |
|
255 return Qt::Native::Success; |
|
256 } |
|
257 |
|
258 Qt::Native::Status sendNativeMouseButtonEvent_Quartz(const QNativeMouseButtonEvent &event) |
|
259 { |
|
260 CGPoint pos; |
|
261 pos.x = event.globalPos.x(); |
|
262 pos.y = event.globalPos.y(); |
|
263 |
|
264 CGEventType type = 0; |
|
265 if (event.button == Qt::LeftButton) |
|
266 type = (event.clickCount > 0) ? kCGEventLeftMouseDown : kCGEventLeftMouseUp; |
|
267 else if (event.button == Qt::RightButton) |
|
268 type = (event.clickCount > 0) ? kCGEventRightMouseDown : kCGEventRightMouseUp; |
|
269 else |
|
270 type = (event.clickCount > 0) ? kCGEventOtherMouseDown : kCGEventOtherMouseUp; |
|
271 |
|
272 CGEventRef e = CGEventCreateMouseEvent(0, type, pos, event.button); |
|
273 setModifiersFromQNativeEvent(e, event); |
|
274 CGEventSetIntegerValueField(e, kCGMouseEventClickState, event.clickCount); |
|
275 CGEventPost(kCGHIDEventTap, e); |
|
276 CFRelease(e); |
|
277 return Qt::Native::Success; |
|
278 } |
|
279 |
|
280 Qt::Native::Status sendNativeMouseDragEvent_Quartz(const QNativeMouseDragEvent &event) |
|
281 { |
|
282 CGPoint pos; |
|
283 pos.x = event.globalPos.x(); |
|
284 pos.y = event.globalPos.y(); |
|
285 |
|
286 CGEventType type = 0; |
|
287 if (event.button == Qt::LeftButton) |
|
288 type = kCGEventLeftMouseDragged; |
|
289 else if (event.button == Qt::RightButton) |
|
290 type = kCGEventRightMouseDragged; |
|
291 else |
|
292 type = kCGEventOtherMouseDragged; |
|
293 |
|
294 CGEventRef e = CGEventCreateMouseEvent(0, type, pos, event.button); |
|
295 setModifiersFromQNativeEvent(e, event); |
|
296 CGEventPost(kCGHIDEventTap, e); |
|
297 CFRelease(e); |
|
298 return Qt::Native::Success; |
|
299 } |
|
300 |
|
301 Qt::Native::Status sendNativeMouseWheelEvent_Quartz(const QNativeMouseWheelEvent &event) |
|
302 { |
|
303 CGPoint pos; |
|
304 pos.x = event.globalPos.x(); |
|
305 pos.y = event.globalPos.y(); |
|
306 |
|
307 CGEventRef e = CGEventCreateScrollWheelEvent(0, kCGScrollEventUnitPixel, 1, 0); |
|
308 CGEventSetIntegerValueField(e, kCGScrollWheelEventDeltaAxis1, event.delta); |
|
309 CGEventSetLocation(e, pos); |
|
310 setModifiersFromQNativeEvent(e, event); |
|
311 CGEventPost(kCGHIDEventTap, e); |
|
312 CFRelease(e); |
|
313 |
|
314 return Qt::Native::Success; |
|
315 } |
|
316 |
|
317 Qt::Native::Status sendNativeModifierEvent_Quartz(const QNativeModifierEvent &event) |
|
318 { |
|
319 CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, 0); |
|
320 CGEventSetType(e, kCGEventFlagsChanged); |
|
321 setModifiersFromQNativeEvent(e, event); |
|
322 CGEventPost(kCGHIDEventTap, e); |
|
323 CFRelease(e); |
|
324 return Qt::Native::Success; |
|
325 } |
|
326 |
|
327 // ************************************************************ |
|
328 // QNativeInput methods: |
|
329 // ************************************************************ |
|
330 |
|
331 Qt::Native::Status QNativeInput::sendNativeMouseButtonEvent(const QNativeMouseButtonEvent &event) |
|
332 { |
|
333 return sendNativeMouseButtonEvent_Quartz(event); |
|
334 } |
|
335 |
|
336 Qt::Native::Status QNativeInput::sendNativeMouseMoveEvent(const QNativeMouseMoveEvent &event) |
|
337 { |
|
338 return sendNativeMouseMoveEvent_Quartz(event); |
|
339 } |
|
340 |
|
341 Qt::Native::Status QNativeInput::sendNativeMouseDragEvent(const QNativeMouseDragEvent &event) |
|
342 { |
|
343 return sendNativeMouseDragEvent_Quartz(event); |
|
344 } |
|
345 |
|
346 Qt::Native::Status QNativeInput::sendNativeMouseWheelEvent(const QNativeMouseWheelEvent &event) |
|
347 { |
|
348 return sendNativeMouseWheelEvent_Quartz(event); |
|
349 } |
|
350 |
|
351 Qt::Native::Status QNativeInput::sendNativeKeyEvent(const QNativeKeyEvent &event, int pid) |
|
352 { |
|
353 if (!pid) |
|
354 return sendNativeKeyEvent_Quartz(event); |
|
355 else |
|
356 return sendNativeKeyEventToProcess_Quartz(event, pid); |
|
357 } |
|
358 |
|
359 Qt::Native::Status QNativeInput::sendNativeModifierEvent(const QNativeModifierEvent &event) |
|
360 { |
|
361 return sendNativeModifierEvent_Quartz(event); |
|
362 } |
|
363 |
|
364 Qt::Native::Status QNativeInput::subscribeForNativeEvents() |
|
365 { |
|
366 return insertEventHandler_Quartz(this); |
|
367 } |
|
368 |
|
369 Qt::Native::Status QNativeInput::unsubscribeForNativeEvents() |
|
370 { |
|
371 return removeEventHandler_Quartz(); |
|
372 } |
|
373 |
|
374 // Some Qt to Mac mappings: |
|
375 int QNativeKeyEvent::Key_A = 0; |
|
376 int QNativeKeyEvent::Key_B = 11; |
|
377 int QNativeKeyEvent::Key_C = 8; |
|
378 int QNativeKeyEvent::Key_1 = 18; |
|
379 int QNativeKeyEvent::Key_Backspace = 51; |
|
380 int QNativeKeyEvent::Key_Enter = 36; |
|
381 int QNativeKeyEvent::Key_Del = 117; |
|
382 |