snes mouse support
[drnoksnes] / platform / hgw.cpp
1 #include <stdio.h>
2 #include <hgw/hgw.h>
3
4 #include "platform.h"
5 #include "hgw.h"
6 #include "snes9x.h"
7
8 #define DIE(format, ...) do { \
9                 fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
10                 fprintf(stderr, format "\n", ## __VA_ARGS__); \
11                 abort(); \
12         } while (0);
13
14
15 bool hgwLaunched;
16 static HgwContext *hgw;
17
18 static void createActionMappingsOnly();
19 static void parseGConfKeyMappings();
20
21 void HgwInit()
22 {
23         // hildon-games-wrapper sets this env variable for itself.
24         char* service = getenv("HGW_EXEC_SERVICE");
25         
26         if (!service) {
27                 // Not launched from hildon-games-wrapper
28                 hgwLaunched = false;
29                 return;
30         }
31         
32         hgw = hgw_context_init();
33         
34         if (!hgw) {
35                 fprintf(stderr, "Error opening hgw context\n");
36                 hgwLaunched = false;
37         }
38         
39         hgwLaunched = true;
40         printf("Loading in HGW mode\n");
41 }
42
43 void HgwDeinit()
44 {
45         if (!hgwLaunched) return;
46
47         hgw_context_destroy(hgw,
48                 (Config.snapshotSave ? HGW_BYE_PAUSED : HGW_BYE_INACTIVE));
49
50         hgw = 0;
51 }
52
53 void HgwConfig()
54 {
55         if (!hgwLaunched) return;
56         
57         Config.fullscreen = true;
58         
59         char romFile[PATH_MAX + 1];
60         if (hgw_conf_request_string(hgw, kGConfRomFile, romFile) == HGW_ERR_NONE) {
61                 S9xSetRomFile(romFile);
62         } else {
63                 hgw_context_destroy(hgw, HGW_BYE_INACTIVE);
64                 DIE("No Rom in Gconf!");
65         }
66
67         char no_audio = FALSE;
68         if (hgw_conf_request_bool(hgw, kGConfDisableAudio, &no_audio) == HGW_ERR_NONE) {
69                 Config.enableAudio = no_audio ? false : true;
70         }
71
72         char turbo = FALSE;
73         if (hgw_conf_request_bool(hgw, kGConfTurboMode, &turbo) == HGW_ERR_NONE) {
74                 Settings.TurboMode = turbo ? TRUE : FALSE;
75         }
76
77         int frameskip = 0;
78         if (hgw_conf_request_int(hgw, kGConfFrameskip, &frameskip) == HGW_ERR_NONE) {
79                 Settings.SkipFrames = (frameskip > 0 ? frameskip : AUTO_FRAMERATE);
80         }
81
82         char transparency = FALSE;
83         if (hgw_conf_request_bool(hgw, kGConfTransparency, &transparency) == HGW_ERR_NONE) {
84                 Settings.Transparency = transparency ? TRUE : FALSE;
85         }
86
87 #if 0
88         char displayFramerate = FALSE;
89         if (hgw_conf_request_bool(hgw, kGConfDisplayFramerate, &displayFramerate) == HGW_ERR_NONE) {
90                 Settings.DisplayFrameRate = displayFramerate ? TRUE : FALSE;
91         }
92 #endif
93
94         int speedhacks = 0;
95         if (hgw_conf_request_int(hgw, kGConfFrameskip, &speedhacks) == HGW_ERR_NONE) {
96                 if (speedhacks <= 0) {
97                         Settings.HacksEnabled = FALSE;
98                         Settings.HacksFilter = FALSE;
99                 } else if (speedhacks == 1) {
100                         Settings.HacksEnabled = TRUE;
101                         Settings.HacksFilter = TRUE;
102                 } else {
103                         Settings.HacksEnabled = TRUE;
104                         Settings.HacksFilter = FALSE;
105                 }
106         }
107
108         int mappings = 0;
109         if (hgw_conf_request_int(hgw, kGConfMapping, &mappings) == HGW_ERR_NONE) {
110                 switch (mappings) {
111                         case 0:
112                                 // Do nothing, leave mappings as is.
113                                 break;
114                         case 1: // Keys
115                                 parseGConfKeyMappings();
116                                 break;
117                         case 2: // Touchscreen
118                                 Config.touchscreenInput = true;
119                                 createActionMappingsOnly();
120                                 break;
121                         case 3: // Touchscreen + keys
122                                 Config.touchscreenInput = true;
123                                 parseGConfKeyMappings();
124                                 break;
125                         case 4: // Mouse
126                                 Settings.Mouse = TRUE;
127                                 Settings.ControllerOption = SNES_MOUSE_SWAPPED;
128                                 createActionMappingsOnly();
129                                 break;
130                         case 5: // Mouse + keys
131                                 Settings.Mouse = TRUE;
132                                 Settings.ControllerOption = SNES_MOUSE;
133                                 parseGConfKeyMappings();
134                                 break;
135                 }
136         }
137
138         HgwStartCommand cmd = hgw_context_get_start_command(hgw);
139         switch (cmd) {
140                 default:
141                 case HGW_COMM_NONE:     // called from libosso
142                 case HGW_COMM_CONT:
143                         Config.snapshotLoad = true;
144                         Config.snapshotSave = true;
145                         break;
146                 case HGW_COMM_RESTART:
147                         Config.snapshotLoad = false;
148                         Config.snapshotSave = true;
149                         break;
150                 case HGW_COMM_QUIT:
151                         // hum, what?
152                         Config.snapshotLoad = false;
153                         Config.snapshotSave = false;
154                         Config.quitting = true;
155                         break;
156         }
157 }
158
159 void HgwPollEvents()
160 {
161         if (!hgwLaunched) return;
162         
163         HgwMessage msg;
164         HgwMessageFlags flags = HGW_MSG_FLAG_NONE;
165         
166         if ( hgw_msg_check_incoming(hgw, &msg, flags) == HGW_ERR_COMMUNICATION ) {
167                 // Message Incoming, process msg
168                 
169                 switch (msg.type) {
170                         case HGW_MSG_TYPE_CBREQ:
171                                 switch (msg.e_val) {
172                                         case HGW_CB_QUIT:
173                                         case HGW_CB_EXIT:
174                                                 Config.quitting = true;
175                                                 break;
176                                 }
177                                 break;
178                         case HGW_MSG_TYPE_DEVSTATE:
179                                 switch (msg.e_val) {
180                                         case HGW_DEVICE_STATE_SHUTDOWN:
181                                                 Config.quitting = true; // try to quit gracefully
182                                                 break;
183                                 }
184                                 break;
185                         default:
186                                 // do nothing
187                                 break;
188                 }
189                 
190                 hgw_msg_free_data(&msg);
191         }
192 }
193
194 // For now, please keep this in sync with ../gui/controls.c
195 typedef struct ButtonEntry {
196         char * gconf_key;
197         unsigned long mask;
198         bool is_action;
199 } ButtonEntry;
200 #define BUTTON_INITIALIZER(button, name) \
201         { kGConfKeysPath "/" name, SNES_##button##_MASK, false }
202 #define ACTION_INITIALIZER(action, name) \
203         { kGConfKeysPath "/" name, kAction##action, true }
204 #define BUTTON_LAST     \
205         { 0 }
206 static const ButtonEntry buttons[] = {
207         BUTTON_INITIALIZER(A, "a"),
208         BUTTON_INITIALIZER(B, "b"),
209         BUTTON_INITIALIZER(X, "x"),
210         BUTTON_INITIALIZER(Y, "y"),
211         BUTTON_INITIALIZER(TL, "l"),
212         BUTTON_INITIALIZER(TR, "r"),
213         BUTTON_INITIALIZER(START, "start"),
214         BUTTON_INITIALIZER(SELECT, "select"),
215         BUTTON_INITIALIZER(UP, "up"),
216         BUTTON_INITIALIZER(DOWN, "down"),
217         BUTTON_INITIALIZER(LEFT, "left"),
218         BUTTON_INITIALIZER(RIGHT, "right"),
219         ACTION_INITIALIZER(Quit, "quit"),
220         ACTION_INITIALIZER(ToggleFullscreen, "fullscreen"),
221         BUTTON_LAST
222 };
223
224 static void createActionMappingsOnly()
225 {
226         // Discard any other mapping
227         ZeroMemory(Config.joypad1Mapping, sizeof(Config.joypad1Mapping));
228         ZeroMemory(Config.action, sizeof(Config.action));
229         
230         // Map quit to fullscreen and escape
231         Config.action[72] = kActionQuit;
232         Config.action[9] = kActionQuit;
233 }
234
235 static void parseGConfKeyMappings()
236 {
237         // Discard any other mapping
238         ZeroMemory(Config.joypad1Mapping, sizeof(Config.joypad1Mapping));
239         ZeroMemory(Config.action, sizeof(Config.action));
240
241         // If the user does not map fullscreen or quit
242         bool quit_mapped = false;
243
244         printf("Hgw: Using gconf key mappings\n");
245
246         int i, scancode;
247         for (i = 0; buttons[i].gconf_key; i++) {
248                 if (hgw_conf_request_int(hgw, buttons[i].gconf_key, &scancode) == HGW_ERR_NONE) {
249                         if (scancode <= 0 || scancode > 255) continue;
250
251                         if (buttons[i].is_action) {
252                                 Config.action[scancode] |= buttons[i].mask;
253                                 if (buttons[i].mask & (kActionQuit | kActionToggleFullscreen)) {
254                                         quit_mapped = true;
255                                 }
256                         } else {
257                                 Config.joypad1Mapping[scancode] |= buttons[i].mask;
258                         }
259                 }
260         }
261
262         // Safeguards
263         if (!quit_mapped) {
264                 // Newbie user won't know how to quit game.
265                 if (!Config.joypad1Mapping[72] && !Config.action[72]) {
266                         // Fullscreen key is not mapped, map
267                         Config.action[72] = kActionQuit;
268                         quit_mapped = true;
269                 }
270                 if (!quit_mapped && !Config.joypad1Mapping[9] && !Config.action[9]) {
271                         // Escape key is not mapped, map
272                         // But only if we couldn't map quit to fullscreen. Some people
273                         // actually want Quit not to be mapped.
274                         Config.action[9] = kActionQuit;
275                         quit_mapped = true;
276                 }
277                 if (!quit_mapped) {
278                         // Force mapping of fullscreen to Quit if can't map anywhere else.
279                         Config.joypad1Mapping[72] = 0;
280                         Config.action[72] = kActionQuit;
281                 }
282         }
283 }
284