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