2018-11-16 00:42:29 +01:00
|
|
|
/*****************************************************************************\
|
|
|
|
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
|
|
|
This file is licensed under the Snes9x License.
|
|
|
|
For further information, consult the LICENSE file in the root directory.
|
|
|
|
\*****************************************************************************/
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include "gtk_s9xcore.h"
|
|
|
|
#include "gtk_s9x.h"
|
|
|
|
#include "gtk_config.h"
|
|
|
|
#include "gtk_control.h"
|
2018-06-21 21:23:43 +02:00
|
|
|
#include "gtk_file.h"
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
const BindingLink b_links[] =
|
|
|
|
{
|
|
|
|
/* Joypad-specific bindings. "Joypad# " will be prepended */
|
|
|
|
{ "b_up", "Up" },
|
|
|
|
{ "b_down", "Down" },
|
|
|
|
{ "b_left", "Left" },
|
|
|
|
{ "b_right", "Right" },
|
|
|
|
{ "b_start", "Start" },
|
|
|
|
{ "b_select", "Select" },
|
|
|
|
{ "b_a", "A" },
|
|
|
|
{ "b_b", "B" },
|
|
|
|
{ "b_x", "X" },
|
|
|
|
{ "b_y", "Y" },
|
|
|
|
{ "b_l", "L" },
|
|
|
|
{ "b_r", "R" },
|
|
|
|
{ "b_a_turbo", "Turbo A" },
|
|
|
|
{ "b_b_turbo", "Turbo B" },
|
|
|
|
{ "b_x_turbo", "Turbo X" },
|
|
|
|
{ "b_y_turbo", "Turbo Y" },
|
|
|
|
{ "b_l_turbo", "Turbo L" },
|
|
|
|
{ "b_r_turbo", "Turbo R" },
|
|
|
|
{ "b_a_sticky", "Sticky A" },
|
|
|
|
{ "b_b_sticky", "Sticky B" },
|
|
|
|
{ "b_x_sticky", "Sticky X" },
|
|
|
|
{ "b_y_sticky", "Sticky Y" },
|
|
|
|
{ "b_l_sticky", "Sticky L" },
|
|
|
|
{ "b_r_sticky", "Sticky R" },
|
|
|
|
|
|
|
|
/* Emulator based bindings */
|
|
|
|
{ "b_open_rom", "GTK_open_rom" },
|
|
|
|
{ "b_enable_turbo", "EmuTurbo" },
|
|
|
|
{ "b_toggle_turbo", "ToggleEmuTurbo" },
|
|
|
|
{ "b_pause", "GTK_pause" },
|
|
|
|
{ "b_decrease_frame_rate", "DecFrameRate" },
|
|
|
|
{ "b_increase_frame_rate", "IncFrameRate" },
|
|
|
|
{ "b_decrease_frame_time", "DecFrameTime" },
|
|
|
|
{ "b_increase_frame_time", "IncFrameTime" },
|
|
|
|
{ "b_hardware_reset", "Reset" },
|
|
|
|
{ "b_soft_reset", "SoftReset" },
|
|
|
|
{ "b_quit", "GTK_quit" },
|
|
|
|
{ "b_bg_layer_0", "ToggleBG0" },
|
|
|
|
{ "b_bg_layer_1", "ToggleBG1" },
|
|
|
|
{ "b_bg_layer_2", "ToggleBG2" },
|
|
|
|
{ "b_bg_layer_3", "ToggleBG3" },
|
|
|
|
{ "b_sprites", "ToggleSprites" },
|
|
|
|
{ "b_bg_layering_hack", "BGLayeringHack" },
|
|
|
|
{ "b_screenshot", "Screenshot" },
|
|
|
|
{ "b_fullscreen", "GTK_fullscreen" },
|
2018-11-06 23:30:50 +01:00
|
|
|
{ "b_state_save_current", "GTK_state_save_current" },
|
|
|
|
{ "b_state_load_current", "GTK_state_load_current" },
|
|
|
|
{ "b_state_increment_save","GTK_state_increment_save" },
|
|
|
|
{ "b_state_decrement_load","GTK_state_decrement_load" },
|
|
|
|
{ "b_state_increment", "GTK_state_increment" },
|
|
|
|
{ "b_state_decrement", "GTK_state_decrement" },
|
2010-09-25 17:46:12 +02:00
|
|
|
{ "b_save_0", "QuickSave000" },
|
|
|
|
{ "b_save_1", "QuickSave001" },
|
|
|
|
{ "b_save_2", "QuickSave002" },
|
|
|
|
{ "b_save_3", "QuickSave003" },
|
|
|
|
{ "b_save_4", "QuickSave004" },
|
|
|
|
{ "b_save_5", "QuickSave005" },
|
|
|
|
{ "b_save_6", "QuickSave006" },
|
|
|
|
{ "b_save_7", "QuickSave007" },
|
|
|
|
{ "b_save_8", "QuickSave008" },
|
2017-04-25 21:45:30 +02:00
|
|
|
{ "b_save_9", "QuickSave009" },
|
2010-09-25 17:46:12 +02:00
|
|
|
{ "b_load_0", "QuickLoad000" },
|
|
|
|
{ "b_load_1", "QuickLoad001" },
|
|
|
|
{ "b_load_2", "QuickLoad002" },
|
|
|
|
{ "b_load_3", "QuickLoad003" },
|
|
|
|
{ "b_load_4", "QuickLoad004" },
|
|
|
|
{ "b_load_5", "QuickLoad005" },
|
|
|
|
{ "b_load_6", "QuickLoad006" },
|
|
|
|
{ "b_load_7", "QuickLoad007" },
|
|
|
|
{ "b_load_8", "QuickLoad008" },
|
2017-04-25 21:45:30 +02:00
|
|
|
{ "b_load_9", "QuickLoad009" },
|
2010-09-25 17:46:12 +02:00
|
|
|
{ "b_sound_channel_0", "SoundChannel0" },
|
|
|
|
{ "b_sound_channel_1", "SoundChannel1" },
|
|
|
|
{ "b_sound_channel_2", "SoundChannel2" },
|
|
|
|
{ "b_sound_channel_3", "SoundChannel3" },
|
|
|
|
{ "b_sound_channel_4", "SoundChannel4" },
|
|
|
|
{ "b_sound_channel_5", "SoundChannel5" },
|
|
|
|
{ "b_sound_channel_6", "SoundChannel6" },
|
|
|
|
{ "b_sound_channel_7", "SoundChannel7" },
|
|
|
|
{ "b_all_sound_channels", "SoundChannelsOn" },
|
|
|
|
{ "b_save_spc", "GTK_save_spc" },
|
|
|
|
{ "b_begin_recording_movie", "BeginRecordingMovie" },
|
|
|
|
{ "b_stop_recording_movie", "EndRecordingMovie" },
|
|
|
|
{ "b_load_movie", "LoadMovie" },
|
|
|
|
{ "b_seek_to_frame", "GTK_seek_to_frame" },
|
|
|
|
{ "b_swap_controllers", "GTK_swap_controllers" },
|
2014-06-27 10:36:36 +02:00
|
|
|
{ "b_rewind", "GTK_rewind" },
|
2018-11-08 21:23:37 +01:00
|
|
|
{ "b_grab_mouse", "GTK_grab_mouse" },
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Where the page breaks occur in the preferences pane */
|
|
|
|
const int b_breaks[] =
|
|
|
|
{
|
|
|
|
12, /* End of main buttons */
|
|
|
|
24, /* End of turbo/sticky buttons */
|
|
|
|
35, /* End of base emulator buttons */
|
|
|
|
43, /* End of Graphic options */
|
2018-11-06 23:30:50 +01:00
|
|
|
69, /* End of save/load states */
|
|
|
|
78, /* End of sound buttons */
|
2018-11-08 21:23:37 +01:00
|
|
|
86, /* End of miscellaneous buttons */
|
2010-09-25 17:46:12 +02:00
|
|
|
-1
|
|
|
|
};
|
|
|
|
|
|
|
|
static int joystick_lock = 0;
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
bool S9xPollButton (uint32 id, bool *pressed)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
bool S9xPollAxis (uint32 id, int16 *value)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
bool S9xPollPointer (uint32 id, int16 *x, int16 *y)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2019-03-02 23:10:00 +01:00
|
|
|
*x = top_level->snes_mouse_x;
|
|
|
|
*y = top_level->snes_mouse_y;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
bool S9xIsMousePluggedIn ()
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
|
|
|
enum controllers ctl;
|
|
|
|
int8 id1, id2, id3, id4;
|
|
|
|
|
|
|
|
for (int i = 0; i <= 1; i++)
|
|
|
|
{
|
|
|
|
S9xGetController (i, &ctl, &id1, &id2, &id3, &id4);
|
2018-05-23 22:50:57 +02:00
|
|
|
if (ctl == CTL_MOUSE || ctl == CTL_SUPERSCOPE)
|
2010-09-26 11:19:15 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
bool S9xGrabJoysticks ()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
if (joystick_lock)
|
2018-12-28 23:32:32 +01:00
|
|
|
return false;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
joystick_lock++;
|
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
return true;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
void S9xReleaseJoysticks ()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
joystick_lock--;
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
static void swap_controllers_1_2 ()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
JoypadBinding interrim;
|
|
|
|
|
2018-05-14 03:17:02 +02:00
|
|
|
interrim = gui_config->pad[0];
|
|
|
|
gui_config->pad[0] = gui_config->pad[1];
|
|
|
|
gui_config->pad[1] = interrim;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
gui_config->rebind_keys ();
|
|
|
|
}
|
|
|
|
|
2018-11-06 23:30:50 +01:00
|
|
|
static void change_slot (int difference)
|
|
|
|
{
|
|
|
|
static char buf[256];
|
|
|
|
|
|
|
|
gui_config->current_save_slot += difference;
|
|
|
|
gui_config->current_save_slot %= 1000;
|
|
|
|
if (gui_config->current_save_slot < 0)
|
|
|
|
gui_config->current_save_slot += 1000;
|
2018-11-16 00:03:24 +01:00
|
|
|
if (!gui_config->rom_loaded)
|
|
|
|
return;
|
|
|
|
|
|
|
|
snprintf (buf, 256, "State Slot: %d", gui_config->current_save_slot);
|
2018-11-06 23:30:50 +01:00
|
|
|
S9xSetInfoString (buf);
|
|
|
|
GFX.InfoStringTimeout = 60;
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
void S9xHandlePortCommand (s9xcommand_t cmd, int16 data1, int16 data2)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-12-28 23:32:32 +01:00
|
|
|
static bool quit_binding_down = false;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
if (data1 == true)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
if (cmd.port[0] == PORT_QUIT)
|
2018-12-28 23:32:32 +01:00
|
|
|
quit_binding_down = true;
|
2014-06-27 10:36:36 +02:00
|
|
|
else if (cmd.port[0] == PORT_REWIND)
|
2018-12-28 23:32:32 +01:00
|
|
|
Settings.Rewinding = true;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
if (data1 == false) /* Release */
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
if (cmd.port[0] != PORT_QUIT)
|
|
|
|
{
|
2018-12-28 23:32:32 +01:00
|
|
|
quit_binding_down = false;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd.port[0] == PORT_COMMAND_FULLSCREEN)
|
|
|
|
{
|
|
|
|
top_level->toggle_fullscreen_mode ();
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_COMMAND_SAVE_SPC)
|
|
|
|
{
|
|
|
|
top_level->save_spc_dialog ();
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_OPEN_ROM)
|
|
|
|
{
|
|
|
|
top_level->open_rom_dialog ();
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_PAUSE)
|
|
|
|
{
|
|
|
|
if (!(top_level->user_pause))
|
|
|
|
top_level->pause_from_user ();
|
|
|
|
else
|
|
|
|
top_level->unpause_from_user ();
|
|
|
|
}
|
|
|
|
|
2014-06-27 10:36:36 +02:00
|
|
|
else if (cmd.port[0] == PORT_REWIND)
|
|
|
|
{
|
2018-12-28 23:32:32 +01:00
|
|
|
Settings.Rewinding = false;
|
2014-06-27 10:36:36 +02:00
|
|
|
}
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
else if (cmd.port[0] == PORT_SEEK_TO_FRAME)
|
|
|
|
{
|
|
|
|
top_level->movie_seek_dialog ();
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_SWAP_CONTROLLERS)
|
|
|
|
{
|
|
|
|
swap_controllers_1_2 ();
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_QUIT)
|
|
|
|
{
|
|
|
|
if (quit_binding_down)
|
|
|
|
S9xExit ();
|
|
|
|
}
|
2018-06-21 21:23:43 +02:00
|
|
|
|
|
|
|
else if (cmd.port[0] >= PORT_QUICKLOAD0 && cmd.port[0] <= PORT_QUICKLOAD9)
|
|
|
|
{
|
|
|
|
S9xQuickLoadSlot (cmd.port[0] - PORT_QUICKLOAD0);
|
|
|
|
}
|
2018-11-06 23:30:50 +01:00
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_SAVESLOT)
|
|
|
|
{
|
|
|
|
S9xQuickSaveSlot (gui_config->current_save_slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_LOADSLOT)
|
|
|
|
{
|
|
|
|
S9xQuickLoadSlot (gui_config->current_save_slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_INCREMENTSAVESLOT)
|
|
|
|
{
|
|
|
|
change_slot (1);
|
|
|
|
S9xQuickSaveSlot (gui_config->current_save_slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_DECREMENTLOADSLOT)
|
|
|
|
{
|
|
|
|
change_slot (-1);
|
|
|
|
S9xQuickLoadSlot (gui_config->current_save_slot);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_INCREMENTSLOT)
|
|
|
|
{
|
|
|
|
change_slot (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_DECREMENTSLOT)
|
|
|
|
{
|
|
|
|
change_slot (-1);
|
|
|
|
}
|
2018-11-08 21:23:37 +01:00
|
|
|
|
|
|
|
else if (cmd.port[0] == PORT_GRABMOUSE)
|
|
|
|
{
|
|
|
|
top_level->toggle_grab_mouse ();
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
Binding S9xGetBindingByName (const char *name)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
for (int i = 0; i < NUM_EMU_LINKS; i++)
|
|
|
|
{
|
|
|
|
if (!strcasecmp (b_links[i + NUM_JOYPAD_LINKS].snes9x_name, name))
|
|
|
|
{
|
|
|
|
return gui_config->shortcut[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Binding ();
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
s9xcommand_t S9xGetPortCommandT (const char *name)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
s9xcommand_t cmd;
|
|
|
|
|
|
|
|
cmd.type = S9xButtonPort;
|
|
|
|
cmd.multi_press = 0;
|
|
|
|
cmd.button_norpt = 0;
|
|
|
|
cmd.port[0] = 0;
|
|
|
|
cmd.port[1] = 0;
|
|
|
|
cmd.port[2] = 0;
|
|
|
|
cmd.port[3] = 0;
|
|
|
|
|
|
|
|
if (!strcasecmp (name, "GTK_fullscreen"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_COMMAND_FULLSCREEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (!strcasecmp (name, "GTK_save_spc"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_COMMAND_SAVE_SPC;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (!strcasecmp (name, "GTK_open_rom"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_OPEN_ROM;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (!strcasecmp (name, "GTK_pause"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_PAUSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (!strcasecmp (name, "GTK_seek_to_frame"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_SEEK_TO_FRAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (!strcasecmp (name, "GTK_quit"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (!strcasecmp (name, "GTK_swap_controllers"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_SWAP_CONTROLLERS;
|
|
|
|
}
|
|
|
|
|
2014-06-27 10:36:36 +02:00
|
|
|
else if (!strcasecmp (name, "GTK_rewind"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_REWIND;
|
|
|
|
}
|
|
|
|
|
2018-06-21 21:23:43 +02:00
|
|
|
else if (strstr (name, "QuickLoad000"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUICKLOAD0;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "QuickLoad001"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUICKLOAD1;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "QuickLoad002"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUICKLOAD2;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "QuickLoad003"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUICKLOAD3;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "QuickLoad004"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUICKLOAD4;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "QuickLoad005"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUICKLOAD5;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "QuickLoad006"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUICKLOAD6;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "QuickLoad007"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUICKLOAD7;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "QuickLoad008"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUICKLOAD8;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "QuickLoad009"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_QUICKLOAD9;
|
|
|
|
}
|
|
|
|
|
2018-11-06 23:30:50 +01:00
|
|
|
else if (strstr (name, "GTK_state_save_current"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_SAVESLOT;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "GTK_state_load_current"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_LOADSLOT;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "GTK_state_increment_save"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_INCREMENTSAVESLOT;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "GTK_state_decrement_load"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_DECREMENTLOADSLOT;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "GTK_state_increment"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_INCREMENTSLOT;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (strstr (name, "GTK_state_decrement"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_DECREMENTSLOT;
|
|
|
|
}
|
|
|
|
|
2018-11-08 21:23:37 +01:00
|
|
|
else if (strstr (name, "GTK_grab_mouse"))
|
|
|
|
{
|
|
|
|
cmd.port[0] = PORT_GRABMOUSE;
|
|
|
|
}
|
|
|
|
|
2018-11-06 23:30:50 +01:00
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
cmd = S9xGetCommandT (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
void S9xProcessEvents (bool8 block)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
JoyEvent event;
|
|
|
|
Binding binding;
|
|
|
|
|
|
|
|
if (S9xGrabJoysticks ())
|
|
|
|
{
|
|
|
|
for (int i = 0; gui_config->joystick[i]; i++)
|
|
|
|
{
|
|
|
|
while (gui_config->joystick[i]->get_event (&event))
|
|
|
|
{
|
|
|
|
binding = Binding (i, event.parameter, 0);
|
|
|
|
S9xReportButton (binding.hex (), event.state == JOY_PRESSED ? 1 : 0);
|
2018-12-28 23:32:32 +01:00
|
|
|
gui_config->screensaver_needs_reset = true;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
S9xReleaseJoysticks ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
static void poll_joystick_events ()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
SDL_Event event;
|
|
|
|
|
|
|
|
while (SDL_PollEvent (&event))
|
|
|
|
{
|
|
|
|
if (event.type == SDL_JOYAXISMOTION)
|
|
|
|
{
|
|
|
|
gui_config->joystick[event.jaxis.which]->handle_event (&event);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (event.type == SDL_JOYHATMOTION)
|
|
|
|
{
|
|
|
|
gui_config->joystick[event.jhat.which]->handle_event (&event);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (event.type == SDL_JOYBUTTONUP ||
|
|
|
|
event.type == SDL_JOYBUTTONDOWN)
|
|
|
|
{
|
|
|
|
gui_config->joystick[event.jbutton.which]->handle_event (&event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
void S9xInitInputDevices ()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2017-11-24 01:57:47 +01:00
|
|
|
SDL_Init (SDL_INIT_JOYSTICK);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
for (int i = 0; ; i++)
|
|
|
|
{
|
|
|
|
gui_config->joystick = (JoyDevice **)
|
|
|
|
realloc (gui_config->joystick,
|
|
|
|
sizeof (JoyDevice *) * (i + 1));
|
|
|
|
|
|
|
|
gui_config->joystick[i] = new JoyDevice (i);
|
|
|
|
|
|
|
|
if (!gui_config->joystick[i]->enabled)
|
|
|
|
{
|
|
|
|
delete gui_config->joystick[i];
|
|
|
|
gui_config->joystick[i] = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gui_config->joystick[i]->joynum = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-03 23:58:40 +02:00
|
|
|
//First plug in both, they'll change later as needed
|
|
|
|
S9xSetController (0, CTL_JOYPAD, 0, 0, 0, 0);
|
|
|
|
S9xSetController (1, CTL_JOYPAD, 1, 0, 0, 0);
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
void S9xDeinitInputDevices ()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
for (int i = 0; gui_config->joystick[i] != NULL; i++)
|
|
|
|
{
|
|
|
|
delete gui_config->joystick[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
free (gui_config->joystick);
|
|
|
|
|
|
|
|
SDL_Quit ();
|
|
|
|
}
|
|
|
|
|
|
|
|
JoyDevice::JoyDevice (unsigned int device_num)
|
|
|
|
{
|
|
|
|
enabled = false;
|
|
|
|
axis = NULL;
|
|
|
|
filedes = NULL;
|
|
|
|
mode = JOY_MODE_INDIVIDUAL;
|
|
|
|
|
|
|
|
if ((int) device_num >= SDL_NumJoysticks ())
|
|
|
|
return;
|
|
|
|
|
|
|
|
filedes = SDL_JoystickOpen (device_num);
|
|
|
|
|
|
|
|
if (!filedes)
|
|
|
|
return;
|
|
|
|
|
|
|
|
enabled = true;
|
|
|
|
|
|
|
|
num_axes = SDL_JoystickNumAxes (filedes);
|
|
|
|
num_hats = SDL_JoystickNumHats (filedes);
|
2019-05-14 22:34:25 +02:00
|
|
|
axis = new int[num_axes];
|
|
|
|
hat = new int[num_hats];
|
|
|
|
calibration = new Calibration[num_axes];
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < num_axes; i++)
|
|
|
|
{
|
|
|
|
calibration[i].min = -32767;
|
|
|
|
calibration[i].max = 32767;
|
|
|
|
calibration[i].center = 0;
|
|
|
|
}
|
|
|
|
|
2017-12-01 01:38:09 +01:00
|
|
|
printf ("Joystick %d, %s:\n %d axes, %d buttons, %d hats\n",
|
|
|
|
device_num + 1,
|
|
|
|
SDL_JoystickName (filedes),
|
|
|
|
SDL_JoystickNumButtons (filedes),
|
|
|
|
num_axes,
|
|
|
|
num_hats);
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
memset (axis, 0, sizeof (int) * num_axes);
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
JoyDevice::~JoyDevice ()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
if (enabled)
|
|
|
|
{
|
|
|
|
SDL_JoystickClose (filedes);
|
2019-05-14 22:34:25 +02:00
|
|
|
delete[] axis;
|
|
|
|
delete[] hat;
|
|
|
|
delete[] calibration;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
enabled = false;
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
void JoyDevice::add_event (unsigned int parameter, unsigned int state)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
JoyEvent event = { parameter, state };
|
|
|
|
|
|
|
|
queue.push (event);
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
void JoyDevice::register_centers ()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
for (int i = 0; i < num_axes; i++)
|
|
|
|
{
|
|
|
|
calibration[i].center = SDL_JoystickGetAxis (filedes, i);
|
|
|
|
|
|
|
|
/* Snap centers to specific target points */
|
|
|
|
if (calibration[i].center < -24576)
|
|
|
|
calibration[i].center = -32768;
|
|
|
|
else if (calibration[i].center < -8192)
|
|
|
|
calibration[i].center = -16384;
|
|
|
|
else if (calibration[i].center < 8192)
|
|
|
|
calibration[i].center = 0;
|
|
|
|
else if (calibration[i].center < 24576)
|
|
|
|
calibration[i].center = 16383;
|
|
|
|
else
|
|
|
|
calibration[i].center = 32767;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
void JoyDevice::handle_event (SDL_Event *event)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
if (event->type == SDL_JOYAXISMOTION)
|
|
|
|
{
|
|
|
|
int cal_min = calibration[event->jaxis.axis].min;
|
|
|
|
int cal_max = calibration[event->jaxis.axis].max;
|
|
|
|
int cal_cen = calibration[event->jaxis.axis].center;
|
|
|
|
int t = gui_config->joystick_threshold;
|
|
|
|
int ax_min = (cal_min - cal_cen) * t / 100 + cal_cen;
|
|
|
|
int ax_max = (cal_max - cal_cen) * t / 100 + cal_cen;
|
|
|
|
|
|
|
|
if (mode == JOY_MODE_INDIVIDUAL)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < NUM_JOYPADS; i++)
|
|
|
|
{
|
|
|
|
Binding *pad = (Binding *) &(gui_config->pad[i]);
|
|
|
|
|
|
|
|
for (int j = 0; j < NUM_JOYPAD_LINKS; j++)
|
|
|
|
{
|
|
|
|
if (pad[j].get_axis () == event->jaxis.axis &&
|
|
|
|
pad[j].get_device () == (unsigned int) (joynum + 1))
|
|
|
|
{
|
|
|
|
t = pad[j].get_threshold ();
|
|
|
|
|
|
|
|
if (pad[j].is_positive ())
|
|
|
|
{
|
|
|
|
ax_max = (cal_max - cal_cen) * t / 100 + cal_cen;
|
|
|
|
}
|
|
|
|
else if (pad[j].is_negative ())
|
|
|
|
{
|
|
|
|
ax_min = (cal_min - cal_cen) * t / 100 + cal_cen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < NUM_EMU_LINKS; i++)
|
|
|
|
{
|
|
|
|
if (gui_config->shortcut[i].get_axis () == event->jaxis.axis &&
|
|
|
|
gui_config->shortcut[i].get_device () ==
|
|
|
|
(unsigned int) (joynum + 1))
|
|
|
|
{
|
|
|
|
t = gui_config->shortcut[i].get_threshold ();
|
|
|
|
if (gui_config->shortcut[i].is_positive ())
|
|
|
|
{
|
|
|
|
ax_max = (cal_max - cal_cen) * t / 100 + cal_cen;
|
|
|
|
}
|
|
|
|
else if (gui_config->shortcut[i].is_negative ())
|
|
|
|
{
|
|
|
|
ax_min = (cal_min - cal_cen) * t / 100 + cal_cen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mode == JOY_MODE_CALIBRATE)
|
|
|
|
{
|
|
|
|
if (event->jaxis.value < calibration[event->jaxis.axis].min)
|
|
|
|
calibration[event->jaxis.axis].min = event->jaxis.value;
|
|
|
|
if (event->jaxis.value > calibration[event->jaxis.axis].max)
|
|
|
|
calibration[event->jaxis.axis].min = event->jaxis.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sanity Check */
|
|
|
|
if (ax_min >= cal_cen)
|
|
|
|
ax_min = cal_cen - 1;
|
|
|
|
if (ax_max <= cal_cen)
|
|
|
|
ax_max = cal_cen + 1;
|
|
|
|
|
|
|
|
if (event->jaxis.value <= ax_min &&
|
|
|
|
axis[event->jaxis.axis] > ax_min)
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (event->jaxis.axis, AXIS_NEG), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event->jaxis.value > ax_min &&
|
|
|
|
axis[event->jaxis.axis] <= ax_min)
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (event->jaxis.axis, AXIS_NEG), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event->jaxis.value >= ax_max &&
|
|
|
|
axis[event->jaxis.axis] < ax_max)
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (event->jaxis.axis, AXIS_POS), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event->jaxis.value < ax_max &&
|
|
|
|
axis[event->jaxis.axis] >= ax_max)
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (event->jaxis.axis, AXIS_POS), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
axis[event->jaxis.axis] = event->jaxis.value;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (event->type == SDL_JOYBUTTONUP ||
|
|
|
|
event->type == SDL_JOYBUTTONDOWN)
|
|
|
|
{
|
|
|
|
add_event (event->jbutton.button,
|
|
|
|
event->jbutton.state == SDL_PRESSED ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (event->type == SDL_JOYHATMOTION)
|
|
|
|
{
|
|
|
|
if ((event->jhat.value & SDL_HAT_UP) &&
|
|
|
|
!(hat[event->jhat.hat] & SDL_HAT_UP))
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2), AXIS_POS), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(event->jhat.value & SDL_HAT_UP) &&
|
|
|
|
(hat[event->jhat.hat] & SDL_HAT_UP))
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2), AXIS_POS), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((event->jhat.value & SDL_HAT_DOWN) &&
|
|
|
|
!(hat[event->jhat.hat] & SDL_HAT_DOWN))
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2), AXIS_NEG), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(event->jhat.value & SDL_HAT_DOWN) &&
|
|
|
|
(hat[event->jhat.hat] & SDL_HAT_DOWN))
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2), AXIS_NEG), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((event->jhat.value & SDL_HAT_LEFT) &&
|
|
|
|
!(hat[event->jhat.hat] & SDL_HAT_LEFT))
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2) + 1, AXIS_NEG), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(event->jhat.value & SDL_HAT_LEFT) &&
|
|
|
|
(hat[event->jhat.hat] & SDL_HAT_LEFT))
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2) + 1, AXIS_NEG), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((event->jhat.value & SDL_HAT_RIGHT) &&
|
|
|
|
!(hat[event->jhat.hat] & SDL_HAT_RIGHT))
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2) + 1, AXIS_POS), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(event->jhat.value & SDL_HAT_RIGHT) &&
|
|
|
|
(hat[event->jhat.hat] & SDL_HAT_RIGHT))
|
|
|
|
{
|
|
|
|
add_event (JOY_AXIS (num_axes + (event->jhat.hat * 2) + 1, AXIS_POS), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
hat[event->jhat.hat] = event->jhat.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
int JoyDevice::get_event (JoyEvent *event)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
poll_events ();
|
|
|
|
|
|
|
|
if (queue.empty ())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
event->parameter = queue.front ().parameter;
|
|
|
|
event->state = queue.front ().state;
|
|
|
|
|
|
|
|
queue.pop ();
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
void JoyDevice::poll_events ()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
poll_joystick_events ();
|
|
|
|
}
|
|
|
|
|
2018-11-02 21:27:12 +01:00
|
|
|
void JoyDevice::flush ()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
SDL_Event event;
|
|
|
|
|
|
|
|
while (SDL_PollEvent (&event))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!queue.empty ())
|
|
|
|
queue.pop ();
|
|
|
|
}
|