1/*  Copyright 2010, 2011 Lawrence Sebald
2
3    This file is part of Yabause.
4
5    Yabause is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    Yabause is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with Yabause; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
18*/
19
20#include "PerCocoa.h"
21#include "yabause.h"
22
23#include <AppKit/NSEvent.h>
24#include <Foundation/NSUserDefaults.h>
25#include <Foundation/NSString.h>
26
27/* Forward Declarations. */
28static int PERCocoaInit(void);
29static void PERCocoaDeInit(void);
30static int PERCocoaHandleEvents(void);
31
32static u32 PERCocoaScan(u32 flags);
33static void PERCocoaFlush(void);
34static void PERCocoaKeyName(u32 key, char *name, int size);
35
36static PerPad_struct *c1 = NULL, *c2 = NULL;
37
38PerInterface_struct PERCocoa = {
39    PERCORE_COCOA,
40    "Cocoa Keyboard Input Interface",
41    &PERCocoaInit,
42    &PERCocoaDeInit,
43    &PERCocoaHandleEvents,
44    &PERCocoaScan,
45    0,
46    &PERCocoaFlush,
47    &PERCocoaKeyName
48};
49
50/* Utility function to check if everything's set up right for a port */
51static BOOL AllSetForPort(int p) {
52    int i;
53    NSString *str;
54    NSUserDefaults *d = [NSUserDefaults standardUserDefaults];
55    id val;
56    Class c = [NSNumber class];
57
58    for(i = 0; i < 13; ++i) {
59        str = [NSString stringWithFormat:@"Keyboard %d %s", p, PerPadNames[i]];
60        val = [d objectForKey:str];
61
62        if(!val || ![val isKindOfClass:c]) {
63            return NO;
64        }
65    }
66
67    return YES;
68}
69
70void PERCocoaSetKey(u32 key, u8 n, int p) {
71    PerPad_struct *c;
72    NSString *str;
73    NSUserDefaults *d = [NSUserDefaults standardUserDefaults];
74    NSNumber *val = [NSNumber numberWithUnsignedInt:(unsigned int)key];
75
76    assert(n <= PERPAD_Z);
77
78    /* Build the string we'll look for, and set the value for that key */
79    str = [NSString stringWithFormat:@"Pad %d %s", p, PerPadNames[n]];
80    [d setObject:val forKey:str];
81    [d synchronize];
82
83    /* Update the mapping if we're running */
84    if(p == 0) {
85        c = c1;
86    }
87    else {
88        c = c2;
89    }
90
91    /* This will effectively make sure we don't update until we've started. */
92    if(c) {
93        PerSetKey(key, n, c);
94    }
95}
96
97u32 PERCocoaGetKey(u8 n, int p) {
98    NSString *str;
99    id result;
100    NSUserDefaults *d = [NSUserDefaults standardUserDefaults];
101
102    assert(n <= PERPAD_Z);
103
104    /* Fetch the key data */
105    str = [NSString stringWithFormat:@"Pad %d %s", p, PerPadNames[n]];
106    result = [d objectForKey:str];
107
108    if(result && [result isKindOfClass:[NSNumber class]]) {
109        return (u32)[result unsignedIntValue];
110    }
111    else {
112        return (u32)-1;
113    }
114}
115static int PERCocoaInit(void) {
116    /* Fill in pad 1 */
117    c1 = PerPadAdd(&PORTDATA1);
118
119    PerSetKey(PERCocoaGetKey(PERPAD_UP, 0), PERPAD_UP, c1);
120    PerSetKey(PERCocoaGetKey(PERPAD_DOWN, 0), PERPAD_DOWN, c1);
121    PerSetKey(PERCocoaGetKey(PERPAD_LEFT, 0), PERPAD_LEFT, c1);
122    PerSetKey(PERCocoaGetKey(PERPAD_RIGHT, 0), PERPAD_RIGHT, c1);
123    PerSetKey(PERCocoaGetKey(PERPAD_LEFT_TRIGGER, 0), PERPAD_LEFT_TRIGGER, c1);
124    PerSetKey(PERCocoaGetKey(PERPAD_RIGHT_TRIGGER, 0), PERPAD_RIGHT_TRIGGER, c1);
125    PerSetKey(PERCocoaGetKey(PERPAD_START, 0), PERPAD_START, c1);
126    PerSetKey(PERCocoaGetKey(PERPAD_A, 0), PERPAD_A, c1);
127    PerSetKey(PERCocoaGetKey(PERPAD_B, 0), PERPAD_B, c1);
128    PerSetKey(PERCocoaGetKey(PERPAD_C, 0), PERPAD_C, c1);
129    PerSetKey(PERCocoaGetKey(PERPAD_X, 0), PERPAD_X, c1);
130    PerSetKey(PERCocoaGetKey(PERPAD_Y, 0), PERPAD_Y, c1);
131    PerSetKey(PERCocoaGetKey(PERPAD_Z, 0), PERPAD_Z, c1);
132
133    /* Fill in pad 2 */
134    c2 = PerPadAdd(&PORTDATA2);
135
136    PerSetKey(PERCocoaGetKey(PERPAD_UP, 1), PERPAD_UP, c2);
137    PerSetKey(PERCocoaGetKey(PERPAD_DOWN, 1), PERPAD_DOWN, c2);
138    PerSetKey(PERCocoaGetKey(PERPAD_LEFT, 1), PERPAD_LEFT, c2);
139    PerSetKey(PERCocoaGetKey(PERPAD_RIGHT, 1), PERPAD_RIGHT, c2);
140    PerSetKey(PERCocoaGetKey(PERPAD_LEFT_TRIGGER, 1), PERPAD_LEFT_TRIGGER, c2);
141    PerSetKey(PERCocoaGetKey(PERPAD_RIGHT_TRIGGER, 1), PERPAD_RIGHT_TRIGGER, c2);
142    PerSetKey(PERCocoaGetKey(PERPAD_START, 1), PERPAD_START, c2);
143    PerSetKey(PERCocoaGetKey(PERPAD_A, 1), PERPAD_A, c2);
144    PerSetKey(PERCocoaGetKey(PERPAD_B, 1), PERPAD_B, c2);
145    PerSetKey(PERCocoaGetKey(PERPAD_C, 1), PERPAD_C, c2);
146    PerSetKey(PERCocoaGetKey(PERPAD_X, 1), PERPAD_X, c2);
147    PerSetKey(PERCocoaGetKey(PERPAD_Y, 1), PERPAD_Y, c2);
148    PerSetKey(PERCocoaGetKey(PERPAD_Z, 1), PERPAD_Z, c2);
149
150    return 0;
151}
152
153static void PERCocoaDeInit(void) {
154}
155
156static int PERCocoaHandleEvents(void) {
157    return YabauseExec();
158}
159
160static u32 PERCocoaScan(u32 flags) {
161    return 0;
162}
163
164static void PERCocoaFlush(void) {
165}
166
167static void PERCocoaKeyName(u32 key, char *name, int size)    {
168    snprintf(name, size, "%x", (unsigned int)key);
169}
170