1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2011-2017 - Daniel De Matteis
3 * Copyright (C) 2013-2014 - Jason Fetters
4 *
5 * RetroArch is free software: you can redistribute it and/or modify it under the terms
6 * of the GNU General Public License as published by the Free Software Found-
7 * ation, either version 3 of the License, or (at your option) any later version.
8 *
9 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with RetroArch.
14 * If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <stdint.h>
18 #include <unistd.h>
19
20 #include <retro_miscellaneous.h>
21
22 #ifdef HAVE_CONFIG_H
23 #include "../../config.h"
24 #endif
25
26 #include "../input_keymaps.h"
27
28 #include "cocoa_input.h"
29
30 #include "../../retroarch.h"
31 #include "../../driver.h"
32
33 #include "../drivers_keyboard/keyboard_event_apple.h"
34
35 /* TODO/FIXME -
36 * fix game focus toggle */
37
38 #ifdef OSX
39 /* Forward declaration */
40 float cocoa_screen_get_backing_scale_factor(void);
41 #endif
42
43 static bool apple_key_state[MAX_KEYS];
44 #if TARGET_OS_IPHONE
45 /* TODO/FIXME - static globals */
46 static bool small_keyboard_active = false;
47
48 #define HIDKEY(X) X
49 #define MAX_ICADE_PROFILES 4
50 #define MAX_ICADE_KEYS 0x100
51
52 typedef struct icade_map
53 {
54 bool up;
55 enum retro_key key;
56 } icade_map_t;
57
58 static icade_map_t icade_maps[MAX_ICADE_PROFILES][MAX_ICADE_KEYS];
59
handle_small_keyboard(unsigned * code,bool down)60 static bool handle_small_keyboard(unsigned* code, bool down)
61 {
62 static uint8_t mapping[128];
63 static bool map_initialized;
64 static const struct { uint8_t orig; uint8_t mod; } mapping_def[] =
65 {
66 { KEY_Grave, KEY_Escape }, { KEY_1, KEY_F1 },
67 { KEY_2, KEY_F2 }, { KEY_3, KEY_F3 },
68 { KEY_4, KEY_F4 }, { KEY_5, KEY_F5 },
69 { KEY_6, KEY_F6 }, { KEY_7, KEY_F7 },
70 { KEY_8, KEY_F8 }, { KEY_9, KEY_F9 },
71 { KEY_0, KEY_F10 }, { KEY_Minus, KEY_F11 },
72 { KEY_Equals, KEY_F12 }, { KEY_Up, KEY_PageUp },
73 { KEY_Down, KEY_PageDown }, { KEY_Left, KEY_Home },
74 { KEY_Right, KEY_End }, { KEY_Q, KP_7 },
75 { KEY_W, KP_8 }, { KEY_E, KP_9 },
76 { KEY_A, KP_4 }, { KEY_S, KP_5 },
77 { KEY_D, KP_6 }, { KEY_Z, KP_1 },
78 { KEY_X, KP_2 }, { KEY_C, KP_3 },
79 { 0 }
80 };
81 unsigned translated_code = 0;
82
83 if (!map_initialized)
84 {
85 int i;
86 for (i = 0; mapping_def[i].orig; i ++)
87 mapping[mapping_def[i].orig] = mapping_def[i].mod;
88 map_initialized = true;
89 }
90
91 if (*code == KEY_RightShift)
92 {
93 small_keyboard_active = down;
94 *code = 0;
95 return true;
96 }
97
98 if (*code < 128)
99 translated_code = mapping[*code];
100
101 /* Allow old keys to be released. */
102 if (!down && apple_key_state[*code])
103 return false;
104
105 if ((!down && apple_key_state[translated_code]) ||
106 small_keyboard_active)
107 {
108 *code = translated_code;
109 return true;
110 }
111
112 return false;
113 }
114
handle_icade_event(unsigned * code,bool * keydown)115 static bool handle_icade_event(unsigned *code, bool *keydown)
116 {
117 static bool initialized = false;
118 bool ret = false;
119 settings_t *settings = config_get_ptr();
120 unsigned kb_type_idx = settings->uints.input_keyboard_gamepad_mapping_type;
121
122 if (!initialized)
123 {
124 unsigned i;
125 unsigned j = 0;
126
127 for (j = 0; j < MAX_ICADE_PROFILES; j++)
128 {
129 for (i = 0; i < MAX_ICADE_KEYS; i++)
130 {
131 icade_maps[j][i].key = RETROK_UNKNOWN;
132 icade_maps[j][i].up = false;
133 }
134 }
135
136 /* iPega PG-9017 */
137 j = 1;
138
139 icade_maps[j][rarch_keysym_lut[RETROK_a]].key = RETROK_LEFT;
140 icade_maps[j][rarch_keysym_lut[RETROK_q]].key = RETROK_LEFT;
141 icade_maps[j][rarch_keysym_lut[RETROK_c]].key = RETROK_RIGHT;
142 icade_maps[j][rarch_keysym_lut[RETROK_d]].key = RETROK_RIGHT;
143 icade_maps[j][rarch_keysym_lut[RETROK_e]].key = RETROK_UP;
144 icade_maps[j][rarch_keysym_lut[RETROK_w]].key = RETROK_UP;
145 icade_maps[j][rarch_keysym_lut[RETROK_x]].key = RETROK_DOWN;
146 icade_maps[j][rarch_keysym_lut[RETROK_z]].key = RETROK_DOWN;
147 icade_maps[j][rarch_keysym_lut[RETROK_f]].key = RETROK_z;
148 icade_maps[j][rarch_keysym_lut[RETROK_u]].key = RETROK_z;
149 icade_maps[j][rarch_keysym_lut[RETROK_i]].key = RETROK_q;
150 icade_maps[j][rarch_keysym_lut[RETROK_m]].key = RETROK_q;
151 icade_maps[j][rarch_keysym_lut[RETROK_j]].key = RETROK_a;
152 icade_maps[j][rarch_keysym_lut[RETROK_n]].key = RETROK_a;
153 icade_maps[j][rarch_keysym_lut[RETROK_k]].key = RETROK_w;
154 icade_maps[j][rarch_keysym_lut[RETROK_p]].key = RETROK_w;
155 icade_maps[j][rarch_keysym_lut[RETROK_h]].key = RETROK_x;
156 icade_maps[j][rarch_keysym_lut[RETROK_r]].key = RETROK_x;
157 icade_maps[j][rarch_keysym_lut[RETROK_y]].key = RETROK_s;
158 icade_maps[j][rarch_keysym_lut[RETROK_t]].key = RETROK_s;
159
160 icade_maps[j][rarch_keysym_lut[RETROK_e]].up = true;
161 icade_maps[j][rarch_keysym_lut[RETROK_z]].up = true;
162 icade_maps[j][rarch_keysym_lut[RETROK_q]].up = true;
163 icade_maps[j][rarch_keysym_lut[RETROK_c]].up = true;
164 icade_maps[j][rarch_keysym_lut[RETROK_f]].up = true;
165 icade_maps[j][rarch_keysym_lut[RETROK_m]].up = true;
166 icade_maps[j][rarch_keysym_lut[RETROK_t]].up = true;
167 icade_maps[j][rarch_keysym_lut[RETROK_n]].up = true;
168 icade_maps[j][rarch_keysym_lut[RETROK_p]].up = true;
169 icade_maps[j][rarch_keysym_lut[RETROK_r]].up = true;
170
171 /* 8-bitty */
172 j = 2;
173
174 icade_maps[j][rarch_keysym_lut[RETROK_a]].key = RETROK_LEFT;
175 icade_maps[j][rarch_keysym_lut[RETROK_q]].key = RETROK_LEFT;
176 icade_maps[j][rarch_keysym_lut[RETROK_c]].key = RETROK_RIGHT;
177 icade_maps[j][rarch_keysym_lut[RETROK_d]].key = RETROK_RIGHT;
178 icade_maps[j][rarch_keysym_lut[RETROK_e]].key = RETROK_UP;
179 icade_maps[j][rarch_keysym_lut[RETROK_w]].key = RETROK_UP;
180 icade_maps[j][rarch_keysym_lut[RETROK_x]].key = RETROK_DOWN;
181 icade_maps[j][rarch_keysym_lut[RETROK_z]].key = RETROK_DOWN;
182 icade_maps[j][rarch_keysym_lut[RETROK_h]].key = RETROK_q;
183 icade_maps[j][rarch_keysym_lut[RETROK_r]].key = RETROK_q;
184 icade_maps[j][rarch_keysym_lut[RETROK_j]].key = RETROK_w;
185 icade_maps[j][rarch_keysym_lut[RETROK_n]].key = RETROK_w;
186 icade_maps[j][rarch_keysym_lut[RETROK_i]].key = RETROK_a;
187 icade_maps[j][rarch_keysym_lut[RETROK_m]].key = RETROK_a;
188 icade_maps[j][rarch_keysym_lut[RETROK_k]].key = RETROK_z;
189 icade_maps[j][rarch_keysym_lut[RETROK_p]].key = RETROK_z;
190 icade_maps[j][rarch_keysym_lut[RETROK_y]].key = RETROK_RSHIFT;
191 icade_maps[j][rarch_keysym_lut[RETROK_t]].key = RETROK_RSHIFT;
192 icade_maps[j][rarch_keysym_lut[RETROK_u]].key = RETROK_RETURN;
193 icade_maps[j][rarch_keysym_lut[RETROK_f]].key = RETROK_RETURN;
194 icade_maps[j][rarch_keysym_lut[RETROK_l]].key = RETROK_x;
195 icade_maps[j][rarch_keysym_lut[RETROK_v]].key = RETROK_x;
196 icade_maps[j][rarch_keysym_lut[RETROK_o]].key = RETROK_s;
197 icade_maps[j][rarch_keysym_lut[RETROK_g]].key = RETROK_s;
198
199 icade_maps[j][rarch_keysym_lut[RETROK_e]].up = true;
200 icade_maps[j][rarch_keysym_lut[RETROK_z]].up = true;
201 icade_maps[j][rarch_keysym_lut[RETROK_q]].up = true;
202 icade_maps[j][rarch_keysym_lut[RETROK_c]].up = true;
203 icade_maps[j][rarch_keysym_lut[RETROK_r]].up = true;
204 icade_maps[j][rarch_keysym_lut[RETROK_n]].up = true;
205 icade_maps[j][rarch_keysym_lut[RETROK_m]].up = true;
206 icade_maps[j][rarch_keysym_lut[RETROK_p]].up = true;
207 icade_maps[j][rarch_keysym_lut[RETROK_t]].up = true;
208 icade_maps[j][rarch_keysym_lut[RETROK_f]].up = true;
209 icade_maps[j][rarch_keysym_lut[RETROK_v]].up = true;
210 icade_maps[j][rarch_keysym_lut[RETROK_g]].up = true;
211
212 /* SNES30 8bitDo */
213 j = 3;
214
215 icade_maps[j][rarch_keysym_lut[RETROK_e]].key = RETROK_UP;
216 icade_maps[j][rarch_keysym_lut[RETROK_w]].key = RETROK_UP;
217 icade_maps[j][rarch_keysym_lut[RETROK_x]].key = RETROK_DOWN;
218 icade_maps[j][rarch_keysym_lut[RETROK_z]].key = RETROK_DOWN;
219 icade_maps[j][rarch_keysym_lut[RETROK_a]].key = RETROK_LEFT;
220 icade_maps[j][rarch_keysym_lut[RETROK_q]].key = RETROK_LEFT;
221 icade_maps[j][rarch_keysym_lut[RETROK_c]].key = RETROK_RIGHT;
222 icade_maps[j][rarch_keysym_lut[RETROK_d]].key = RETROK_RIGHT;
223 icade_maps[j][rarch_keysym_lut[RETROK_u]].key = RETROK_x;
224 icade_maps[j][rarch_keysym_lut[RETROK_f]].key = RETROK_x;
225 icade_maps[j][rarch_keysym_lut[RETROK_h]].key = RETROK_z;
226 icade_maps[j][rarch_keysym_lut[RETROK_r]].key = RETROK_z;
227 icade_maps[j][rarch_keysym_lut[RETROK_y]].key = RETROK_a;
228 icade_maps[j][rarch_keysym_lut[RETROK_t]].key = RETROK_a;
229 icade_maps[j][rarch_keysym_lut[RETROK_j]].key = RETROK_s;
230 icade_maps[j][rarch_keysym_lut[RETROK_n]].key = RETROK_s;
231 icade_maps[j][rarch_keysym_lut[RETROK_k]].key = RETROK_q;
232 icade_maps[j][rarch_keysym_lut[RETROK_p]].key = RETROK_q;
233 icade_maps[j][rarch_keysym_lut[RETROK_i]].key = RETROK_w;
234 icade_maps[j][rarch_keysym_lut[RETROK_m]].key = RETROK_w;
235 icade_maps[j][rarch_keysym_lut[RETROK_l]].key = RETROK_RSHIFT;
236 icade_maps[j][rarch_keysym_lut[RETROK_v]].key = RETROK_RSHIFT;
237 icade_maps[j][rarch_keysym_lut[RETROK_o]].key = RETROK_RETURN;
238 icade_maps[j][rarch_keysym_lut[RETROK_g]].key = RETROK_RETURN;
239
240 icade_maps[j][rarch_keysym_lut[RETROK_v]].up = true;
241 icade_maps[j][rarch_keysym_lut[RETROK_g]].up = true;
242 icade_maps[j][rarch_keysym_lut[RETROK_e]].up = true;
243 icade_maps[j][rarch_keysym_lut[RETROK_z]].up = true;
244 icade_maps[j][rarch_keysym_lut[RETROK_q]].up = true;
245 icade_maps[j][rarch_keysym_lut[RETROK_c]].up = true;
246 icade_maps[j][rarch_keysym_lut[RETROK_r]].up = true;
247 icade_maps[j][rarch_keysym_lut[RETROK_f]].up = true;
248 icade_maps[j][rarch_keysym_lut[RETROK_n]].up = true;
249 icade_maps[j][rarch_keysym_lut[RETROK_t]].up = true;
250 icade_maps[j][rarch_keysym_lut[RETROK_p]].up = true;
251 icade_maps[j][rarch_keysym_lut[RETROK_m]].up = true;
252
253 initialized = true;
254 }
255
256 if ((*code < 0x20) && (icade_maps[kb_type_idx][*code].key != RETROK_UNKNOWN))
257 {
258 *keydown = icade_maps[kb_type_idx][*code].up ? false : true;
259 ret = true;
260 *code = rarch_keysym_lut[icade_maps[kb_type_idx][*code].key];
261 }
262
263 return ret;
264 }
265
apple_input_keyboard_event(bool down,unsigned code,uint32_t character,uint32_t mod,unsigned device)266 void apple_input_keyboard_event(bool down,
267 unsigned code, uint32_t character, uint32_t mod, unsigned device)
268 {
269 settings_t *settings = config_get_ptr();
270 bool keyboard_gamepad_enable = settings->bools.input_keyboard_gamepad_enable;
271 bool small_keyboard_enable = settings->bools.input_small_keyboard_enable;
272 code = HIDKEY(code);
273
274 if (keyboard_gamepad_enable)
275 {
276 if (handle_icade_event(&code, &down))
277 character = 0;
278 else
279 code = 0;
280 }
281 else if (small_keyboard_enable)
282 {
283 if (handle_small_keyboard(&code, down))
284 character = 0;
285 }
286
287 if (code == 0 || code >= MAX_KEYS)
288 return;
289
290 apple_key_state[code] = down;
291
292 input_keyboard_event(down,
293 input_keymaps_translate_keysym_to_rk(code),
294 character, (enum retro_mod)mod, device);
295 }
296 #else
297 /* Taken from https://github.com/depp/keycode,
298 * check keycode.h for license. */
299 static const unsigned char MAC_NATIVE_TO_HID[128] = {
300 4, 22, 7, 9, 11, 10, 29, 27, 6, 25,255, 5, 20, 26, 8, 21,
301 28, 23, 30, 31, 32, 33, 35, 34, 46, 38, 36, 45, 37, 39, 48, 18,
302 24, 47, 12, 19, 40, 15, 13, 52, 14, 51, 49, 54, 56, 17, 16, 55,
303 43, 44, 53, 42,255, 41,231,227,225, 57,226,224,229,230,228,255,
304 108, 99,255, 85,255, 87,255, 83,255,255,255, 84, 88,255, 86,109,
305 110,103, 98, 89, 90, 91, 92, 93, 94, 95,111, 96, 97,255,255,255,
306 62, 63, 64, 60, 65, 66,255, 68,255,104,107,105,255, 67,255, 69,
307 255,106,117, 74, 75, 76, 61, 77, 59, 78, 58, 80, 79, 81, 82,255
308 };
309
310 #define HIDKEY(X) (X < 128) ? MAC_NATIVE_TO_HID[X] : 0
311
apple_input_keyboard_event(bool down,unsigned code,uint32_t character,uint32_t mod,unsigned device)312 void apple_input_keyboard_event(bool down,
313 unsigned code, uint32_t character, uint32_t mod, unsigned device)
314 {
315 code = HIDKEY(code);
316 if (code == 0 || code >= MAX_KEYS)
317 return;
318
319 apple_key_state[code] = down;
320
321 input_keyboard_event(down,
322 input_keymaps_translate_keysym_to_rk(code),
323 character, (enum retro_mod)mod, device);
324 }
325 #endif
326
cocoa_input_init(const char * joypad_driver)327 static void *cocoa_input_init(const char *joypad_driver)
328 {
329 cocoa_input_data_t *apple = (cocoa_input_data_t*)calloc(1, sizeof(*apple));
330 if (!apple)
331 return NULL;
332
333 input_keymaps_init_keyboard_lut(rarch_key_map_apple_hid);
334
335 return apple;
336 }
337
cocoa_input_poll(void * data)338 static void cocoa_input_poll(void *data)
339 {
340 uint32_t i;
341 cocoa_input_data_t *apple = (cocoa_input_data_t*)data;
342 #ifndef IOS
343 float backing_scale_factor = cocoa_screen_get_backing_scale_factor();
344 #endif
345
346 if (!apple)
347 return;
348
349 for (i = 0; i < apple->touch_count; i++)
350 {
351 struct video_viewport vp;
352
353 vp.x = 0;
354 vp.y = 0;
355 vp.width = 0;
356 vp.height = 0;
357 vp.full_width = 0;
358 vp.full_height = 0;
359
360 #ifndef IOS
361 apple->touches[i].screen_x *= backing_scale_factor;
362 apple->touches[i].screen_y *= backing_scale_factor;
363 #endif
364 video_driver_translate_coord_viewport_wrap(
365 &vp,
366 apple->touches[i].screen_x,
367 apple->touches[i].screen_y,
368 &apple->touches[i].fixed_x,
369 &apple->touches[i].fixed_y,
370 &apple->touches[i].full_x,
371 &apple->touches[i].full_y);
372 }
373 }
374
cocoa_input_state(void * data,const input_device_driver_t * joypad,const input_device_driver_t * sec_joypad,rarch_joypad_info_t * joypad_info,const struct retro_keybind ** binds,bool keyboard_mapping_blocked,unsigned port,unsigned device,unsigned idx,unsigned id)375 static int16_t cocoa_input_state(
376 void *data,
377 const input_device_driver_t *joypad,
378 const input_device_driver_t *sec_joypad,
379 rarch_joypad_info_t *joypad_info,
380 const struct retro_keybind **binds,
381 bool keyboard_mapping_blocked,
382 unsigned port,
383 unsigned device,
384 unsigned idx,
385 unsigned id)
386 {
387 cocoa_input_data_t *apple = (cocoa_input_data_t*)data;
388
389 switch (device)
390 {
391 case RETRO_DEVICE_JOYPAD:
392 if (id == RETRO_DEVICE_ID_JOYPAD_MASK)
393 {
394 unsigned i;
395 /* Do a bitwise OR to combine both input
396 * states together */
397 int16_t ret = 0;
398
399 if (!keyboard_mapping_blocked)
400 {
401 for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
402 {
403 if ((binds[port][i].key < RETROK_LAST) && apple_key_state[rarch_keysym_lut[binds[port][i].key]])
404 ret |= (1 << i);
405 }
406 }
407 return ret;
408 }
409
410 if (binds[port][id].valid)
411 {
412 if (id < RARCH_BIND_LIST_END)
413 if (apple_key_state[rarch_keysym_lut[binds[port][id].key]])
414 return 1;
415 }
416 break;
417 case RETRO_DEVICE_ANALOG:
418 break;
419 case RETRO_DEVICE_KEYBOARD:
420 return (id < RETROK_LAST) && apple_key_state[rarch_keysym_lut[(enum retro_key)id]];
421 case RETRO_DEVICE_MOUSE:
422 case RARCH_DEVICE_MOUSE_SCREEN:
423 {
424 int16_t val = 0;
425 switch (id)
426 {
427 case RETRO_DEVICE_ID_MOUSE_X:
428 if (device == RARCH_DEVICE_MOUSE_SCREEN)
429 {
430 #ifdef IOS
431 return apple->window_pos_x;
432 #else
433 return apple->window_pos_x * cocoa_screen_get_backing_scale_factor();
434 #endif
435 }
436 val = apple->window_pos_x - apple->mouse_x_last;
437 apple->mouse_x_last = apple->window_pos_x;
438 return val;
439 case RETRO_DEVICE_ID_MOUSE_Y:
440 if (device == RARCH_DEVICE_MOUSE_SCREEN)
441 {
442 #ifdef IOS
443 return apple->window_pos_y;
444 #else
445 return apple->window_pos_y * cocoa_screen_get_backing_scale_factor();
446 #endif
447 }
448 val = apple->window_pos_y - apple->mouse_y_last;
449 apple->mouse_y_last = apple->window_pos_y;
450 return val;
451 case RETRO_DEVICE_ID_MOUSE_LEFT:
452 return apple->mouse_buttons & 1;
453 case RETRO_DEVICE_ID_MOUSE_RIGHT:
454 return apple->mouse_buttons & 2;
455 case RETRO_DEVICE_ID_MOUSE_WHEELUP:
456 return apple->mouse_wu;
457 case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
458 return apple->mouse_wd;
459 case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
460 return apple->mouse_wl;
461 case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
462 return apple->mouse_wr;
463 }
464 }
465 break;
466 case RETRO_DEVICE_POINTER:
467 case RARCH_DEVICE_POINTER_SCREEN:
468 {
469 const bool want_full = (device == RARCH_DEVICE_POINTER_SCREEN);
470
471 if (idx < apple->touch_count && (idx < MAX_TOUCHES))
472 {
473 int16_t x, y;
474 const cocoa_touch_data_t *touch = (const cocoa_touch_data_t *)
475 &apple->touches[idx];
476
477 if (!touch)
478 return 0;
479
480 x = touch->fixed_x;
481 y = touch->fixed_y;
482
483 if (want_full)
484 {
485 x = touch->full_x;
486 y = touch->full_y;
487 }
488
489 switch (id)
490 {
491 case RETRO_DEVICE_ID_POINTER_PRESSED:
492 return (x != -0x8000) && (y != -0x8000);
493 case RETRO_DEVICE_ID_POINTER_X:
494 return x;
495 case RETRO_DEVICE_ID_POINTER_Y:
496 return y;
497 case RETRO_DEVICE_ID_POINTER_COUNT:
498 return apple->touch_count;
499 }
500 }
501 }
502 break;
503 }
504
505 return 0;
506 }
507
cocoa_input_free(void * data)508 static void cocoa_input_free(void *data)
509 {
510 unsigned i;
511 cocoa_input_data_t *apple = (cocoa_input_data_t*)data;
512
513 if (!apple || !data)
514 return;
515
516 for (i = 0; i < MAX_KEYS; i++)
517 apple_key_state[i] = 0;
518
519 free(apple);
520 }
521
cocoa_input_get_capabilities(void * data)522 static uint64_t cocoa_input_get_capabilities(void *data)
523 {
524 return
525 (1 << RETRO_DEVICE_JOYPAD) |
526 (1 << RETRO_DEVICE_MOUSE) |
527 (1 << RETRO_DEVICE_KEYBOARD) |
528 (1 << RETRO_DEVICE_POINTER) |
529 (1 << RETRO_DEVICE_ANALOG);
530 }
531
532 input_driver_t input_cocoa = {
533 cocoa_input_init,
534 cocoa_input_poll,
535 cocoa_input_state,
536 cocoa_input_free,
537 NULL,
538 NULL,
539 cocoa_input_get_capabilities,
540 "cocoa",
541 NULL, /* grab_mouse */
542 NULL
543 };
544