diff --git a/src/drivers/sdl/gui.cpp b/src/drivers/sdl/gui.cpp
index b5e64e54..3327a9f8 100644
--- a/src/drivers/sdl/gui.cpp
+++ b/src/drivers/sdl/gui.cpp
@@ -35,35 +35,32 @@ extern Config *g_config;
GtkWidget* MainWindow = NULL;
GtkWidget* socket = NULL;
-GtkWidget* padNoCombo;
+GtkWidget* padNoCombo = NULL;
+GtkWidget* configNoCombo = NULL;
+GtkWidget* buttonMappings[10];
// This function configures a single button on a gamepad
int configGamepadButton(GtkButton* button, gpointer p)
{
gint x = ((gint)(glong)(p));
//gint x = GPOINTER_TO_INT(p);
- int padNo = 0;
- char* padStr = gtk_combo_box_get_active_text(GTK_COMBO_BOX(padNoCombo));
-
- if(!strcmp(padStr, "1"))
- padNo = 0;
- if(!strcmp(padStr, "2"))
- padNo = 1;
- if(!strcmp(padStr, "3"))
- padNo = 2;
- if(!strcmp(padStr, "4"))
- padNo = 3;
+ int padNo = atoi(gtk_combo_box_get_active_text(GTK_COMBO_BOX(padNoCombo))) - 1;
+ int configNo = atoi(gtk_combo_box_get_active_text(GTK_COMBO_BOX(configNoCombo))) - 1;
char buf[256];
std::string prefix;
+ // only configure when the "Change" button is pressed in, not when it is unpressed
+ if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
+ return 0;
+
ButtonConfigBegin();
- snprintf(buf, 256, "SDL.Input.GamePad.%d", padNo);
+ snprintf(buf, sizeof(buf), "SDL.Input.GamePad.%d", padNo);
prefix = buf;
- ConfigButton((char*)GamePadNames[x], &GamePadConfig[padNo][x]);
+ DWaitButton((const uint8*)"Press a button", &GamePadConfig[padNo][x], configNo);
- g_config->setOption(prefix + GamePadNames[x], GamePadConfig[padNo][x].ButtonNum[0]);
+ g_config->setOption(prefix + GamePadNames[x], GamePadConfig[padNo][x].ButtonNum[configNo]);
if(GamePadConfig[padNo][x].ButtType[0] == BUTTC_KEYBOARD)
{
@@ -73,10 +70,16 @@ int configGamepadButton(GtkButton* button, gpointer p)
} else {
g_config->setOption(prefix + "DeviceType", "Unknown");
}
- g_config->setOption(prefix + "DeviceNum", GamePadConfig[padNo][0].DeviceNum[0]);
+ g_config->setOption(prefix + "DeviceNum", GamePadConfig[padNo][x].DeviceNum[configNo]);
+ g_config->save();
+
+ snprintf(buf, sizeof(buf), "%s", ButtonName(&GamePadConfig[padNo][x], configNo));
+ gtk_label_set_markup(GTK_LABEL(buttonMappings[x]), buf);
ButtonConfigEnd();
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
+
return 0;
}
@@ -435,6 +438,38 @@ int setInputDevice(GtkWidget* w, gpointer p)
return 1;
}
+gboolean closeGamepadConfig(GtkWidget* w, GdkEvent* event, gpointer p)
+{
+ gint paused = ((gint)(glong)(p));
+ if(!paused)
+ FCEUI_SetEmulationPaused(0);
+ gtk_widget_destroy(w);
+ return FALSE;
+}
+
+void updateGamepadConfig(GtkWidget* w, gpointer p)
+{
+ int i;
+ char strBuf[128];
+ int padNo = atoi(gtk_combo_box_get_active_text(GTK_COMBO_BOX(padNoCombo))) - 1;
+ int configNo = atoi(gtk_combo_box_get_active_text(GTK_COMBO_BOX(configNoCombo))) - 1;
+
+ for(i=0; i<10; i++)
+ {
+ GtkWidget* mappedKey = buttonMappings[i];
+ if(GamePadConfig[padNo][i].ButtType[configNo] == BUTTC_KEYBOARD)
+ {
+ snprintf(strBuf, sizeof(strBuf), "%s",
+ SDL_GetKeyName((SDLKey)GamePadConfig[padNo][i].ButtonNum[configNo]));
+ }
+ else // FIXME: display joystick button/hat/axis names properly
+ strncpy(strBuf, "Joystick", sizeof(strBuf));
+
+ gtk_label_set_text(GTK_LABEL(mappedKey), strBuf);
+ gtk_label_set_use_markup(GTK_LABEL(mappedKey), TRUE);
+ }
+}
+
// creates and opens the gamepad config window
void openGamepadConfig()
{
@@ -442,17 +477,29 @@ void openGamepadConfig()
GtkWidget* vbox;
GtkWidget* hboxPadNo;
GtkWidget* padNoLabel;
+ GtkWidget* configNoLabel;
GtkWidget* fourScoreChk;
+ GtkWidget* oppositeDirChk;
+ GtkWidget* buttonFrame;
+ GtkWidget* buttonTable;
- GtkWidget* buttons[10];
+ win = gtk_dialog_new_with_buttons("Controller Configuration",
+ GTK_WINDOW(MainWindow),
+ (GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_OK,
+ NULL);
+ gtk_window_set_title(GTK_WINDOW(win), "Controller Configuration");
+ gtk_widget_set_size_request(win, 350, 500);
- win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title(GTK_WINDOW(win), "Gamepad Config");
- gtk_widget_set_size_request(win, 250, 500);
- vbox = gtk_vbox_new(TRUE, 4);
- hboxPadNo = gtk_hbox_new(FALSE, 5);
- padNoLabel = gtk_label_new("Gamepad Number:");
- fourScoreChk = gtk_check_button_new_with_label("Enable four score");
+ vbox = gtk_dialog_get_content_area(GTK_DIALOG(win));
+ gtk_box_set_homogeneous(GTK_BOX(vbox), FALSE);
+
+ hboxPadNo = gtk_hbox_new(FALSE, 0);
+ padNoLabel = gtk_label_new("Port:");
+ configNoLabel = gtk_label_new("Config Number:");
+ fourScoreChk = gtk_check_button_new_with_label("Enable Four Score");
+ oppositeDirChk = gtk_check_button_new_with_label("Allow Up+Down / Left+Right");
typeCombo = gtk_combo_box_new_text();
gtk_combo_box_append_text(GTK_COMBO_BOX(typeCombo), "gamepad");
@@ -469,8 +516,17 @@ void openGamepadConfig()
gtk_combo_box_append_text(GTK_COMBO_BOX(padNoCombo), "2");
gtk_combo_box_append_text(GTK_COMBO_BOX(padNoCombo), "3");
gtk_combo_box_append_text(GTK_COMBO_BOX(padNoCombo), "4");
-
gtk_combo_box_set_active(GTK_COMBO_BOX(padNoCombo), 0);
+ g_signal_connect(GTK_OBJECT(padNoCombo), "changed", G_CALLBACK(updateGamepadConfig), NULL);
+
+ configNoCombo = gtk_combo_box_new_text();
+ gtk_combo_box_append_text(GTK_COMBO_BOX(configNoCombo), "1");
+ gtk_combo_box_append_text(GTK_COMBO_BOX(configNoCombo), "2");
+ gtk_combo_box_append_text(GTK_COMBO_BOX(configNoCombo), "3");
+ gtk_combo_box_append_text(GTK_COMBO_BOX(configNoCombo), "4");
+ gtk_combo_box_set_active(GTK_COMBO_BOX(configNoCombo), 0);
+ g_signal_connect(GTK_OBJECT(padNoCombo), "changed", G_CALLBACK(updateGamepadConfig), NULL);
+
g_signal_connect(GTK_OBJECT(typeCombo), "changed", G_CALLBACK(setInputDevice),
gtk_combo_box_get_active_text(GTK_COMBO_BOX(typeCombo)));
@@ -486,20 +542,56 @@ void openGamepadConfig()
g_signal_connect(GTK_OBJECT(fourScoreChk), "clicked", G_CALLBACK(toggleOption), (gpointer)"SDL.FourScore");
gtk_box_pack_start(GTK_BOX(hboxPadNo), padNoLabel, TRUE, TRUE, 5);
- gtk_box_pack_start(GTK_BOX(hboxPadNo), padNoCombo, TRUE, FALSE, 5);
- gtk_box_pack_start(GTK_BOX(vbox), hboxPadNo, TRUE, TRUE, 5);
+ gtk_box_pack_start(GTK_BOX(hboxPadNo), padNoCombo, TRUE, TRUE, 5);
+ //gtk_box_pack_start(GTK_BOX(hboxPadNo), configNoLabel, TRUE, TRUE, 5);
+ //gtk_box_pack_start(GTK_BOX(hboxPadNo), configNoCombo, TRUE, TRUE, 5);
+ gtk_box_pack_start(GTK_BOX(vbox), hboxPadNo, FALSE, TRUE, 5);
//gtk_box_pack_start_defaults(GTK_BOX(vbox), typeCombo);
- gtk_box_pack_start(GTK_BOX(vbox), fourScoreChk, TRUE, TRUE, 5);
+ gtk_box_pack_start(GTK_BOX(vbox), fourScoreChk, FALSE, TRUE, 5);
+ //gtk_box_pack_start(GTK_BOX(vbox), oppositeDirChk, FALSE, TRUE, 5);
+
+
// create gamepad buttons
+ buttonFrame = gtk_frame_new("Buttons");
+ gtk_label_set_use_markup(GTK_LABEL(gtk_frame_get_label_widget(GTK_FRAME(buttonFrame))), TRUE);
+ buttonTable = gtk_table_new(10, 3, FALSE);
+ gtk_table_set_col_spacings(GTK_TABLE(buttonTable), 5);
+ gtk_container_add(GTK_CONTAINER(buttonFrame), buttonTable);
for(int i=0; i<10; i++)
{
- buttons[i] = gtk_button_new_with_label(GamePadNames[i]);
- gtk_box_pack_start(GTK_BOX(vbox), buttons[i], TRUE, TRUE, 3);
- gtk_signal_connect(GTK_OBJECT(buttons[i]), "clicked", G_CALLBACK(configGamepadButton), GINT_TO_POINTER(i));
+ GtkWidget* buttonName = gtk_label_new(GamePadNames[i]);
+ GtkWidget* mappedKey = gtk_label_new(NULL);
+ GtkWidget* changeButton = gtk_toggle_button_new();
+ char strBuf[128];
+
+ sprintf(strBuf, "%s:", GamePadNames[i]);
+ gtk_label_set_text(GTK_LABEL(buttonName), strBuf);
+ gtk_misc_set_alignment(GTK_MISC(buttonName), 1.0, 0.5);
+
+ gtk_misc_set_alignment(GTK_MISC(mappedKey), 0.0, 0.5);
+
+ gtk_button_set_label(GTK_BUTTON(changeButton), "Change");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(changeButton), FALSE);
+
+ gtk_table_attach(GTK_TABLE(buttonTable), buttonName, 0, 1, i, i+1, GTK_FILL, GTK_FILL, 0, 0);
+ gtk_table_attach(GTK_TABLE(buttonTable), mappedKey, 1, 2, i, i+1,
+ (GtkAttachOptions)(GTK_EXPAND|GTK_FILL), (GtkAttachOptions)(GTK_EXPAND|GTK_FILL), 0, 0);
+ gtk_table_attach(GTK_TABLE(buttonTable), changeButton, 2, 3, i, i+1,
+ (GtkAttachOptions)0, (GtkAttachOptions)0, 0, 0);
+
+ gtk_signal_connect(GTK_OBJECT(changeButton), "clicked", G_CALLBACK(configGamepadButton), GINT_TO_POINTER(i));
+ buttonMappings[i] = mappedKey;
}
- gtk_container_add(GTK_CONTAINER(win), vbox);
+ // display the button mappings for the currently selected configuration
+ updateGamepadConfig(NULL, NULL);
+
+ gtk_box_pack_start(GTK_BOX(vbox), buttonFrame, TRUE, TRUE, 5);
+
+ g_signal_connect(GTK_OBJECT(win), "delete-event", G_CALLBACK(closeGamepadConfig), GINT_TO_POINTER(FCEUI_EmulationPaused()));
+ g_signal_connect(GTK_OBJECT(win), "response", G_CALLBACK(closeGamepadConfig), GINT_TO_POINTER(FCEUI_EmulationPaused()));
+ FCEUI_SetEmulationPaused(1);
gtk_widget_show_all(win);
@@ -916,6 +1008,7 @@ void openSoundConfig()
bufferHscale = gtk_hscale_new_with_range(15, 200, 2);
bufferLbl = gtk_label_new("Buffer size (in ms)");
+
// sync widget with cfg
g_config->getOption("SDL.Sound.BufSize", &cfgBuf);
gtk_range_set_value(GTK_RANGE(bufferHscale), cfgBuf);
@@ -1597,13 +1690,6 @@ gint convertKeypress(GtkWidget *grab, GdkEventKey *event, gpointer user_data)
SDL_Event sdlev;
SDLKey sdlkey;
int keystate;
-
- // Only grab keys from the main window.
- if (grab != MainWindow)
- {
- // Don't push this key onto the SDL event stack.
- return FALSE;
- }
switch (event->type)
{
diff --git a/src/drivers/sdl/input.cpp b/src/drivers/sdl/input.cpp
index 8878e0a5..2814cfb7 100644
--- a/src/drivers/sdl/input.cpp
+++ b/src/drivers/sdl/input.cpp
@@ -40,7 +40,10 @@
#endif
#ifdef _GTK_LITE
-#include
+#include "gui.h"
+#ifdef SDL_VIDEO_DRIVER_X11
+#include
+#endif
#endif
@@ -762,16 +765,34 @@ ButtonConfigBegin()
// reactivate the video subsystem
if(!SDL_WasInit(SDL_INIT_VIDEO)) {
- if(SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) {
+ if(!bcpv) {
+ InitVideo(GameInfo);
+ }
+ else {
+#if defined(_GTK) && defined(SDL_VIDEO_DRIVER_X11)
+ int noGui;
+ g_config->getOption("SDL.NoGUI", &noGui);
+ if(noGui == 0)
+ {
+ while (gtk_events_pending())
+ gtk_main_iteration_do(FALSE);
+
+ char SDL_windowhack[128];
+ sprintf(SDL_windowhack, "SDL_WINDOWID=%u", (unsigned int)GDK_WINDOW_XWINDOW(gtk_widget_get_window(socket)));
+ SDL_putenv(SDL_windowhack);
+ }
+#endif
+ if(SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) {
FCEUD_Message(SDL_GetError());
return(0);
+ }
+
+ // set the screen and notify the user of button configuration
+ screen = SDL_SetVideoMode(420, 200, 8, 0);
+ SDL_WM_SetCaption("Button Config",0);
}
}
- // set the screen and notify the user of button configuration
- screen = SDL_SetVideoMode(420, 200, 8, 0);
- SDL_WM_SetCaption("Button Config",0);
-
// XXX soules - why did we shut this down?
// initialize the joystick subsystem
InitJoysticks();
@@ -791,12 +812,12 @@ ButtonConfigEnd()
// shutdown the joystick and video subsystems
KillJoysticks();
- SDL_QuitSubSystem(SDL_INIT_VIDEO);
+ //SDL_QuitSubSystem(SDL_INIT_VIDEO);
// re-initialize joystick and video subsystems if they were active before
- if(!bcpv) {
+ /*if(!bcpv) {
InitVideo(GameInfo);
- }
+ }*/
if(!bcpj) {
InitJoysticks();
}
@@ -1259,11 +1280,68 @@ UpdateFTrainer()
}
}
+/**
+ * Get the display name of the key or joystick button mapped to a specific
+ * NES gamepad button.
+ * @param bc the NES gamepad's button config
+ * @param which the index of the button
+ */
+const char*
+ButtonName(const ButtConfig* bc, int which)
+{
+ static char name[256];
+
+ switch(bc->ButtType[which])
+ {
+ case BUTTC_KEYBOARD:
+ return SDL_GetKeyName((SDLKey)bc->ButtonNum[which]);
+ case BUTTC_JOYSTICK:
+ int joyNum, inputNum;
+ const char* inputType, *inputDirection;
+
+ joyNum = bc->DeviceNum[which];
+
+ if(bc->ButtonNum[which] & 0x8000)
+ {
+ inputType = "Axis";
+ inputNum = bc->ButtonNum[which] & 0x3FFF;
+ inputDirection = bc->ButtonNum[which] & 0x4000 ? "-" : "+";
+ }
+ else if(bc->ButtonNum[which] & 0x2000)
+ {
+ int inputValue;
+ char direction[128] = "";
+
+ inputType = "Hat";
+ inputNum = (bc->ButtonNum[which] >> 8) & 0x1F;
+ inputValue = bc->ButtonNum[which] & 0xF;
+
+ if(inputValue & SDL_HAT_UP) strncat(direction, "Up ", sizeof(direction));
+ if(inputValue & SDL_HAT_DOWN) strncat(direction, "Down ", sizeof(direction));
+ if(inputValue & SDL_HAT_LEFT) strncat(direction, "Left ", sizeof(direction));
+ if(inputValue & SDL_HAT_RIGHT) strncat(direction, "Right ", sizeof(direction));
+
+ if(direction[0])
+ inputDirection = direction;
+ else
+ inputDirection = "Center";
+ }
+ else
+ {
+ inputType = "Button";
+ inputNum = bc->ButtonNum[which];
+ inputDirection = "";
+ }
+ }
+
+ return name;
+}
+
/**
* Waits for a button input and returns the information as to which
* button was pressed. Used in button configuration.
*/
-static int
+int
DWaitButton(const uint8 *text,
ButtConfig *bc,
int wb)
@@ -1281,44 +1359,60 @@ DWaitButton(const uint8 *text,
}
}
- while(SDL_WaitEvent(&event)) {
- switch(event.type) {
- case SDL_KEYDOWN:
- bc->ButtType[wb] = BUTTC_KEYBOARD;
- bc->DeviceNum[wb] = 0;
- bc->ButtonNum[wb] = event.key.keysym.sym;
- return(1);
- case SDL_JOYBUTTONDOWN:
- bc->ButtType[wb] = BUTTC_JOYSTICK;
- bc->DeviceNum[wb] = event.jbutton.which;
- bc->ButtonNum[wb] = event.jbutton.button;
- return(1);
- case SDL_JOYHATMOTION:
- if(event.jhat.value != SDL_HAT_CENTERED) {
- bc->ButtType[wb] = BUTTC_JOYSTICK;
- bc->DeviceNum[wb] = event.jhat.which;
- bc->ButtonNum[wb] = (0x2000 | ((event.jhat.hat & 0x1F) << 8) |
- event.jhat.value);
+ while(1) {
+ int done = 0;
+#ifdef _GTK
+ while(gtk_events_pending())
+ gtk_main_iteration_do(FALSE);
+#endif
+ while(SDL_PollEvent(&event)) {
+ done++;
+ switch(event.type) {
+ case SDL_KEYDOWN:
+ bc->ButtType[wb] = BUTTC_KEYBOARD;
+ bc->DeviceNum[wb] = 0;
+ bc->ButtonNum[wb] = event.key.keysym.sym;
return(1);
- }
- break;
- case SDL_JOYAXISMOTION:
- if(LastAx[event.jaxis.which][event.jaxis.axis] == 0x100000) {
- if(abs(event.jaxis.value) < 1000) {
- LastAx[event.jaxis.which][event.jaxis.axis] = event.jaxis.value;
- }
- } else {
- if(abs(LastAx[event.jaxis.which][event.jaxis.axis] - event.jaxis.value) >= 8192) {
+ case SDL_JOYBUTTONDOWN:
+ bc->ButtType[wb] = BUTTC_JOYSTICK;
+ bc->DeviceNum[wb] = event.jbutton.which;
+ bc->ButtonNum[wb] = event.jbutton.button;
+ return(1);
+ case SDL_JOYHATMOTION:
+ if(event.jhat.value == SDL_HAT_CENTERED)
+ done--;
+ else {
bc->ButtType[wb] = BUTTC_JOYSTICK;
- bc->DeviceNum[wb] = event.jaxis.which;
- bc->ButtonNum[wb] = (0x8000 | event.jaxis.axis |
- ((event.jaxis.value < 0)
- ? 0x4000 : 0));
+ bc->DeviceNum[wb] = event.jhat.which;
+ bc->ButtonNum[wb] = (0x2000 | ((event.jhat.hat & 0x1F) << 8) |
+ event.jhat.value);
return(1);
}
+ break;
+ case SDL_JOYAXISMOTION:
+ if(LastAx[event.jaxis.which][event.jaxis.axis] == 0x100000) {
+ if(abs(event.jaxis.value) < 1000) {
+ LastAx[event.jaxis.which][event.jaxis.axis] = event.jaxis.value;
+ }
+ done--;
+ } else {
+ if(abs(LastAx[event.jaxis.which][event.jaxis.axis] - event.jaxis.value) >= 8192) {
+ bc->ButtType[wb] = BUTTC_JOYSTICK;
+ bc->DeviceNum[wb] = event.jaxis.which;
+ bc->ButtonNum[wb] = (0x8000 | event.jaxis.axis |
+ ((event.jaxis.value < 0)
+ ? 0x4000 : 0));
+ return(1);
+ }
+ else
+ done--;
+ }
+ break;
+ default:
+ done--;
}
- break;
}
+ if(done) break;
}
return(0);
diff --git a/src/drivers/sdl/input.h b/src/drivers/sdl/input.h
index 5dd5a128..abe5ddf5 100644
--- a/src/drivers/sdl/input.h
+++ b/src/drivers/sdl/input.h
@@ -19,6 +19,7 @@ void setHotKeys();
int ButtonConfigBegin();
void ButtonConfigEnd();
void ConfigButton(char *text, ButtConfig *bc);
+int DWaitButton(const uint8 *text, ButtConfig *bc, int wb);
#define BUTTC_KEYBOARD 0x00
#define BUTTC_JOYSTICK 0x01
@@ -49,5 +50,6 @@ void UpdateInput(Config *config);
void InputCfg(const std::string &);
std::string GetUserText(const char* title);
+const char* ButtonName(const ButtConfig* bc, int which);
#endif