Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AppleJack (Pippin) controller support #117

Merged
merged 5 commits into from
Oct 7, 2024

Conversation

kkaisershot
Copy link
Contributor

Add support for the Pippin controller, now that rudimentary support for Pippin is present. Use SDL's GameController API for a consistent button mapping across popular modern gamepads. Refactor AdbMouse to support passing mouse specifications at construction time in addition to hardcoding via a preprocessor macro. Likewise, add new "adb_devices" property to allow for users to specify at launch which ADB devices should be emulated, rather than hardcoding mouse and keyboard for all machine types.

AdbMouse and AdbKeyboard are subdevices of the CUDA device alongside AdbBus.
This doesn't make sense because conceptually, ADB devices hang off of the ADB
bus, not CUDA itself. An ADB bus can exist without a CUDA present, for example
Egret on older 68K Macs and the PMU on newer Power Macs. Therefore, make the ADB
device list a subhierarchy of AdbBus instead. Add a new "adb_devices" property
belonging to AdbBus that can allow users to specify ADB devices on the command
line at machine creation time, independent of the emulated bus's host. Make this
property default to "Mouse,Keyboard" to preserve existing behavior.
Add new GamepadButton enum with bits corresponding to AppleJack button bits.
Both the AppleJack controller and the SDL GameController coincidentally define
one d-pad, two shoulder buttons, four face buttons, and three system buttons.
This makes mapping modern game controllers to the AppleJack straightforward.
All AppleJack controllers start in mouse emulation mode, behaving exactly like
ADB mice. Only upon receiving a Listen command on register 3 with handler ID
0x46 does the AppleJack switch protocols, albeit such a change consisting merely
of expanding register 0's buffer size to 4 bytes. In this state, the first 2
bytes remain defined as they are for an ADB mouse; the additional 16 bits carry
the respective states of each of the AppleJack controller's remaining 11 buttons
out of a possible supported 16.

For backward compatibility, honor both mouse clicks and shoulder button presses
on the host when considering the state of the emulated trigger buttons.
Leave a keyboard attached for compatibility.
@joevt
Copy link
Contributor

joevt commented Oct 7, 2024

I like it.

  • In my fork, I had moved AdbMouse and AdbKeyboard to AdbBus, but like you said, perhaps we don't want all machines to always include those. Your new adb_devices property is a way for a machine to define its default list of devices and for a user to override that list.

  • In this fork, you have to give each device a different name if you want to add multiple of the same device. My fork has changes that allow connecting multiple devices of the same name so you can specify multiple pippin controllers for example. I am working on command line changes to support this.

  • In either fork, there's some AdbBus issues that make Adb address collisions not get handled correctly.

  • The AdbMouse and AdbKeyboard devices are types that should only be added once, since they use system events. A different kind of mouse and keyboard needs to be added to support additional mice and keyboards - they maybe will use SDL's HID APIs to capture a device removing that device from the ones that send system events.

  • Do I understand correctly that this Pippin Controller is similar to the AdbMouse and AdbKeyboard devices, in that it uses global system events specific to game controllers in the same way that AdbMouse uses system events specific to mice, and AdbKeyboard uses system events specific to keyboards? In that case, a different type of Pippin controller needs to be created in order to add additional pippin controllers, using SDL's HID APIs to capture a device and removing that device from the ones that send global game controller events.

  • If in either the mouse, or keyboard, or game controller event there is a way to distinguish events between different mice, keyboards, and game controllers, then that could be the method used to distinguish events between duplicate Adb devices.

  • Looks like SDL gamepads have an ID. You could open all gamepads for the system events version of the Pippin. Additional pippin controllers will remove gamepad IDs from the first pippin controller.

  • If SDL gamepads have names or serial numbers, then that may be a better way to assign them to AdbDevices. Different game controllers might be better at emulating different ADB devices. See issue Feature Request - Emulated Joysticks #24 .

@dingusdev dingusdev merged commit 1f05865 into dingusdev:master Oct 7, 2024
5 checks passed
@kkaisershot
Copy link
Contributor Author

kkaisershot commented Oct 8, 2024

  • In this fork, you have to give each device a different name if you want to add multiple of the same device. My fork has changes that allow connecting multiple devices of the same name so you can specify multiple pippin controllers for example. I am working on command line changes to support this.

Very cool; looking forward to that! I didn't pursue that here because it was apparent to me that DingusPPC does not yet support multiple ADB devices of the same type, and I wanted to limit the scope of this PR to just AppleJack support. Officially, Pippin supports up to four AppleJack controllers at once, though I'm not sure if/how anything enforces this given that there can be up to 15 devices present on an ADB. In any case, Pippin consoles only have two P-ADB ports (though rare Y-adapters exist).

  • In either fork, there's some AdbBus issues that make Adb address collisions not get handled correctly.

When this gets fixed then it should be straightforward to support more than one AppleJack controller at once, too. Multiple AppleJacks are distinguished by their ADB addresses.

  • The AdbMouse and AdbKeyboard devices are types that should only be added once, since they use system events. A different kind of mouse and keyboard needs to be added to support additional mice and keyboards - they maybe will use SDL's HID APIs to capture a device removing that device from the ones that send system events.

Hmm. Multiple ADB mice and keyboards of the same type can be added to a single Mac without issue, but yes they are normally not distinguished from each other by the OS. That is probably something handled at the OS level; are you saying it should also be taken into account by the ADB emulation? Just realized that by "system events" you mean host system events, not emulated system events. Then yes, support for multiple mice and keyboards will depend on the host supporting them likewise.

  • Do I understand correctly that this Pippin Controller is similar to the AdbMouse and AdbKeyboard devices, in that it uses global system events specific to game controllers in the same way that AdbMouse uses system events specific to mice, and AdbKeyboard uses system events specific to keyboards? In that case, a different type of Pippin controller needs to be created in order to add additional pippin controllers, using SDL's HID APIs to capture a device and removing that device from the ones that send global game controller events.

At its lowest level accessible to the programmer, the Pippin SDK defines an AJGlobalData struct that, among other things, exposes a bitmap of the instantaneous switch states of the controller. The idea is that, to get at the other 11 buttons, you leverage the Cursor Device Manager to get at the AppleJack driver's global data, defined to be an AJGlobalData struct. Call CountADBs, then GetIndADB for each enumerated device, then after casting the returned data block's refCon to AJGlobalData*, check if its signature is equal to 'pipp'. If it is, then it's an AppleJack and you can read switchStates directly. The only system events involved by the ROM's AppleJack driver are those used by the mouse, so I imagine that if DingusPPC were to support disambiguating between multiple AdbMouse addresses, then that support would likewise trickle down to AdbAppleJack by way of inheritance. :)

The trackball and two triggers are treated as a mouse device at all times. Indeed, if I connect two AppleJacks simultaneously and use them both to control the cursor, I observe the same behavior as when multiple mice are used likewise. No Pippin title I know of disambiguates between multiple trackballs, though I suppose it could be possible by calling ADBOp directly and ignoring the system's mouse events.

(Side note: the "AJ Control" INIT that ships with some titles provides an additional ADB driver that piggybacks on top of the ROM's AppleJack driver. This driver maps AppleJack button presses to emulated keypresses, using system events. But as this requires the base AppleJack support described above, DingusPPC itself should not have to care about it.) See above; just realized you mean host system events.

In main.cpp I just open the first game controller I find, providing just one source of game controller events. I define a gamepad_id in the GamepadEvent struct, which is currently unused, but whose use is designed to distinguish between controllers, since SDL's which field of its SDL_ControllerButtonEvent provides that info. SDL fortunately doesn't have a notion of global game controller events that I can tell.

  • If in either the mouse, or keyboard, or game controller event there is a way to distinguish events between different mice, keyboards, and game controllers, then that could be the method used to distinguish events between duplicate Adb devices.
  • Looks like SDL gamepads have an ID. You could open all gamepads for the system events version of the Pippin. Additional pippin controllers will remove gamepad IDs from the first pippin controller.

Yes, the SDL GameController API assigns each game controller its own ID. This patch only supports one gamepad, for a pretty important reason (IMO): DingusPPC won't run any of the multiplayer Pippin games yet, so I'd have no way to verify that multiple emulated controllers actually work. ;)

  • If SDL gamepads have names or serial numbers, then that may be a better way to assign them to AdbDevices. Different game controllers might be better at emulating different ADB devices. See issue Feature Request - Emulated Joysticks #24 .

One issue with the legacy SDL joystick API is that there's no standardization regarding what buttons/axes/hats/trackballs on a given controller map to in terms of software IDs. So while some older joysticks might provide a better analogue to classic ADB devices, configuring them would likely be a manual process for the user per joystick. This is why I chose to implement AppleJack support here in terms of the newer GameController API: the A/B/X/Y buttons are guaranteed to be in the same location from gamepad to gamepad, so I map them to their respective corresponding locations on the AppleJack controller. I verified this with both an Xbox 360 controller and a Logitech Dual Action controller. Neither required any manual mapping beyond what I'm doing in hostevents_sdl.cpp.

@joevt
Copy link
Contributor

joevt commented Oct 8, 2024

We'll be able to test multiple Pippin controllers using normal Power Mac emulation - same for any emulated ADB devices. There are apps for classic Mac OS to dump ADB packets.

I would like to research the HID support that SDL has to enumerate devices and buttons and axis and such. In macOS, USBProber.app can dump the HID report descriptors of a device. ControllerMate.app is an app that can visually view and script HID devices. It includes USBProber internally in the ControllerMate Profile.

@joevt joevt mentioned this pull request Nov 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants