From 002e9e0f34819dc89b013b62c7fab8c4fbf0f57d Mon Sep 17 00:00:00 2001
From: mjbudd77 <mjbudd77@gmail.com>
Date: Fri, 26 Jun 2020 16:35:41 -0400
Subject: [PATCH] Added logic to configure gamepad buttons. Still needs more
 testing.

---
 src/drivers/Qt/GameApp.cpp     |  43 +++++--
 src/drivers/Qt/GameApp.h       |   4 +
 src/drivers/Qt/GamePadConf.cpp | 206 +++++++++++++++++++++++++++++++--
 src/drivers/Qt/GamePadConf.h   |  24 ++++
 src/drivers/Qt/input.cpp       |  22 +++-
 5 files changed, 283 insertions(+), 16 deletions(-)

diff --git a/src/drivers/Qt/GameApp.cpp b/src/drivers/Qt/GameApp.cpp
index 25d2e07a..3b05e458 100644
--- a/src/drivers/Qt/GameApp.cpp
+++ b/src/drivers/Qt/GameApp.cpp
@@ -32,24 +32,41 @@ gameWin_t::gameWin_t(QWidget *parent)
 
 	gameTimer->setTimerType( Qt::PreciseTimer );
 	gameTimer->start( 10 );
+
+   gamePadConfWin = NULL;
 }
 
 gameWin_t::~gameWin_t(void)
 {
+   if ( gamePadConfWin != NULL )
+   {
+      gamePadConfWin->closeWindow();
+   }
 	fceuWrapperClose();
 
 	delete viewport;
 }
 
+void gameWin_t::closeEvent(QCloseEvent *event)
+{
+   printf("Main Window Close Event\n");
+   if ( gamePadConfWin != NULL )
+   {
+      printf("Command Game Pad Close\n");
+      gamePadConfWin->closeWindow();
+   }
+   event->accept();
+}
+
 void gameWin_t::keyPressEvent(QKeyEvent *event)
 {
-   //printf("Key Press: 0x%x \n", event->key() );
+   printf("Key Press: 0x%x \n", event->key() );
 	pushKeyEvent( event, 1 );
 }
 
 void gameWin_t::keyReleaseEvent(QKeyEvent *event)
 {
-   //printf("Key Release: 0x%x \n", event->key() );
+   printf("Key Release: 0x%x \n", event->key() );
 	pushKeyEvent( event, 0 );
 }
 
@@ -165,8 +182,20 @@ void gameWin_t::closeROMCB(void)
 
 void gameWin_t::openGamePadConfWin(void)
 {
+   if ( gamePadConfWin != NULL )
+   {
+      printf("GamePad Config Window Already Open\n");
+      return;
+   }
 	printf("Open GamePad Config Window\n");
-	GamePadConfDialog_t  gpConf(this);
+   gamePadConfWin = new GamePadConfDialog_t(this);
+	
+   gamePadConfWin->show();
+   gamePadConfWin->exec();
+
+   delete gamePadConfWin;
+   gamePadConfWin = NULL;
+   printf("GamePad Config Window Destroyed\n");
 }
 
 void gameWin_t::aboutQPlot(void)
@@ -177,12 +206,12 @@ void gameWin_t::aboutQPlot(void)
 
 void gameWin_t::runGameFrame(void)
 {
-	struct timespec ts;
-	double t;
+	//struct timespec ts;
+	//double t;
 
-	clock_gettime( CLOCK_REALTIME, &ts );
+	//clock_gettime( CLOCK_REALTIME, &ts );
 
-	t = (double)ts.tv_sec + (double)(ts.tv_nsec * 1.0e-9);
+	//t = (double)ts.tv_sec + (double)(ts.tv_nsec * 1.0e-9);
    //printf("Run Frame %f\n", t);
 	
 	fceuWrapperUpdate();
diff --git a/src/drivers/Qt/GameApp.h b/src/drivers/Qt/GameApp.h
index 5dafcfff..258bfa77 100644
--- a/src/drivers/Qt/GameApp.h
+++ b/src/drivers/Qt/GameApp.h
@@ -16,6 +16,7 @@
 #include <QTimer>
 
 #include "GameViewer.h"
+#include "GamePadConf.h"
 
 class  gameWin_t : public QMainWindow
 {
@@ -41,7 +42,10 @@ class  gameWin_t : public QMainWindow
 
 	 QTimer  *gameTimer;
 
+    GamePadConfDialog_t *gamePadConfWin;
+
 	protected:
+    void closeEvent(QCloseEvent *event);
 	 void keyPressEvent(QKeyEvent *event);
 	 void keyReleaseEvent(QKeyEvent *event);
 
diff --git a/src/drivers/Qt/GamePadConf.cpp b/src/drivers/Qt/GamePadConf.cpp
index c056e137..9d155df0 100644
--- a/src/drivers/Qt/GamePadConf.cpp
+++ b/src/drivers/Qt/GamePadConf.cpp
@@ -1,13 +1,26 @@
 // GamePadConf.cpp
 //
 #include "GamePadConf.h"
+#include "main.h"
+#include "input.h"
+#include "config.h"
+#include "keyscan.h"
+#include "fceuWrapper.h"
 
 //----------------------------------------------------
 GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent)
 	: QDialog( parent )
 {
-	QHBoxLayout *hbox1, *hbox2;
-	QCheckBox *efs_chkbox;
+	QHBoxLayout *hbox1;
+	QGridLayout *grid;
+	QCheckBox *efs_chkbox, *udlr_chkbox;
+   QGroupBox *frame;
+   QPushButton *closebutton;
+
+   portNum = 0;
+   buttonConfigStatus = 1;
+
+   setWindowTitle("GamePad Config");
 
 	hbox1 = new QHBoxLayout();
 
@@ -16,25 +29,202 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent)
 	hbox1->addWidget( label );
 	hbox1->addWidget( portSel );
 
-	hbox2 = new QHBoxLayout();
-	efs_chkbox = new QCheckBox("Enable Four Score");
-	hbox2->addWidget( efs_chkbox );
+   portSel->addItem( tr("1"), 0 );
+   portSel->addItem( tr("2"), 1 );
+   portSel->addItem( tr("3"), 2 );
+   portSel->addItem( tr("4"), 3 );
+
+	efs_chkbox  = new QCheckBox("Enable Four Score");
+	udlr_chkbox = new QCheckBox("Allow Up+Down/Left+Right");
+
+   frame = new QGroupBox(tr("Buttons:"));
+   grid  = new QGridLayout();
+
+   grid-> setHorizontalSpacing(50);
+
+   //frame->setFrameStyle( QFrame::Box );
+   frame->setLayout( grid );
+
+   for (int i=0; i<10; i++)
+   {
+      char text[64];
+      const char *keyNameStr;
+	   QLabel *buttonName;
+
+      sprintf( text, "%s:", GamePadNames[i] );
+
+	   //hbox2 = new QHBoxLayout();
+
+      //hbox2->setAlignment(Qt::AlignCenter);
+
+      keyNameStr = ButtonName( &GamePadConfig[portNum][i], portNum );
+
+	   buttonName = new QLabel(tr(text));
+	   keyName[i] = new QLabel(tr(keyNameStr));
+      button[i]  = new QPushButton(tr("Change"));
+
+      grid->addWidget( buttonName, i, 0, Qt::AlignCenter );
+      grid->addWidget( keyName[i], i, 1, Qt::AlignCenter );
+      grid->addWidget( button[i] , i, 2, Qt::AlignCenter );
+   }
+   closebutton     = new QPushButton(tr("Close"));
+
+   connect(button[0], SIGNAL(clicked()), this, SLOT(changeButton0(void)) );
+   connect(button[1], SIGNAL(clicked()), this, SLOT(changeButton1(void)) );
+   connect(button[2], SIGNAL(clicked()), this, SLOT(changeButton2(void)) );
+   connect(button[3], SIGNAL(clicked()), this, SLOT(changeButton3(void)) );
+   connect(button[4], SIGNAL(clicked()), this, SLOT(changeButton4(void)) );
+   connect(button[5], SIGNAL(clicked()), this, SLOT(changeButton5(void)) );
+   connect(button[6], SIGNAL(clicked()), this, SLOT(changeButton6(void)) );
+   connect(button[7], SIGNAL(clicked()), this, SLOT(changeButton7(void)) );
+   connect(button[8], SIGNAL(clicked()), this, SLOT(changeButton8(void)) );
+   connect(button[9], SIGNAL(clicked()), this, SLOT(changeButton9(void)) );
+   connect(closebutton, SIGNAL(clicked()), this, SLOT(closeWindow(void)) );
 
 	QVBoxLayout *mainLayout = new QVBoxLayout();
 
 	mainLayout->addLayout( hbox1 );
 	mainLayout->addWidget( efs_chkbox );
-	//mainLayout->addLayout( hbox2 );
+	mainLayout->addWidget( udlr_chkbox );
+	mainLayout->addWidget( frame );
+	mainLayout->addWidget( closebutton, Qt::AlignRight );
 
 	setLayout( mainLayout );
 
-	show();
-	exec();
+	//show();
+	//exec();
+
 }
 
 //----------------------------------------------------
 GamePadConfDialog_t::~GamePadConfDialog_t(void)
 {
+   buttonConfigStatus = 0;
+}
+void GamePadConfDialog_t::keyPressEvent(QKeyEvent *event)
+{
+   //printf("Key Press: 0x%x \n", event->key() );
+	pushKeyEvent( event, 1 );
+}
 
+void GamePadConfDialog_t::keyReleaseEvent(QKeyEvent *event)
+{
+   //printf("Key Release: 0x%x \n", event->key() );
+	pushKeyEvent( event, 0 );
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton(int padNo, int x)
+{
+   int configNo = 0;
+   char buf[256];
+   std::string prefix;
+   const char *keyNameStr;
+
+   if ( buttonConfigStatus == 2 )
+   {
+      buttonConfigStatus = 0;
+      return;
+   }
+   buttonConfigStatus = 2;
+
+   ButtonConfigBegin ();
+
+   button[x]->setText("Waiting" );
+
+   snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%d.", padNo);
+	prefix = buf;
+	DWaitButton (NULL, &GamePadConfig[padNo][x], configNo, &buttonConfigStatus );
+
+   g_config->setOption (prefix + GamePadNames[x],
+			     GamePadConfig[padNo][x].ButtonNum[configNo]);
+
+   if (GamePadConfig[padNo][x].ButtType[0] == BUTTC_KEYBOARD)
+	{
+		g_config->setOption (prefix + "DeviceType", "Keyboard");
+	}
+	else if (GamePadConfig[padNo][x].ButtType[0] == BUTTC_JOYSTICK)
+	{
+		g_config->setOption (prefix + "DeviceType", "Joystick");
+	}
+	else
+	{
+		g_config->setOption (prefix + "DeviceType", "Unknown");
+	}
+	g_config->setOption (prefix + "DeviceNum",
+			     GamePadConfig[padNo][x].DeviceNum[configNo]);
+
+   keyNameStr = ButtonName( &GamePadConfig[padNo][x], padNo );
+
+   keyName[x]->setText( keyNameStr );
+   button[x]->setText("Change");
+
+   ButtonConfigEnd ();
+
+   buttonConfigStatus = 1;
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::closeEvent(QCloseEvent *event)
+{
+   printf("GamePad Close Window Event\n");
+   buttonConfigStatus = 0;
+   done(0);
+   event->accept();
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::closeWindow(void)
+{
+   printf("Close Window\n");
+   buttonConfigStatus = 0;
+   done(0);
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton0(void)
+{
+   changeButton( portNum, 0 );
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton1(void)
+{
+   changeButton( portNum, 1 );
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton2(void)
+{
+   changeButton( portNum, 2 );
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton3(void)
+{
+   changeButton( portNum, 3 );
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton4(void)
+{
+   changeButton( portNum, 4 );
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton5(void)
+{
+   changeButton( portNum, 5 );
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton6(void)
+{
+   changeButton( portNum, 6 );
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton7(void)
+{
+   changeButton( portNum, 7 );
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton8(void)
+{
+   changeButton( portNum, 8 );
+}
+//----------------------------------------------------
+void GamePadConfDialog_t::changeButton9(void)
+{
+   changeButton( portNum, 9 );
 }
 //----------------------------------------------------
diff --git a/src/drivers/Qt/GamePadConf.h b/src/drivers/Qt/GamePadConf.h
index 62962b3d..e7dd6cc5 100644
--- a/src/drivers/Qt/GamePadConf.h
+++ b/src/drivers/Qt/GamePadConf.h
@@ -11,18 +11,42 @@
 #include <QCheckBox>
 #include <QPushButton>
 #include <QLabel>
+#include <QFrame>
+#include <QGroupBox>
 
 class GamePadConfDialog_t : public QDialog
 {
+   Q_OBJECT
+
 	public:
 		GamePadConfDialog_t(QWidget *parent = 0);
 		~GamePadConfDialog_t(void);
 
 	protected:
 		QComboBox *portSel;
+      QPushButton *button[10];
+      QLabel      *keyName[10];
 
+      int  portNum;
+      int  buttonConfigStatus;
 
+      void changeButton( int port, int button );
+      void keyPressEvent(QKeyEvent *event);
+	   void keyReleaseEvent(QKeyEvent *event);
+      void closeEvent(QCloseEvent *bar);
 
+   public slots:
+      void closeWindow(void);
 	private slots:
+      void changeButton0(void);
+      void changeButton1(void);
+      void changeButton2(void);
+      void changeButton3(void);
+      void changeButton4(void);
+      void changeButton5(void);
+      void changeButton6(void);
+      void changeButton7(void);
+      void changeButton8(void);
+      void changeButton9(void);
 
 };
diff --git a/src/drivers/Qt/input.cpp b/src/drivers/Qt/input.cpp
index 701e9e0b..a95bec6f 100644
--- a/src/drivers/Qt/input.cpp
+++ b/src/drivers/Qt/input.cpp
@@ -52,6 +52,7 @@ extern bool bindSavestate, frameAdvanceLagSkip, lagCounterDisplay;
 static int UsrInputType[NUM_INPUT_DEVICES];
 static int CurInputType[NUM_INPUT_DEVICES];
 static int cspec = 0;
+static int buttonConfigInProgress = 0;
 
 extern int gametype;
 
@@ -963,7 +964,7 @@ UpdatePhysicalInput ()
 }
 
 
-static int bcpv, bcpj;
+static int bcpv=0, bcpj=0;
 
 /**
  *  Begin configuring the buttons by placing the video and joystick
@@ -981,6 +982,8 @@ int ButtonConfigBegin ()
 	// initialize the joystick subsystem
 	InitJoysticks ();
 
+   buttonConfigInProgress = 1;
+
 	return 1;
 }
 
@@ -1004,6 +1007,7 @@ ButtonConfigEnd ()
 	{
 		InitJoysticks ();
 	}
+   buttonConfigInProgress = 0;
 }
 
 /**
@@ -1197,6 +1201,10 @@ void FCEUD_UpdateInput ()
 	int x;
 	int t = 0;
 
+   if ( buttonConfigInProgress )
+   {
+      return;
+   }
 	UpdatePhysicalInput ();
 	KeyboardCommands ();
 
@@ -1622,6 +1630,7 @@ int DWaitButton (const uint8 * text, ButtConfig * bc, int wb, int *buttonConfigS
 	SDL_Event event;
 	static int32 LastAx[64][64];
 	int x, y;
+   int timeout_ms = 10000;
 
 	if (text)
 	{
@@ -1643,6 +1652,16 @@ int DWaitButton (const uint8 * text, ButtConfig * bc, int wb, int *buttonConfigS
 	while (1)
 	{
 		int done = 0;
+
+      usleep(10000);
+      timeout_ms -= 10;
+
+      if ( timeout_ms <= 0 )
+      {
+         break;
+      }
+
+      QCoreApplication::processEvents();
 //#ifdef _GTK
 //		while (gtk_events_pending ())
 //			gtk_main_iteration_do (FALSE);
@@ -1653,6 +1672,7 @@ int DWaitButton (const uint8 * text, ButtConfig * bc, int wb, int *buttonConfigS
 			switch (event.type)
 			{
 				case SDL_KEYDOWN:
+               //printf("SDL KeyDown:%i \n", event.key.keysym.sym );
 					bc->ButtType[wb] = BUTTC_KEYBOARD;
 					bc->DeviceNum[wb] = 0;
 					bc->ButtonNum[wb] = event.key.keysym.sym;