Explicitly send events for modifier keys in wxUIActionSimulator.
[wxWidgets.git] / src / osx / uiaction_osx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/uiaction_osx.cpp
3 // Purpose: wxUIActionSimulator implementation
4 // Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
5 // Modified by:
6 // Created: 2010-03-06
7 // RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
8 // Copyright: (c) Kevin Ollivier
9 // (c) 2010 Steven Lamerton
10 // (c) 2010 Vadim Zeitlin
11 // Licence: wxWindows licence
12 /////////////////////////////////////////////////////////////////////////////
13
14 #include "wx/defs.h"
15
16 #if wxUSE_UIACTIONSIMULATOR
17
18 #include "wx/uiaction.h"
19
20 #include "wx/log.h"
21
22 #include "wx/osx/private.h"
23 #include "wx/osx/core/cfref.h"
24
25 namespace
26 {
27
28 CGEventTapLocation tap = kCGSessionEventTap;
29
30 CGEventType CGEventTypeForMouseButton(int button, bool isDown)
31 {
32 switch ( button )
33 {
34 case wxMOUSE_BTN_LEFT:
35 return isDown ? kCGEventLeftMouseDown : kCGEventLeftMouseUp;
36
37 case wxMOUSE_BTN_RIGHT:
38 return isDown ? kCGEventRightMouseDown : kCGEventRightMouseUp;
39
40 // All the other buttons use the constant OtherMouseDown but we still
41 // want to check for invalid parameters so assert first
42 default:
43 wxFAIL_MSG("Unsupported button passed in.");
44 // fall back to the only known remaining case
45
46 case wxMOUSE_BTN_MIDDLE:
47 return isDown ? kCGEventOtherMouseDown : kCGEventOtherMouseUp;
48 }
49 }
50
51 CGPoint GetMousePosition()
52 {
53 int x, y;
54 wxGetMousePosition(&x, &y);
55
56 CGPoint pos;
57 pos.x = x;
58 pos.y = y;
59
60 return pos;
61 }
62
63 CGKeyCode wxCharCodeWXToOSX(wxKeyCode code)
64 {
65 CGKeyCode keycode;
66
67 switch (code)
68 {
69 case 'a': case 'A': keycode = kVK_ANSI_A; break;
70 case 'b': case 'B': keycode = kVK_ANSI_B; break;
71 case 'c': case 'C': keycode = kVK_ANSI_C; break;
72 case 'd': case 'D': keycode = kVK_ANSI_D; break;
73 case 'e': case 'E': keycode = kVK_ANSI_E; break;
74 case 'f': case 'F': keycode = kVK_ANSI_F; break;
75 case 'g': case 'G': keycode = kVK_ANSI_G; break;
76 case 'h': case 'H': keycode = kVK_ANSI_H; break;
77 case 'i': case 'I': keycode = kVK_ANSI_I; break;
78 case 'j': case 'J': keycode = kVK_ANSI_J; break;
79 case 'k': case 'K': keycode = kVK_ANSI_K; break;
80 case 'l': case 'L': keycode = kVK_ANSI_L; break;
81 case 'm': case 'M': keycode = kVK_ANSI_M; break;
82 case 'n': case 'N': keycode = kVK_ANSI_N; break;
83 case 'o': case 'O': keycode = kVK_ANSI_O; break;
84 case 'p': case 'P': keycode = kVK_ANSI_P; break;
85 case 'q': case 'Q': keycode = kVK_ANSI_Q; break;
86 case 'r': case 'R': keycode = kVK_ANSI_R; break;
87 case 's': case 'S': keycode = kVK_ANSI_S; break;
88 case 't': case 'T': keycode = kVK_ANSI_T; break;
89 case 'u': case 'U': keycode = kVK_ANSI_U; break;
90 case 'v': case 'V': keycode = kVK_ANSI_V; break;
91 case 'w': case 'W': keycode = kVK_ANSI_W; break;
92 case 'x': case 'X': keycode = kVK_ANSI_X; break;
93 case 'y': case 'Y': keycode = kVK_ANSI_Y; break;
94 case 'z': case 'Z': keycode = kVK_ANSI_Z; break;
95
96 case '0': keycode = kVK_ANSI_0; break;
97 case '1': keycode = kVK_ANSI_1; break;
98 case '2': keycode = kVK_ANSI_2; break;
99 case '3': keycode = kVK_ANSI_3; break;
100 case '4': keycode = kVK_ANSI_4; break;
101 case '5': keycode = kVK_ANSI_5; break;
102 case '6': keycode = kVK_ANSI_6; break;
103 case '7': keycode = kVK_ANSI_7; break;
104 case '8': keycode = kVK_ANSI_8; break;
105 case '9': keycode = kVK_ANSI_9; break;
106
107 case WXK_BACK: keycode = kVK_Delete; break;
108 case WXK_TAB: keycode = kVK_Tab; break;
109 case WXK_RETURN: keycode = kVK_Return; break;
110 case WXK_ESCAPE: keycode = kVK_Escape; break;
111 case WXK_SPACE: keycode = kVK_Space; break;
112 case WXK_DELETE: keycode = kVK_Delete; break;
113
114 case WXK_SHIFT: keycode = kVK_Shift; break;
115 case WXK_ALT: keycode = kVK_Option; break;
116 case WXK_CONTROL: keycode = kVK_Control; break;
117 case WXK_COMMAND: keycode = kVK_Command; break;
118
119 case WXK_CAPITAL: keycode = kVK_CapsLock; break;
120 case WXK_END: keycode = kVK_End; break;
121 case WXK_HOME: keycode = kVK_Home; break;
122 case WXK_LEFT: keycode = kVK_LeftArrow; break;
123 case WXK_UP: keycode = kVK_UpArrow; break;
124 case WXK_RIGHT: keycode = kVK_RightArrow; break;
125 case WXK_DOWN: keycode = kVK_DownArrow; break;
126
127 case WXK_HELP: keycode = kVK_Help; break;
128
129
130 case WXK_NUMPAD0: keycode = kVK_ANSI_Keypad0; break;
131 case WXK_NUMPAD1: keycode = kVK_ANSI_Keypad1; break;
132 case WXK_NUMPAD2: keycode = kVK_ANSI_Keypad2; break;
133 case WXK_NUMPAD3: keycode = kVK_ANSI_Keypad3; break;
134 case WXK_NUMPAD4: keycode = kVK_ANSI_Keypad4; break;
135 case WXK_NUMPAD5: keycode = kVK_ANSI_Keypad5; break;
136 case WXK_NUMPAD6: keycode = kVK_ANSI_Keypad6; break;
137 case WXK_NUMPAD7: keycode = kVK_ANSI_Keypad7; break;
138 case WXK_NUMPAD8: keycode = kVK_ANSI_Keypad8; break;
139 case WXK_NUMPAD9: keycode = kVK_ANSI_Keypad9; break;
140 case WXK_F1: keycode = kVK_F1; break;
141 case WXK_F2: keycode = kVK_F2; break;
142 case WXK_F3: keycode = kVK_F3; break;
143 case WXK_F4: keycode = kVK_F4; break;
144 case WXK_F5: keycode = kVK_F5; break;
145 case WXK_F6: keycode = kVK_F6; break;
146 case WXK_F7: keycode = kVK_F7; break;
147 case WXK_F8: keycode = kVK_F8; break;
148 case WXK_F9: keycode = kVK_F9; break;
149 case WXK_F10: keycode = kVK_F10; break;
150 case WXK_F11: keycode = kVK_F11; break;
151 case WXK_F12: keycode = kVK_F12; break;
152 case WXK_F13: keycode = kVK_F13; break;
153 case WXK_F14: keycode = kVK_F14; break;
154 case WXK_F15: keycode = kVK_F15; break;
155 case WXK_F16: keycode = kVK_F16; break;
156 case WXK_F17: keycode = kVK_F17; break;
157 case WXK_F18: keycode = kVK_F18; break;
158 case WXK_F19: keycode = kVK_F19; break;
159 case WXK_F20: keycode = kVK_F20; break;
160
161 case WXK_PAGEUP: keycode = kVK_PageUp; break;
162 case WXK_PAGEDOWN: keycode = kVK_PageDown; break;
163
164 case WXK_NUMPAD_DELETE: keycode = kVK_ANSI_KeypadClear; break;
165 case WXK_NUMPAD_EQUAL: keycode = kVK_ANSI_KeypadEquals; break;
166 case WXK_NUMPAD_MULTIPLY: keycode = kVK_ANSI_KeypadMultiply; break;
167 case WXK_NUMPAD_ADD: keycode = kVK_ANSI_KeypadPlus; break;
168 case WXK_NUMPAD_SUBTRACT: keycode = kVK_ANSI_KeypadMinus; break;
169 case WXK_NUMPAD_DECIMAL: keycode = kVK_ANSI_KeypadDecimal; break;
170 case WXK_NUMPAD_DIVIDE: keycode = kVK_ANSI_KeypadDivide; break;
171
172 default:
173 wxLogDebug( "Unrecognised keycode %d", code );
174 keycode = -1;
175 }
176
177 return keycode;
178 }
179
180 } // anonymous namespace
181
182 bool wxUIActionSimulator::MouseDown(int button)
183 {
184 CGEventType type = CGEventTypeForMouseButton(button, true);
185 wxCFRef<CGEventRef> event(
186 CGEventCreateMouseEvent(NULL, type, GetMousePosition(), button));
187
188 if ( !event )
189 return false;
190
191 CGEventSetType(event, type);
192 CGEventPost(tap, event);
193
194 return true;
195 }
196
197 bool wxUIActionSimulator::MouseMove(long x, long y)
198 {
199 CGPoint pos;
200 pos.x = x;
201 pos.y = y;
202
203 CGEventType type = kCGEventMouseMoved;
204 wxCFRef<CGEventRef> event(
205 CGEventCreateMouseEvent(NULL, type, pos, kCGMouseButtonLeft));
206
207 if ( !event )
208 return false;
209
210 CGEventSetType(event, type);
211 CGEventPost(tap, event);
212
213 return true;
214 }
215
216 bool wxUIActionSimulator::MouseUp(int button)
217 {
218 CGEventType type = CGEventTypeForMouseButton(button, false);
219 wxCFRef<CGEventRef> event(
220 CGEventCreateMouseEvent(NULL, type, GetMousePosition(), button));
221
222 if ( !event )
223 return false;
224
225 CGEventSetType(event, type);
226 CGEventPost(tap, event);
227
228 return true;
229 }
230
231 bool wxUIActionSimulator::DoKey(int keycode, int modifiers, bool isDown)
232 {
233 CGKeyCode cgcode = wxCharCodeWXToOSX((wxKeyCode)keycode);
234
235 wxCFRef<CGEventRef>
236 event(CGEventCreateKeyboardEvent(NULL, cgcode, isDown));
237 if ( !event )
238 return false;
239
240 CGEventPost(kCGHIDEventTap, event);
241 return true;
242 }
243
244 }
245
246 #endif // wxUSE_UIACTIONSIMULATOR
247