1 /*****************************************************************************\
2      Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3                 This file is licensed under the Snes9x License.
4    For further information, consult the LICENSE file in the root directory.
5 \*****************************************************************************/
6 
7 #include <fcntl.h>
8 
9 #include "gtk_s9xcore.h"
10 #include "gtk_s9x.h"
11 #include "gtk_config.h"
12 #include "gtk_control.h"
13 #include "gtk_file.h"
14 
15 const BindingLink b_links[] =
16 {
17         /* Joypad-specific bindings. "Joypad# " will be prepended */
18         { "b_up",        "Up"          },
19         { "b_down",      "Down"        },
20         { "b_left",      "Left"        },
21         { "b_right",     "Right"       },
22         { "b_start",     "Start"       },
23         { "b_select",    "Select"      },
24         { "b_a",         "A"           },
25         { "b_b",         "B"           },
26         { "b_x",         "X"           },
27         { "b_y",         "Y"           },
28         { "b_l",         "L"           },
29         { "b_r",         "R"           },
30         { "b_a_turbo",   "Turbo A"     },
31         { "b_b_turbo",   "Turbo B"     },
32         { "b_x_turbo",   "Turbo X"     },
33         { "b_y_turbo",   "Turbo Y"     },
34         { "b_l_turbo",   "Turbo L"     },
35         { "b_r_turbo",   "Turbo R"     },
36         { "b_a_sticky",  "Sticky A"    },
37         { "b_b_sticky",  "Sticky B"    },
38         { "b_x_sticky",  "Sticky X"    },
39         { "b_y_sticky",  "Sticky Y"    },
40         { "b_l_sticky",  "Sticky L"    },
41         { "b_r_sticky",  "Sticky R"    },
42 
43         /* Emulator based bindings */
44         { "b_open_rom",            "GTK_open_rom"      },
45         { "b_enable_turbo",        "EmuTurbo"          },
46         { "b_toggle_turbo",        "ToggleEmuTurbo"    },
47         { "b_pause",               "GTK_pause"         },
48         { "b_decrease_frame_rate", "DecFrameRate"      },
49         { "b_increase_frame_rate", "IncFrameRate"      },
50         { "b_decrease_frame_time", "DecFrameTime"      },
51         { "b_increase_frame_time", "IncFrameTime"      },
52         { "b_hardware_reset",      "Reset"             },
53         { "b_soft_reset",          "SoftReset"         },
54         { "b_quit",                "GTK_quit"          },
55         { "b_bg_layer_0",          "ToggleBG0"         },
56         { "b_bg_layer_1",          "ToggleBG1"         },
57         { "b_bg_layer_2",          "ToggleBG2"         },
58         { "b_bg_layer_3",          "ToggleBG3"         },
59         { "b_sprites",             "ToggleSprites"     },
60         { "b_bg_layering_hack",    "BGLayeringHack"    },
61         { "b_screenshot",          "Screenshot"        },
62         { "b_fullscreen",          "GTK_fullscreen"    },
63         { "b_state_save_current",  "GTK_state_save_current" },
64         { "b_state_load_current",  "GTK_state_load_current" },
65         { "b_state_increment_save","GTK_state_increment_save" },
66         { "b_state_decrement_load","GTK_state_decrement_load" },
67         { "b_state_increment",     "GTK_state_increment" },
68         { "b_state_decrement",     "GTK_state_decrement" },
69         { "b_save_0",              "QuickSave000"      },
70         { "b_save_1",              "QuickSave001"      },
71         { "b_save_2",              "QuickSave002"      },
72         { "b_save_3",              "QuickSave003"      },
73         { "b_save_4",              "QuickSave004"      },
74         { "b_save_5",              "QuickSave005"      },
75         { "b_save_6",              "QuickSave006"      },
76         { "b_save_7",              "QuickSave007"      },
77         { "b_save_8",              "QuickSave008"      },
78         { "b_save_9",              "QuickSave009"      },
79         { "b_load_0",              "QuickLoad000"      },
80         { "b_load_1",              "QuickLoad001"      },
81         { "b_load_2",              "QuickLoad002"      },
82         { "b_load_3",              "QuickLoad003"      },
83         { "b_load_4",              "QuickLoad004"      },
84         { "b_load_5",              "QuickLoad005"      },
85         { "b_load_6",              "QuickLoad006"      },
86         { "b_load_7",              "QuickLoad007"      },
87         { "b_load_8",              "QuickLoad008"      },
88         { "b_load_9",              "QuickLoad009"      },
89         { "b_sound_channel_0",     "SoundChannel0"     },
90         { "b_sound_channel_1",     "SoundChannel1"     },
91         { "b_sound_channel_2",     "SoundChannel2"     },
92         { "b_sound_channel_3",     "SoundChannel3"     },
93         { "b_sound_channel_4",     "SoundChannel4"     },
94         { "b_sound_channel_5",     "SoundChannel5"     },
95         { "b_sound_channel_6",     "SoundChannel6"     },
96         { "b_sound_channel_7",     "SoundChannel7"     },
97         { "b_all_sound_channels",  "SoundChannelsOn"   },
98         { "b_save_spc",            "GTK_save_spc"      },
99         { "b_begin_recording_movie", "BeginRecordingMovie" },
100         { "b_stop_recording_movie", "EndRecordingMovie" },
101         { "b_load_movie",          "LoadMovie" },
102         { "b_seek_to_frame",       "GTK_seek_to_frame" },
103         { "b_swap_controllers",    "GTK_swap_controllers" },
104         { "b_rewind",              "GTK_rewind"        },
105         { "b_grab_mouse",          "GTK_grab_mouse"    },
106 
107         { NULL, NULL }
108 };
109 
110 /* Where the page breaks occur in the preferences pane */
111 const int b_breaks[] =
112 {
113         12, /* End of main buttons */
114         24, /* End of turbo/sticky buttons */
115         35, /* End of base emulator buttons */
116         43, /* End of Graphic options */
117         69, /* End of save/load states */
118         78, /* End of sound buttons */
119         86, /* End of miscellaneous buttons */
120         -1
121 };
122 
123 static int joystick_lock = 0;
124 
S9xPollButton(uint32 id,bool * pressed)125 bool S9xPollButton (uint32 id, bool *pressed)
126 {
127     return true;
128 }
129 
S9xPollAxis(uint32 id,int16 * value)130 bool S9xPollAxis (uint32 id, int16 *value)
131 {
132     return true;
133 }
134 
S9xPollPointer(uint32 id,int16 * x,int16 * y)135 bool S9xPollPointer (uint32 id, int16 *x, int16 *y)
136 {
137     *x = top_level->snes_mouse_x;
138     *y = top_level->snes_mouse_y;
139 
140     return true;
141 }
142 
S9xIsMousePluggedIn()143 bool S9xIsMousePluggedIn ()
144 {
145     enum controllers ctl;
146     int8 id1, id2, id3, id4;
147 
148     for (int i = 0; i <= 1; i++)
149     {
150         S9xGetController (i, &ctl, &id1, &id2, &id3, &id4);
151         if (ctl == CTL_MOUSE || ctl == CTL_SUPERSCOPE)
152             return true;
153     }
154 
155     return false;
156 }
157 
S9xGrabJoysticks()158 bool S9xGrabJoysticks ()
159 {
160     if (joystick_lock)
161         return false;
162 
163     joystick_lock++;
164 
165     return true;
166 }
167 
S9xReleaseJoysticks()168 void S9xReleaseJoysticks ()
169 {
170     joystick_lock--;
171 }
172 
swap_controllers_1_2()173 static void swap_controllers_1_2 ()
174 {
175     JoypadBinding interrim;
176 
177     interrim = gui_config->pad[0];
178     gui_config->pad[0] = gui_config->pad[1];
179     gui_config->pad[1] = interrim;
180 
181     gui_config->rebind_keys ();
182 }
183 
change_slot(int difference)184 static void change_slot (int difference)
185 {
186     static char buf[256];
187 
188     gui_config->current_save_slot += difference;
189     gui_config->current_save_slot %= 1000;
190     if (gui_config->current_save_slot < 0)
191         gui_config->current_save_slot += 1000;
192     if (!gui_config->rom_loaded)
193         return;
194 
195     snprintf (buf, 256, "State Slot: %d", gui_config->current_save_slot);
196     S9xSetInfoString (buf);
197     GFX.InfoStringTimeout = 60;
198 }
199 
S9xHandlePortCommand(s9xcommand_t cmd,int16 data1,int16 data2)200 void S9xHandlePortCommand (s9xcommand_t cmd, int16 data1, int16 data2)
201 {
202     static bool quit_binding_down = false;
203 
204     if (data1 == true)
205     {
206         if (cmd.port[0] == PORT_QUIT)
207             quit_binding_down = true;
208         else if (cmd.port[0] == PORT_REWIND)
209             Settings.Rewinding = true;
210     }
211 
212     if (data1 == false) /* Release */
213     {
214         if (cmd.port[0] != PORT_QUIT)
215         {
216             quit_binding_down = false;
217         }
218 
219         if (cmd.port[0] == PORT_COMMAND_FULLSCREEN)
220         {
221             top_level->toggle_fullscreen_mode ();
222         }
223 
224         else if (cmd.port[0] == PORT_COMMAND_SAVE_SPC)
225         {
226             top_level->save_spc_dialog ();
227         }
228 
229         else if (cmd.port[0] == PORT_OPEN_ROM)
230         {
231             top_level->open_rom_dialog ();
232         }
233 
234         else if (cmd.port[0] == PORT_PAUSE)
235         {
236             if (!(top_level->user_pause))
237                 top_level->pause_from_user ();
238             else
239                 top_level->unpause_from_user ();
240         }
241 
242         else if (cmd.port[0] == PORT_REWIND)
243         {
244             Settings.Rewinding = false;
245         }
246 
247         else if (cmd.port[0] == PORT_SEEK_TO_FRAME)
248         {
249             top_level->movie_seek_dialog ();
250         }
251 
252         else if (cmd.port[0] == PORT_SWAP_CONTROLLERS)
253         {
254             swap_controllers_1_2 ();
255         }
256 
257         else if (cmd.port[0] == PORT_QUIT)
258         {
259             if (quit_binding_down)
260                 S9xExit ();
261         }
262 
263         else if (cmd.port[0] >= PORT_QUICKLOAD0 && cmd.port[0] <= PORT_QUICKLOAD9)
264         {
265             S9xQuickLoadSlot (cmd.port[0] - PORT_QUICKLOAD0);
266         }
267 
268         else if (cmd.port[0] == PORT_SAVESLOT)
269         {
270             S9xQuickSaveSlot (gui_config->current_save_slot);
271         }
272 
273         else if (cmd.port[0] == PORT_LOADSLOT)
274         {
275             S9xQuickLoadSlot (gui_config->current_save_slot);
276         }
277 
278         else if (cmd.port[0] == PORT_INCREMENTSAVESLOT)
279         {
280             change_slot (1);
281             S9xQuickSaveSlot (gui_config->current_save_slot);
282         }
283 
284         else if (cmd.port[0] == PORT_DECREMENTLOADSLOT)
285         {
286             change_slot (-1);
287             S9xQuickLoadSlot (gui_config->current_save_slot);
288         }
289 
290         else if (cmd.port[0] == PORT_INCREMENTSLOT)
291         {
292             change_slot (1);
293         }
294 
295         else if (cmd.port[0] == PORT_DECREMENTSLOT)
296         {
297             change_slot (-1);
298         }
299 
300         else if (cmd.port[0] == PORT_GRABMOUSE)
301         {
302             top_level->toggle_grab_mouse ();
303         }
304     }
305 }
306 
S9xGetBindingByName(const char * name)307 Binding S9xGetBindingByName (const char *name)
308 {
309     for (int i = 0; i < NUM_EMU_LINKS; i++)
310     {
311         if (!strcasecmp (b_links[i + NUM_JOYPAD_LINKS].snes9x_name, name))
312         {
313             return gui_config->shortcut[i];
314         }
315     }
316 
317     return Binding ();
318 }
319 
S9xGetPortCommandT(const char * name)320 s9xcommand_t S9xGetPortCommandT (const char *name)
321 {
322     s9xcommand_t cmd;
323 
324     cmd.type = S9xButtonPort;
325     cmd.multi_press = 0;
326     cmd.button_norpt = 0;
327     cmd.port[0] = 0;
328     cmd.port[1] = 0;
329     cmd.port[2] = 0;
330     cmd.port[3] = 0;
331 
332     if (!strcasecmp (name, "GTK_fullscreen"))
333     {
334         cmd.port[0] = PORT_COMMAND_FULLSCREEN;
335     }
336 
337     else if (!strcasecmp (name, "GTK_save_spc"))
338     {
339         cmd.port[0] = PORT_COMMAND_SAVE_SPC;
340     }
341 
342     else if (!strcasecmp (name, "GTK_open_rom"))
343     {
344         cmd.port[0] = PORT_OPEN_ROM;
345     }
346 
347     else if (!strcasecmp (name, "GTK_pause"))
348     {
349         cmd.port[0] = PORT_PAUSE;
350     }
351 
352     else if (!strcasecmp (name, "GTK_seek_to_frame"))
353     {
354         cmd.port[0] = PORT_SEEK_TO_FRAME;
355     }
356 
357     else if (!strcasecmp (name, "GTK_quit"))
358     {
359         cmd.port[0] = PORT_QUIT;
360     }
361 
362     else if (!strcasecmp (name, "GTK_swap_controllers"))
363     {
364         cmd.port[0] = PORT_SWAP_CONTROLLERS;
365     }
366 
367     else if (!strcasecmp (name, "GTK_rewind"))
368     {
369         cmd.port[0] = PORT_REWIND;
370     }
371 
372     else if (strstr (name, "QuickLoad000"))
373     {
374         cmd.port[0] = PORT_QUICKLOAD0;
375     }
376 
377     else if (strstr (name, "QuickLoad001"))
378     {
379         cmd.port[0] = PORT_QUICKLOAD1;
380     }
381 
382     else if (strstr (name, "QuickLoad002"))
383     {
384         cmd.port[0] = PORT_QUICKLOAD2;
385     }
386 
387     else if (strstr (name, "QuickLoad003"))
388     {
389         cmd.port[0] = PORT_QUICKLOAD3;
390     }
391 
392     else if (strstr (name, "QuickLoad004"))
393     {
394         cmd.port[0] = PORT_QUICKLOAD4;
395     }
396 
397     else if (strstr (name, "QuickLoad005"))
398     {
399         cmd.port[0] = PORT_QUICKLOAD5;
400     }
401 
402     else if (strstr (name, "QuickLoad006"))
403     {
404         cmd.port[0] = PORT_QUICKLOAD6;
405     }
406 
407     else if (strstr (name, "QuickLoad007"))
408     {
409         cmd.port[0] = PORT_QUICKLOAD7;
410     }
411 
412     else if (strstr (name, "QuickLoad008"))
413     {
414         cmd.port[0] = PORT_QUICKLOAD8;
415     }
416 
417     else if (strstr (name, "QuickLoad009"))
418     {
419         cmd.port[0] = PORT_QUICKLOAD9;
420     }
421 
422     else if (strstr (name, "GTK_state_save_current"))
423     {
424         cmd.port[0] = PORT_SAVESLOT;
425     }
426 
427     else if (strstr (name, "GTK_state_load_current"))
428     {
429         cmd.port[0] = PORT_LOADSLOT;
430     }
431 
432     else if (strstr (name, "GTK_state_increment_save"))
433     {
434         cmd.port[0] = PORT_INCREMENTSAVESLOT;
435     }
436 
437     else if (strstr (name, "GTK_state_decrement_load"))
438     {
439         cmd.port[0] = PORT_DECREMENTLOADSLOT;
440     }
441 
442     else if (strstr (name, "GTK_state_increment"))
443     {
444         cmd.port[0] = PORT_INCREMENTSLOT;
445     }
446 
447     else if (strstr (name, "GTK_state_decrement"))
448     {
449         cmd.port[0] = PORT_DECREMENTSLOT;
450     }
451 
452     else if (strstr (name, "GTK_grab_mouse"))
453     {
454         cmd.port[0] = PORT_GRABMOUSE;
455     }
456 
457 
458     else
459     {
460         cmd = S9xGetCommandT (name);
461     }
462 
463     return cmd;
464 }
465 
S9xProcessEvents(bool8 block)466 void S9xProcessEvents (bool8 block)
467 {
468     JoyEvent event;
469     Binding  binding;
470 
471     if (S9xGrabJoysticks ())
472     {
473         for (int i = 0; gui_config->joystick[i]; i++)
474         {
475             while (gui_config->joystick[i]->get_event (&event))
476             {
477                 binding = Binding (i, event.parameter, 0);
478                 S9xReportButton (binding.hex (), event.state == JOY_PRESSED ? 1 : 0);
479                 gui_config->screensaver_needs_reset = true;
480             }
481         }
482 
483         S9xReleaseJoysticks ();
484     }
485 }
486 
poll_joystick_events()487 static void poll_joystick_events ()
488 {
489     SDL_Event event;
490 
491     while (SDL_PollEvent (&event))
492     {
493         if (event.type == SDL_JOYAXISMOTION)
494         {
495              gui_config->joystick[event.jaxis.which]->handle_event (&event);
496         }
497 
498         else if (event.type == SDL_JOYHATMOTION)
499         {
500             gui_config->joystick[event.jhat.which]->handle_event (&event);
501         }
502 
503         else if (event.type == SDL_JOYBUTTONUP ||
504                  event.type == SDL_JOYBUTTONDOWN)
505         {
506             gui_config->joystick[event.jbutton.which]->handle_event (&event);
507         }
508     }
509 }
510 
S9xInitInputDevices()511 void S9xInitInputDevices ()
512 {
513     SDL_Init (SDL_INIT_JOYSTICK);
514 
515     for (int i = 0; ; i++)
516     {
517         gui_config->joystick = (JoyDevice **)
518             realloc (gui_config->joystick,
519                      sizeof (JoyDevice *) * (i + 1));
520 
521         gui_config->joystick[i] = new JoyDevice (i);
522 
523         if (!gui_config->joystick[i]->enabled)
524         {
525             delete gui_config->joystick[i];
526             gui_config->joystick[i] = NULL;
527             break;
528         }
529         else
530         {
531             gui_config->joystick[i]->joynum = i;
532         }
533     }
534 
535     //First plug in both, they'll change later as needed
536     S9xSetController (0, CTL_JOYPAD,     0, 0, 0, 0);
537     S9xSetController (1, CTL_JOYPAD,     1, 0, 0, 0);
538 }
539 
S9xDeinitInputDevices()540 void S9xDeinitInputDevices ()
541 {
542     for (int i = 0; gui_config->joystick[i] != NULL; i++)
543     {
544         delete gui_config->joystick[i];
545     }
546 
547     free (gui_config->joystick);
548 
549     SDL_Quit ();
550 }
551 
JoyDevice(unsigned int device_num)552 JoyDevice::JoyDevice (unsigned int device_num)
553 {
554     enabled = false;
555     axis = NULL;
556     filedes = NULL;
557     mode = JOY_MODE_INDIVIDUAL;
558 
559     if ((int) device_num >= SDL_NumJoysticks ())
560         return;
561 
562     filedes = SDL_JoystickOpen (device_num);
563 
564     if (!filedes)
565         return;
566 
567     enabled = true;
568 
569     num_axes = SDL_JoystickNumAxes (filedes);
570     num_hats = SDL_JoystickNumHats (filedes);
571     axis = new int[num_axes];
572     hat = new int[num_hats];
573     calibration = new Calibration[num_axes];
574 
575     for (int i = 0; i < num_axes; i++)
576     {
577         calibration[i].min = -32767;
578         calibration[i].max = 32767;
579         calibration[i].center = 0;
580     }
581 
582     printf ("Joystick %d, %s:\n  %d axes, %d buttons, %d hats\n",
583             device_num + 1,
584             SDL_JoystickName (filedes),
585             SDL_JoystickNumButtons (filedes),
586             num_axes,
587             num_hats);
588 
589     memset (axis, 0, sizeof (int) * num_axes);
590 }
591 
~JoyDevice()592 JoyDevice::~JoyDevice ()
593 {
594     if (enabled)
595     {
596         SDL_JoystickClose (filedes);
597         delete[] axis;
598         delete[] hat;
599         delete[] calibration;
600     }
601 
602     enabled = false;
603 }
604 
add_event(unsigned int parameter,unsigned int state)605 void JoyDevice::add_event (unsigned int parameter, unsigned int state)
606 {
607     JoyEvent event = { parameter, state };
608 
609     queue.push (event);
610 }
611 
register_centers()612 void JoyDevice::register_centers ()
613 {
614     for (int i = 0; i < num_axes; i++)
615     {
616         calibration[i].center = SDL_JoystickGetAxis (filedes, i);
617 
618         /* Snap centers to specific target points */
619         if (calibration[i].center < -24576)
620             calibration[i].center = -32768;
621         else if (calibration[i].center < -8192)
622             calibration[i].center = -16384;
623         else if (calibration[i].center < 8192)
624             calibration[i].center = 0;
625         else if (calibration[i].center < 24576)
626             calibration[i].center = 16383;
627         else
628             calibration[i].center = 32767;
629     }
630 }
631 
handle_event(SDL_Event * event)632 void JoyDevice::handle_event (SDL_Event *event)
633 {
634     if (event->type == SDL_JOYAXISMOTION)
635     {
636         int cal_min = calibration[event->jaxis.axis].min;
637         int cal_max = calibration[event->jaxis.axis].max;
638         int cal_cen = calibration[event->jaxis.axis].center;
639         int t = gui_config->joystick_threshold;
640         int ax_min = (cal_min - cal_cen) * t / 100 + cal_cen;
641         int ax_max = (cal_max - cal_cen) * t / 100 + cal_cen;
642 
643         if (mode == JOY_MODE_INDIVIDUAL)
644         {
645             for (int i = 0; i < NUM_JOYPADS; i++)
646             {
647                 Binding *pad = (Binding *) &(gui_config->pad[i]);
648 
649                 for (int j = 0; j < NUM_JOYPAD_LINKS; j++)
650                 {
651                     if (pad[j].get_axis () == event->jaxis.axis &&
652                         pad[j].get_device () == (unsigned int) (joynum + 1))
653                     {
654                         t = pad[j].get_threshold ();
655 
656                         if (pad[j].is_positive ())
657                         {
658                             ax_max = (cal_max - cal_cen) * t / 100 + cal_cen;
659                         }
660                         else if (pad[j].is_negative ())
661                         {
662                             ax_min = (cal_min - cal_cen) * t / 100 + cal_cen;
663                         }
664                     }
665                 }
666             }
667 
668             for (int i = 0; i < NUM_EMU_LINKS; i++)
669             {
670                 if (gui_config->shortcut[i].get_axis () == event->jaxis.axis &&
671                     gui_config->shortcut[i].get_device () ==
672                     (unsigned int) (joynum + 1))
673                 {
674                     t = gui_config->shortcut[i].get_threshold ();
675                     if (gui_config->shortcut[i].is_positive ())
676                     {
677                         ax_max = (cal_max - cal_cen) * t / 100 + cal_cen;
678                     }
679                     else if (gui_config->shortcut[i].is_negative ())
680                     {
681                         ax_min = (cal_min - cal_cen) * t / 100 + cal_cen;
682                     }
683                 }
684             }
685         }
686         else if (mode == JOY_MODE_CALIBRATE)
687         {
688             if (event->jaxis.value < calibration[event->jaxis.axis].min)
689                 calibration[event->jaxis.axis].min = event->jaxis.value;
690             if (event->jaxis.value > calibration[event->jaxis.axis].max)
691                 calibration[event->jaxis.axis].min = event->jaxis.value;
692         }
693 
694         /* Sanity Check */
695         if (ax_min >= cal_cen)
696             ax_min = cal_cen - 1;
697         if (ax_max <= cal_cen)
698             ax_max = cal_cen + 1;
699 
700         if (event->jaxis.value <= ax_min &&
701                 axis[event->jaxis.axis] > ax_min)
702         {
703             add_event (JOY_AXIS (event->jaxis.axis, AXIS_NEG), 1);
704         }
705 
706         if (event->jaxis.value > ax_min &&
707                 axis[event->jaxis.axis] <= ax_min)
708         {
709             add_event (JOY_AXIS (event->jaxis.axis, AXIS_NEG), 0);
710         }
711 
712         if (event->jaxis.value >= ax_max &&
713                 axis[event->jaxis.axis] < ax_max)
714         {
715             add_event (JOY_AXIS (event->jaxis.axis, AXIS_POS), 1);
716         }
717 
718         if (event->jaxis.value < ax_max &&
719                 axis[event->jaxis.axis] >= ax_max)
720         {
721             add_event (JOY_AXIS (event->jaxis.axis, AXIS_POS), 0);
722         }
723 
724         axis[event->jaxis.axis] = event->jaxis.value;
725 
726     }
727 
728     else if (event->type == SDL_JOYBUTTONUP ||
729             event->type == SDL_JOYBUTTONDOWN)
730     {
731         add_event (event->jbutton.button,
732                    event->jbutton.state == SDL_PRESSED ? 1 : 0);
733     }
734 
735     else if (event->type == SDL_JOYHATMOTION)
736     {
737         if ((event->jhat.value & SDL_HAT_UP) &&
738             !(hat[event->jhat.hat] & SDL_HAT_UP))
739         {
740             add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2), AXIS_POS), 1);
741         }
742 
743         if (!(event->jhat.value & SDL_HAT_UP) &&
744             (hat[event->jhat.hat] & SDL_HAT_UP))
745         {
746             add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2), AXIS_POS), 0);
747         }
748 
749         if ((event->jhat.value & SDL_HAT_DOWN) &&
750             !(hat[event->jhat.hat] & SDL_HAT_DOWN))
751         {
752             add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2), AXIS_NEG), 1);
753         }
754 
755         if (!(event->jhat.value & SDL_HAT_DOWN) &&
756             (hat[event->jhat.hat] & SDL_HAT_DOWN))
757         {
758             add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2), AXIS_NEG), 0);
759         }
760 
761         if ((event->jhat.value & SDL_HAT_LEFT) &&
762             !(hat[event->jhat.hat] & SDL_HAT_LEFT))
763         {
764             add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2) + 1, AXIS_NEG), 1);
765         }
766 
767         if (!(event->jhat.value & SDL_HAT_LEFT) &&
768             (hat[event->jhat.hat] & SDL_HAT_LEFT))
769         {
770             add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2) + 1, AXIS_NEG), 0);
771         }
772 
773         if ((event->jhat.value & SDL_HAT_RIGHT) &&
774             !(hat[event->jhat.hat] & SDL_HAT_RIGHT))
775         {
776             add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2) + 1, AXIS_POS), 1);
777         }
778 
779         if (!(event->jhat.value & SDL_HAT_RIGHT) &&
780             (hat[event->jhat.hat] & SDL_HAT_RIGHT))
781         {
782             add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2) + 1, AXIS_POS), 0);
783         }
784 
785         hat[event->jhat.hat] = event->jhat.value;
786     }
787 }
788 
get_event(JoyEvent * event)789 int JoyDevice::get_event (JoyEvent *event)
790 {
791     poll_events ();
792 
793     if (queue.empty ())
794         return 0;
795 
796     event->parameter = queue.front ().parameter;
797     event->state     = queue.front ().state;
798 
799     queue.pop ();
800 
801     return 1;
802 }
803 
poll_events()804 void JoyDevice::poll_events ()
805 {
806     poll_joystick_events ();
807 }
808 
flush()809 void JoyDevice::flush ()
810 {
811     SDL_Event event;
812 
813     while (SDL_PollEvent (&event))
814     {
815     }
816 
817     while (!queue.empty ())
818         queue.pop ();
819 }
820