pad: more input updates
authornotaz <notasas@gmail.com>
Fri, 13 Mar 2026 23:42:15 +0000 (01:42 +0200)
committernotaz <notasas@gmail.com>
Sat, 14 Mar 2026 00:03:35 +0000 (02:03 +0200)
simulate replug on config changes, cleanups

frontend/libretro.c
frontend/menu.c
frontend/plugin.c
frontend/plugin.h
libpcsxcore/pad.c
libpcsxcore/plugins.h
libpcsxcore/psxbios.c
libpcsxcore/sio.c

index 87e9b21..4040b3e 100644 (file)
@@ -881,8 +881,8 @@ static char *get_pse_pad_label[] = {
 static const struct retro_controller_description pads[8] =
 {
    { "standard",   RETRO_DEVICE_JOYPAD },
-   { "analog",     RETRO_DEVICE_PSE_ANALOG },
    { "dualshock",  RETRO_DEVICE_PSE_DUALSHOCK },
+   { "analog",     RETRO_DEVICE_PSE_ANALOG },
    { "negcon",     RETRO_DEVICE_PSE_NEGCON },
    { "guncon",     RETRO_DEVICE_PSE_GUNCON },
    { "konami gun", RETRO_DEVICE_PSE_JUSTIFIER },
@@ -1138,6 +1138,8 @@ unsigned retro_api_version(void)
 static void update_multitap(void)
 {
    struct retro_variable var = { 0 };
+   int multitap1_old = multitap1;
+   int multitap2_old = multitap2;
 
    multitap1 = 0;
    multitap2 = 0;
@@ -1156,13 +1158,19 @@ static void update_multitap(void)
          multitap2 = 1;
       }
    }
+   if (multitap1 != multitap1_old || multitap2 != multitap2_old) {
+      SysPrintf("multitap: %d %d\n", multitap1, multitap2);
+      padChanged();
+   }
 }
 
 void retro_set_controller_port_device(unsigned port, unsigned device)
 {
+   int in_type_old;
    if (port >= PORTS_NUMBER)
       return;
 
+   in_type_old = in_type[port];
    switch (device)
    {
    case RETRO_DEVICE_JOYPAD:
@@ -1193,7 +1201,10 @@ void retro_set_controller_port_device(unsigned port, unsigned device)
       break;
    }
 
-   SysPrintf("port: %u  device: %s\n", port + 1, get_pse_pad_label[in_type[port]]);
+   if (in_type[port] != in_type_old) {
+       SysPrintf("port: %u  device: %s\n", port + 1, get_pse_pad_label[in_type[port]]);
+       padChanged();
+   }
 }
 
 void retro_get_system_info(struct retro_system_info *info)
index 436c104..2702be3 100644 (file)
@@ -308,6 +308,7 @@ static int optional_cdimg_filter(struct dirent **namelist, int count,
 static void menu_sync_config(void)
 {
        static int allow_abs_only_old;
+       int in_type_old[2] = { in_type[0], in_type[1] };
 
        Config.PsxAuto = 1;
        if (region > 0) {
@@ -334,6 +335,8 @@ static void menu_sync_config(void)
                in_probe();
                allow_abs_only_old = in_evdev_allow_abs_only;
        }
+       if (in_type[0] != in_type_old[0] || in_type[1] != in_type_old[1])
+               padChanged();
 
        spu_config.iVolume = 768 + 128 * volume_boost;
        pl_rearmed_cbs.frameskip = frameskip - 1;
index 86b8bb9..0180e46 100644 (file)
 #include "../plugins/dfsound/spu.h"
 
 /* PAD */
-long PAD1_readPort(PadDataS *pad) {
+void PAD1_readPort(PadDataS *pad, int *is_multitap) {
        int pad_index = pad->requestPadIndex;
 
        pad->controllerType = in_type[pad_index];
        pad->buttonStatus = ~in_keystate[pad_index];
 
-       pad->portMultitap = multitap1;
-
        if (in_type[pad_index] == PSE_PAD_TYPE_ANALOGJOY || in_type[pad_index] == PSE_PAD_TYPE_ANALOGPAD || in_type[pad_index] == PSE_PAD_TYPE_NEGCON || in_type[pad_index] == PSE_PAD_TYPE_GUNCON || in_type[pad_index] == PSE_PAD_TYPE_GUN)
        {
                pad->leftJoyX = in_analog_left[pad_index][0];
@@ -49,17 +47,16 @@ long PAD1_readPort(PadDataS *pad) {
                pad->moveY = in_mouse[pad_index][1];
        }
 
-       return 0;
+       if (is_multitap)
+               *is_multitap = multitap1;
 }
 
-long PAD2_readPort(PadDataS *pad) {
+void PAD2_readPort(PadDataS *pad, int *is_multitap) {
        int pad_index = pad->requestPadIndex;
 
        pad->controllerType = in_type[pad_index];
        pad->buttonStatus = ~in_keystate[pad_index];
 
-       pad->portMultitap = multitap2;
-
        if (in_type[pad_index] == PSE_PAD_TYPE_ANALOGJOY || in_type[pad_index] == PSE_PAD_TYPE_ANALOGPAD || in_type[pad_index] == PSE_PAD_TYPE_NEGCON || in_type[pad_index] == PSE_PAD_TYPE_GUNCON || in_type[pad_index] == PSE_PAD_TYPE_GUN)
        {
                pad->leftJoyX = in_analog_left[pad_index][0];
@@ -77,7 +74,8 @@ long PAD2_readPort(PadDataS *pad) {
                pad->moveY = in_mouse[pad_index][1];
        }
 
-       return 0;
+       if (is_multitap)
+               *is_multitap = multitap2;
 }
 
 /* GPU */
index 20c622d..a77ec70 100644 (file)
@@ -16,7 +16,7 @@ void *plugin_link(enum builtint_plugins_e id, const char *sym);
 void plugin_call_rearmed_cbs(void);
 
 struct PadDataS;
-long PAD1_readPort(struct PadDataS *);
-long PAD2_readPort(struct PadDataS *);
+void PAD1_readPort(struct PadDataS *, int *is_multitap);
+void PAD2_readPort(struct PadDataS *, int *is_multitap);
 
 #endif /* __PLUGIN_H__ */
index 2f107b2..13d7de8 100644 (file)
 #include "psxcounters.h"
 #include "plugins.h"
 
-extern int in_type[8];
+#define REPLUG_FRAMES 32u
 
 // Pad information, keystate, mode, config mode, vibration
-static PadDataS pads[8];
-
-static int reqPos;
+static struct {
+       PadDataS pads[8];
+       int reqPos;
+       u32 replug_frame;
+} g;
 
 // response for request 44, 45, 46, 47, 4C, 4D
 static const u8 resp45[8]    = {0xF3, 0x5A, 0x01, 0x02, 0x00, 0x02, 0x01, 0x00};
@@ -179,7 +181,7 @@ static void initBufForRequest(PadDataS *pad, unsigned char value)
                if (pad->ds.autoAnalogTried == 16) {
                        // auto-enable for convenience
                        SysPrintf("Pad%ld: Auto-enabling dualshock analog mode.\n",
-                               (long)(pad - pads + 1));
+                               (long)(pad - g.pads + 1));
                        pad->ds.padMode = 1;
                        pad->ds.autoAnalogTried = 255;
                }
@@ -265,7 +267,7 @@ static void ds_update_vibrate(PadDataS *pad)
                pad->Vib[1] = 0;
        }
        if (pad->Vib[0] != pad->VibF[0] || pad->Vib[1] != pad->VibF[1]) {
-               size_t padIndex = pad - pads;
+               size_t padIndex = pad - g.pads;
                //value is different update Value and call libretro for vibration
                pad->VibF[0] = pad->Vib[0];
                pad->VibF[1] = pad->Vib[1];
@@ -381,7 +383,8 @@ static void PADstartPoll_(PadDataS *pad)
                        pad->respSize = 4;
                        break;
                default:
-                       pad->respSize = 0;
+                       pad->rxData[0] = 0xff;
+                       pad->respSize = 1;
                        break;
        }
 }
@@ -421,14 +424,16 @@ static void PADpoll_dualshock(PadDataS *pad, unsigned char value, int pos)
 
 static unsigned char PADpoll_(int port, unsigned char value, int pos, int *more_data)
 {
-       PadDataS *pad = &pads[port];
+       PadDataS *pad = &g.pads[port];
 
        if (pos < sizeof(pad->txData))
                pad->txData[pos] = value;
-       if (pos == 0 && value != 0x42 && in_type[port] != PSE_PAD_TYPE_ANALOGPAD)
+       if (pos == 0 && value != 0x42 && pad->controllerType != PSE_PAD_TYPE_ANALOGPAD) {
                pad->respSize = 1;
+               pad->rxData[0] = 0xff;
+       }
 
-       switch (in_type[port]) {
+       switch (pad->controllerType) {
                case PSE_PAD_TYPE_ANALOGPAD:
                        PADpoll_dualshock(pad, value, pos);
                        break;
@@ -440,7 +445,7 @@ static unsigned char PADpoll_(int port, unsigned char value, int pos, int *more_
 
        *more_data = pos < pad->respSize - 1;
        if (pos >= pad->respSize) {
-               log_unhandled("pad %zd read %d/%d\n", pad - pads, pos, pad->respSize);
+               log_unhandled("pad %zd read %d/%d\n", pad - g.pads, pos, pad->respSize);
                return 0xff; // no response/HiZ
        }
 
@@ -468,7 +473,7 @@ static unsigned char PADpollMultitap(int port, unsigned char value, int pos, int
 
        pos_dev = pos - 2;
        dev = pos_dev / 8u;
-       pad = &pads[port + dev];
+       pad = &g.pads[port + dev];
        if (pos_dev % 8u == 0) {
                memcpy(pad->rxDataOld, pad->rxData, sizeof(pad->rxDataOld));
                PADstartPoll_(pad);
@@ -481,13 +486,19 @@ static unsigned char PADpollMultitap(int port, unsigned char value, int pos, int
 static unsigned char PADpollMain(int port, unsigned char value, int *more_data)
 {
        unsigned char ret;
-       int pos = reqPos++;
+       int pos = g.reqPos++;
 
        PAD_LOG_TX(pos, value);
-
        if (pos == 1)
-               pads[port].txData1 = value;
-       if (!pads[port].portMultitap || !pads[port].multitapLongModeEnabled)
+               g.pads[port].txData1 = value;
+
+       if (g.replug_frame) {
+               if (frame_counter - g.replug_frame > REPLUG_FRAMES)
+                       g.replug_frame = 0;
+               ret = 0xff;
+               *more_data = 0;
+       }
+       else if (!g.pads[port].portMultitap || !g.pads[port].multitapLongModeEnabled)
                ret = PADpoll_(port, value, pos, more_data);
        else
                ret = PADpollMultitap(port, value, pos, more_data);
@@ -499,84 +510,99 @@ static unsigned char PADpollMain(int port, unsigned char value, int *more_data)
 
 }
 
+static int PADstartPollMain(PadDataS *pad)
+{
+       g.reqPos = 0;
+
+       pad->multitapLongModeEnabled = 0;
+       if (pad->portMultitap)
+               pad->multitapLongModeEnabled = pad->txData1 & 1;
+
+       if (!pad->portMultitap || !pad->multitapLongModeEnabled) {
+               PADstartPoll_(pad);
+               return 0;
+       }
+       return 1;
+}
+
 // refresh the button state on port 1.
 // int pad is not needed.
-unsigned char PAD1_startPoll(int unused)
+unsigned char PAD1_startPoll(void)
 {
+       PadDataS *pad = &g.pads[0];
        int i;
 
-       reqPos = 0;
-       pads[0].requestPadIndex = 0;
-       PAD1_readPort(&pads[0]);
-
-       pads[0].multitapLongModeEnabled = 0;
-       if (pads[0].portMultitap)
-               pads[0].multitapLongModeEnabled = pads[0].txData1 & 1;
+       pad->requestPadIndex = 0;
+       PAD1_readPort(pad, &pad->portMultitap);
 
-       if (!pads[0].portMultitap || !pads[0].multitapLongModeEnabled) {
-               PADstartPoll_(&pads[0]);
-       } else {
+       if (PADstartPollMain(pad)) {
                // a multitap is plugged and enabled: refresh pads 1-3
                for (i = 1; i < 4; i++) {
-                       pads[i].requestPadIndex = i;
-                       PAD1_readPort(&pads[i]);
+                       g.pads[i].requestPadIndex = i;
+                       PAD1_readPort(&g.pads[i], NULL);
                }
        }
        return 0xff;
 }
 
-unsigned char PAD1_poll(unsigned char value, int *more_data) {
+unsigned char PAD1_poll(unsigned char value, int *more_data)
+{
        return PADpollMain(0, value, more_data);
 }
 
-
-unsigned char PAD2_startPoll(int pad)
+unsigned char PAD2_startPoll(void)
 {
-       int pad_index = pads[0].portMultitap ? 4 : 1;
+       int pad_index = g.pads[0].portMultitap ? 4 : 1;
+       PadDataS *pad = &g.pads[pad_index];
        int i;
 
-       reqPos = 0;
-       pads[pad_index].requestPadIndex = pad_index;
-       PAD2_readPort(&pads[pad_index]);
-
-       pads[pad_index].multitapLongModeEnabled = 0;
-       if (pads[pad_index].portMultitap)
-               pads[pad_index].multitapLongModeEnabled = pads[pad_index].txData1 & 1;
+       pad->requestPadIndex = pad_index;
+       PAD2_readPort(pad, &pad->portMultitap);
 
-       if (!pads[pad_index].portMultitap || !pads[pad_index].multitapLongModeEnabled) {
-               PADstartPoll_(&pads[pad_index]);
-       } else {
+       if (PADstartPollMain(pad)) {
                for (i = 1; i < 4; i++) {
-                       pads[pad_index + i].requestPadIndex = pad_index + i;
-                       PAD2_readPort(&pads[pad_index + i]);
+                       g.pads[pad_index + i].requestPadIndex = pad_index + i;
+                       PAD2_readPort(&g.pads[pad_index + i], NULL);
                }
        }
        return 0xff;
 }
 
-unsigned char PAD2_poll(unsigned char value, int *more_data) {
-       return PADpollMain(pads[0].portMultitap ? 4 : 1, value, more_data);
+unsigned char PAD2_poll(unsigned char value, int *more_data)
+{
+       return PADpollMain(g.pads[0].portMultitap ? 4 : 1, value, more_data);
 }
 
 void padReset(void) {
        size_t p;
 
-       memset(pads, 0, sizeof(pads));
-       for (p = 0; p < sizeof(pads) / sizeof(pads[0]); p++) {
-               memset(pads[p].rxData, 0xff, sizeof(pads[p].rxData));
-               memset(pads[p].ds.cmd4dConfig, 0xff, sizeof(pads[p].ds.cmd4dConfig));
+       memset(&g, 0, sizeof(g));
+       for (p = 0; p < sizeof(g.pads) / sizeof(g.pads[0]); p++) {
+               memset(g.pads[p].rxData, 0xff, sizeof(g.pads[p].rxData));
+               memset(g.pads[p].ds.cmd4dConfig, 0xff, sizeof(g.pads[p].ds.cmd4dConfig));
        }
 }
 
-int padFreeze(void *f, int Mode) {
+int padFreeze(void *f, int Mode)
+{
+       int changed = 0;
        size_t i;
 
-       for (i = 0; i < sizeof(pads) / sizeof(pads[0]); i++) {
-               pads[i].saveSize = sizeof(pads[i]);
-               gzfreeze(&pads[i], sizeof(pads[i]));
-               if (Mode == 0 && pads[i].saveSize != sizeof(pads[i]))
-                       SaveFuncs.seek(f, pads[i].saveSize - sizeof(pads[i]), SEEK_CUR);
+       for (i = 0; i < sizeof(g.pads) / sizeof(g.pads[0]); i++) {
+               unsigned char controllerType = g.pads[i].controllerType;
+               int portMultitap = g.pads[i].portMultitap;
+               g.pads[i].saveSize = sizeof(g.pads[i]);
+               gzfreeze(&g.pads[i], sizeof(g.pads[i]));
+               if (Mode == 0) { // load
+                       if (g.pads[i].saveSize != sizeof(g.pads[i]))
+                               SaveFuncs.seek(f, g.pads[i].saveSize - sizeof(g.pads[i]),
+                                               SEEK_CUR);
+                       changed |= controllerType != g.pads[i].controllerType;
+                       changed |= portMultitap != g.pads[i].portMultitap;
+               }
        }
+       if (changed)
+               padChanged();
 
        return 0;
 }
@@ -585,9 +611,15 @@ int padToggleAnalog(unsigned int index)
 {
        int r = -1;
 
-       if (index < sizeof(pads) / sizeof(pads[0])) {
-               r = (pads[index].ds.padMode ^= 1);
-               pads[index].ds.userToggled = 1;
+       if (index < sizeof(g.pads) / sizeof(g.pads[0])) {
+               r = (g.pads[index].ds.padMode ^= 1);
+               g.pads[index].ds.userToggled = 1;
        }
        return r;
 }
+
+void padChanged(void)
+{
+       padReset();
+       g.replug_frame = frame_counter;
+}
index f8a3197..f44e425 100644 (file)
@@ -124,17 +124,18 @@ extern SPUplayCDDAchannel  SPU_playCDDAchannel;
 extern SPUsetCDvol         SPU_setCDvol;\r
 \r
 // PAD Functions\r
-long PAD1_readPort(PadDataS *);\r
-unsigned char PAD1_startPoll(int);\r
+void PAD1_readPort(struct PadDataS *, int *is_multitap);\r
+unsigned char PAD1_startPoll(void);\r
 unsigned char PAD1_poll(unsigned char, int *);\r
 \r
-long PAD2_readPort(PadDataS *);\r
-unsigned char PAD2_startPoll(int);\r
+void PAD2_readPort(struct PadDataS *, int *is_multitap);\r
+unsigned char PAD2_startPoll(void);\r
 unsigned char PAD2_poll(unsigned char, int *);\r
 \r
 int padFreeze(void *f, int Mode);\r
 int padToggleAnalog(unsigned int index);\r
 void padReset(void);\r
+void padChanged(void);\r
 \r
 #ifdef ENABLE_SIO1API\r
 \r
index de3768f..ee358a7 100644 (file)
@@ -4135,7 +4135,7 @@ void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 stack) {
 
 #define psxBios_PADpoll(pad) { \
        int i, more_data = 0; \
-       PAD##pad##_startPoll(pad); \
+       PAD##pad##_startPoll(); \
        pad_buf##pad[1] = PAD##pad##_poll(0x42, &more_data); \
        pad_buf##pad[0] = more_data ? 0 : 0xff; \
        PAD##pad##_poll(0, &more_data); \
index 3234541..e35631b 100644 (file)
@@ -208,8 +208,8 @@ void sioWrite8(unsigned char value) {
                        StatReg |= RX_RDY;              // Transfer is Ready
 
                        switch (CtrlReg & 0x2002) {
-                               case 0x0002: buf[0] = PAD1_startPoll(1); break;
-                               case 0x2002: buf[0] = PAD2_startPoll(2); break;
+                               case 0x0002: buf[0] = PAD1_startPoll(); break;
+                               case 0x2002: buf[0] = PAD2_startPoll(); break;
                        }
                        bufcount = 1;
                        parp = 0;