Friday, February 14, 2014

Devices API design

Revision 1 API

the preceding API for gamepads on rev1 was very simple : in fact it was only a halfword (!), representing the bits of each button on the SNES gamepad. This was simple, convenient and closest to the hardware.

Now with the different class of devices that can be used and the fact the USB HID is used, I think we will need to have a different API.


rev2 API goals


My main design goals for this API are : keep it simple and just act as a layer between the devices and the software (no policy, that's what engines are for), but still provide something for the simpler games.

The first thing to decide, by device, is what needs to be handled as an event queue (i.e. an array of ints - we will keep it simple) or as state variables.
It is trivial to transform a state API to an event like API, but it is dumb to transform a natively event hardware model to a state API back to an event-based game. So It'll be useful to state what is practically used in games, noting that maybe event to status is simpler than the other transformation.

Device classes

The first three classes of devices I'd like to be able to handle are gamepads, mice and keyboards.

Keyboards

 I think the best representation is events (having a 256bit table of the press of each key is somewhat not useful). Actually, the USB Boot protocol for keyboards is made of an event : control keys status (8 bits for left/right control, alt, windows ..) + up to 6 1byte keycodes buffer. I think we can keep as close to it as possible, while separating the different keystrokes as independent events. Translating with kb maps (including ctrl/alt modifiers), handling stroke repeat, making some keypresses have more priority than others (Ctrl-C) shall be done outside of this event handling API.

Mice

 there are buttons and cursor.
  - buttons are somewhat like events (press/releases), however sometimes button status can be useful. I think event-based might win here. Handling dbl clicks or right/left handed shall be outside the scope of this API.

  - mouse moves shall also be seen as events but 99% of the time what is needed is absolute x/y positioning, so it's not as clear-cut.
However, translating relative x/y move events to absolute x/y has a lot of policy : shall there be clipping (restricting the mouse movement), mouse speed can be adjusted, some acceleration can be needed. I think mousemove/clicks events are closest to the reality + simple x/y keeping as cut n paste examples. only 3 buttons need to be handled - wheel will need to move away from boot protocol, we won't do that now.

Gamepads and joysticks


Button press are fundamentally events, because even if by example you want to have autofire, you want the first fire to happen exactly as the button is first pressed. For simplicity, sometimes only state is kept, so that can be useful as well. Gamepads can be very various but we need to keep the standard ones simple to use. I propose to stick (haha) to a known set of buttons, mapped by default. the name of the buttons can be snes ones (AB XY LR start select)

I think dpad, hats & joysticks are different than mice as the pad status is much more useful than pad changes (except when you see one press to the right as one movement, but it is less frequent). For the directional pad/stick, I propose to only handle one per gamepad now, represented by X/Y position of +/-127 for d pads or hats, or int8 for analog sticks. if both are actioned, the last moved one wins.
other : device plugged/unplugged can be other events.

Proposal


the proposal is to have an array of 2 struct values (one per USB port):
{
 - uint16 device type (none, mice, keyboard, gamepad ...).
 - buttons : mice or joystick buttons current status
 - int16 x/y : either absolute mice or current joypad position
}
+ one global event queue circular buffer edit FIFO ! (duh) with event_type : uint8  + 3 bytes data (32 bits total)

Extensions

since we have an event queue , other events can be provided by extra libraries :

- timers (why not? as a library)
- SD card async IO ready, sd card inserted, removed
- user button pressed/released
- user events for event-based programming
- sprite collisions
- UEXT related events

What do you think of this ?

No comments:

Post a Comment