From 80d871b4bdc9996049da243ce0eef2d589ac237f Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Tue, 23 Jun 2026 21:34:42 -0500 Subject: [PATCH] pbus: fix orbatak silly pad to 24-bit and split trackball/buttons --- libopera/opera_pbus.c | 20 ++++++++++++------- libopera/opera_pbus.h | 11 ++++++++--- libopera/pbus.txt | 36 +++++++++++++++++++++------------- lr_input.c | 45 +++++++++++++++++++++++++++++++------------ 4 files changed, 77 insertions(+), 35 deletions(-) diff --git a/libopera/opera_pbus.c b/libopera/opera_pbus.c index b792b73..b8714d5 100644 --- a/libopera/opera_pbus.c +++ b/libopera/opera_pbus.c @@ -283,7 +283,7 @@ opera_pbus_add_arcade_lightgun(const opera_pbus_arcade_lightgun_t *lg_) void opera_pbus_add_orbatak_trackball(const opera_pbus_orbatak_trackball_t *tb_) { - if(!pbus_reserve(8)) + if(!pbus_reserve(4)) return; PBUS.buf[PBUS.idx++] = PBUS_ORBATAK_TRACKBALL_ID; @@ -291,15 +291,21 @@ opera_pbus_add_orbatak_trackball(const opera_pbus_orbatak_trackball_t *tb_) PBUS.buf[PBUS.idx++] = (((tb_->y & 0x03F) << 2) | ((tb_->x & 0x300) >> 8)); PBUS.buf[PBUS.idx++] = (tb_->x & 0xFF); +} + +void +opera_pbus_add_orbatak_buttons(const opera_pbus_orbatak_buttons_t *btn_) +{ + if(!pbus_reserve(3)) + return; PBUS.buf[PBUS.idx++] = PBUS_ORBATAK_BUTTONS_ID; PBUS.buf[PBUS.idx++] = 0; - PBUS.buf[PBUS.idx++] = ((tb_->coin_p1 << PBUS_ORBATAK_SHIFT_COIN_P1) | - (tb_->coin_p2 << PBUS_ORBATAK_SHIFT_COIN_P2) | - (tb_->start_p1 << PBUS_ORBATAK_SHIFT_START_P1) | - (tb_->start_p2 << PBUS_ORBATAK_SHIFT_START_P2) | - (tb_->service << PBUS_ORBATAK_SHIFT_SERVICE)); - PBUS.buf[PBUS.idx++] = 0; + PBUS.buf[PBUS.idx++] = ((btn_->coin_p1 << PBUS_ORBATAK_SHIFT_COIN_P1) | + (btn_->coin_p2 << PBUS_ORBATAK_SHIFT_COIN_P2) | + (btn_->start_p1 << PBUS_ORBATAK_SHIFT_START_P1) | + (btn_->start_p2 << PBUS_ORBATAK_SHIFT_START_P2) | + (btn_->service << PBUS_ORBATAK_SHIFT_SERVICE)); } void* diff --git a/libopera/opera_pbus.h b/libopera/opera_pbus.h index ba28596..6fbcc7a 100644 --- a/libopera/opera_pbus.h +++ b/libopera/opera_pbus.h @@ -72,15 +72,18 @@ struct opera_pbus_arcade_lightgun_s }; struct opera_pbus_orbatak_trackball_s +{ + int16_t x; + int16_t y; +}; + +struct opera_pbus_orbatak_buttons_s { uint8_t start_p1; uint8_t start_p2; uint8_t coin_p1; uint8_t coin_p2; uint8_t service; - - int16_t x; - int16_t y; }; typedef struct opera_pbus_joypad_s opera_pbus_joypad_t; @@ -89,6 +92,7 @@ typedef struct opera_pbus_mouse_s opera_pbus_mouse_t; typedef struct opera_pbus_lightgun_s opera_pbus_lightgun_t; typedef struct opera_pbus_arcade_lightgun_s opera_pbus_arcade_lightgun_t; typedef struct opera_pbus_orbatak_trackball_s opera_pbus_orbatak_trackball_t; +typedef struct opera_pbus_orbatak_buttons_s opera_pbus_orbatak_buttons_t; void* opera_pbus_buf(void); uint32_t opera_pbus_size(void); @@ -100,5 +104,6 @@ void opera_pbus_add_mouse(const opera_pbus_mouse_t *mouse_); void opera_pbus_add_lightgun(const opera_pbus_lightgun_t *lightgun_); void opera_pbus_add_arcade_lightgun(const opera_pbus_arcade_lightgun_t *lightgun_); void opera_pbus_add_orbatak_trackball(const opera_pbus_orbatak_trackball_t *tb_); +void opera_pbus_add_orbatak_buttons(const opera_pbus_orbatak_buttons_t *btn_); #endif /* LIBOPERA_PBUS_H_INCLUDED */ diff --git a/libopera/pbus.txt b/libopera/pbus.txt index 4eb018b..3d72946 100644 --- a/libopera/pbus.txt +++ b/libopera/pbus.txt @@ -169,21 +169,31 @@ y = ((10 * counter) / NTSC_DEFAULT_YSCANTIME); ### ORBATAK TRACKBALL -Orbatak uses two different devices. The trackballs are just mice as -described above. The buttons (coins, start, service) are managed via -the "SILLY_CONTROL_PAD" as defined in the 3DO SDK (event.h) or in the -least uses the same identifier. +Orbatak uses two different devices per player. The trackballs are just +mice as described above. The buttons (coins, start, service) use the +SILLY_CONTROL_PAD (0xC0) identifier as defined in the 3DO SDK (event.h). +The Portfolio OS EventBroker parses 0xC0 as a 24-bit (3 byte) device +(EventBroker.c: inBits=24, outBits=8). + +The standard SILLY_CONTROL_PAD format (3 bytes, 24 bits): MSB -> LSB -8bit: identifier (0xC0) -8bit: 0x00 -3bit: unused -1bit: coin (p1) -1bit: coin (p2) -1bit: start (p2) -1bit: start (p1) -1bit: service -8bit: 0x00 +* 8bit: identifier (0xC0) in bits 7-5, standard control pad buttons + (down, up, right, left, A) in bits 4-0 +* 8bit: standard control pad buttons (B, C, Start, X, RT, LT) in + bits 7-2, unused in bits 1-0 +* 8bit: unused by the standard driver, available for custom devices + +Orbatak maps its arcade buttons in byte 2 (the third byte): + +MSB -> LSB +2bit: unused (bits 7,6) +1bit: coin (p1) (bit 5) +1bit: coin (p2) (bit 4) +1bit: unused (bit 3) +1bit: start (p2) (bit 2) +1bit: start (p1) (bit 1) +1bit: service (bit 0) ## Device Usage In Games diff --git a/lr_input.c b/lr_input.c index 46559a4..08296fc 100644 --- a/lr_input.c +++ b/lr_input.c @@ -7,6 +7,8 @@ #include +#include + static uint32_t ACTIVE_DEVICES = 0; static unsigned PBUS_DEVICES[LR_INPUT_MAX_DEVICES] = {0}; @@ -149,7 +151,7 @@ lr_input_poll_lightgun(const int port_) lg.trigger = poll_lightgun(port_,RETRO_DEVICE_ID_LIGHTGUN_TRIGGER); lg.option = poll_lightgun(port_,RETRO_DEVICE_ID_LIGHTGUN_SELECT); lg.reload = poll_lightgun(port_,RETRO_DEVICE_ID_LIGHTGUN_RELOAD); - + if(poll_lightgun(port_,RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN)) { lg.trigger = 0; @@ -174,7 +176,7 @@ lr_input_poll_arcade_lightgun(const int port_) lg.coins = poll_lightgun(port_,RETRO_DEVICE_ID_LIGHTGUN_SELECT); lg.start = poll_lightgun(port_,RETRO_DEVICE_ID_LIGHTGUN_START); lg.holster = poll_lightgun(port_,RETRO_DEVICE_ID_LIGHTGUN_RELOAD); - + if(poll_lightgun(port_,RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN)) { lg.trigger = 0; @@ -210,15 +212,21 @@ lr_input_poll_orbatak_trackball(const int port_) tb.y = 24; } - tb.start_p1 = poll_joypad(port_,RETRO_DEVICE_ID_JOYPAD_SELECT); - tb.start_p2 = poll_joypad(port_,RETRO_DEVICE_ID_JOYPAD_START); - tb.coin_p1 = poll_joypad(port_,RETRO_DEVICE_ID_JOYPAD_L); - tb.coin_p2 = poll_joypad(port_,RETRO_DEVICE_ID_JOYPAD_R); - tb.service = poll_joypad(port_,RETRO_DEVICE_ID_JOYPAD_R2); - opera_pbus_add_orbatak_trackball(&tb); } +static +void +lr_input_poll_orbatak_buttons(const int port_, + opera_pbus_orbatak_buttons_t *btn_) +{ + btn_->start_p1 |= poll_joypad(port_,RETRO_DEVICE_ID_JOYPAD_SELECT); + btn_->start_p2 |= poll_joypad(port_,RETRO_DEVICE_ID_JOYPAD_START); + btn_->coin_p1 |= poll_joypad(port_,RETRO_DEVICE_ID_JOYPAD_L); + btn_->coin_p2 |= poll_joypad(port_,RETRO_DEVICE_ID_JOYPAD_R); + btn_->service |= poll_joypad(port_,RETRO_DEVICE_ID_JOYPAD_R2); +} + static void lr_input_poll(const int port_) @@ -243,9 +251,6 @@ lr_input_poll(const int port_) case RETRO_DEVICE_ARCADE_LIGHTGUN: lr_input_poll_arcade_lightgun(port_); break; - case RETRO_DEVICE_ORBATAK_TRACKBALL: - lr_input_poll_orbatak_trackball(port_); - break; } } @@ -293,6 +298,11 @@ lr_input_update(const uint32_t active_devices_) { int i; uint32_t active_devices; + int has_orbatak; + opera_pbus_orbatak_buttons_t orbatak_buttons; + + has_orbatak = 0; + memset(&orbatak_buttons,0,sizeof(orbatak_buttons)); opera_pbus_reset(); retro_input_poll_cb(); @@ -302,6 +312,17 @@ lr_input_update(const uint32_t active_devices_) { if(PBUS_DEVICES[i] == RETRO_DEVICE_NONE) continue; - lr_input_poll(i); + + if(PBUS_DEVICES[i] == RETRO_DEVICE_ORBATAK_TRACKBALL) + { + lr_input_poll_orbatak_trackball(i); + lr_input_poll_orbatak_buttons(i,&orbatak_buttons); + has_orbatak = 1; + } + else + lr_input_poll(i); } + + if(has_orbatak) + opera_pbus_add_orbatak_buttons(&orbatak_buttons); }