From e2737161c31c920a6ef3daff339f5961563acf51 Mon Sep 17 00:00:00 2001 From: JetSetIlly Date: Thu, 30 Sep 2021 15:50:10 +0100 Subject: [PATCH] added right player joystick using default Stella keys: Up Y Down H Left G Right J Fire F --- README.md | 70 ++++++++++++++++----- gui/requests.go | 1 - gui/sdlimgui/service.go | 3 +- hardware/riot/ports/plugging/plugging.go | 1 + hardware/riot/ports/ports.go | 17 ++++- userinput/controllers.go | 80 ++++++++++++++++++++---- userinput/userinput.go | 5 ++ 7 files changed, 147 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 01a3b5ff2..5012c9e1c 100644 --- a/README.md +++ b/README.md @@ -208,20 +208,60 @@ Although if want to pass flags to the run mode you'll need to specify it. ## Hand Controllers -Stick, paddle and keypad inputs are supported. Currently, only stick and -paddles for the left player are available but keypad input is available for -both players. +Stick, paddle and keypad inputs are supported. ### Stick -The stick is the most common control method for `Atari 2600` games. The stick -can be operated with the DPad or left thumbstick of a [gamepad](#gamepad) or by -the cursor keys on your computer's keyboard. Fire button is the keyboards space -bar or any of the gamepad's face buttons. +The stick is the most common control method for `Atari 2600` games. The +left-side player is controlled with the following keys. + + + + + + + + + + + + + +
Left-Side Player
Cursor KeysStick Direction
SpaceFire Button
+ +The right-side player is controlled with the following keys. + + + + + + + + + + + + + + + + + + + + + + + + + +
Right-Side Player
GLeft
JRight
YUp
HDown
FFire Button
+ +The stick for the left-side player can also be controlled with a [gamepad](#gamepad). ### Paddle -The paddle can be controlled with the mouse or [gamepad](#gamepad). +The paddle for the left-side player can be controlled with the mouse or a [gamepad](#gamepad). In the case of the mouse, the mouse must be [captured](#mouse-capture). @@ -230,7 +270,9 @@ however and which device is used depends on the game. For some games, the triggers will suffice but other games will perform better when using the mouse. `Nightdriver` is an example of a game that plays well with the triggers, -whereas `Circus Tricks` is better played with the mouse. +whereas experience says that `Circus Tricks` is better played with the mouse. + +The paddle for the right-side player is not currently supported. ### Keypad @@ -238,9 +280,9 @@ Keypad input for both players is supported. - + - + @@ -294,9 +336,9 @@ need. ### Gamepad -For convenience the joystick and paddle can be controlled through a gamepad. -For the joystick, use the left thumbstick or the DPad. Any of the face buttons -will act as the joystick's fire button. +For convenience the joystick and paddle for the left-side player can be +controlled through a gamepad. For the joystick, use the left thumbstick or the +DPad. Any of the face buttons will act as the joystick's fire button. To control the paddle use the left and right analogue triggers. Note that you will need to 'waggle' the triggers a couple of times for the emulator to detect diff --git a/gui/requests.go b/gui/requests.go index 50440f277..3b9d7497a 100644 --- a/gui/requests.go +++ b/gui/requests.go @@ -66,6 +66,5 @@ const ( // of the controller. ReqControllerChange FeatureReq = "ReqControllerChange" // plugging.PortID, plugging.PeripheralID - ReqCartridgeEvent FeatureReq = "ReqCartridgeEvent" // mapper.Event ) diff --git a/gui/sdlimgui/service.go b/gui/sdlimgui/service.go index ee265c5ad..79fa89ce0 100644 --- a/gui/sdlimgui/service.go +++ b/gui/sdlimgui/service.go @@ -344,8 +344,7 @@ func (img *SdlImgui) serviceKeyboard(ev *sdl.KeyboardEvent) { } } - // forward keypresses to userinput.Event channel if in playmore or gui is - // in captured state + // forward keypresses to userinput.Event channel if img.isPlaymode() || img.isCaptured() { mod := userinput.KeyModNone diff --git a/hardware/riot/ports/plugging/plugging.go b/hardware/riot/ports/plugging/plugging.go index 7aed703c4..0d6e8b53c 100644 --- a/hardware/riot/ports/plugging/plugging.go +++ b/hardware/riot/ports/plugging/plugging.go @@ -35,6 +35,7 @@ type PeripheralID string // List of valid PeripheralID values. const ( + PeriphNone PeripheralID = "None" PeriphPanel PeripheralID = "Panel" PeriphStick PeripheralID = "Stick" PeriphPaddle PeripheralID = "Paddle" diff --git a/hardware/riot/ports/ports.go b/hardware/riot/ports/ports.go index 0975aac44..19c3c18db 100644 --- a/hardware/riot/ports/ports.go +++ b/hardware/riot/ports/ports.go @@ -306,8 +306,7 @@ func (p *Ports) GetPlayback() error { return nil } -// HandleEvent forwards the Event and EventData to the device connected to the -// specified PortID. +// HandleEvent implements userinput.HandleInput interface. func (p *Ports) HandleEvent(id plugging.PortID, ev Event, d EventData) error { var err error @@ -333,6 +332,20 @@ func (p *Ports) HandleEvent(id plugging.PortID, ev Event, d EventData) error { return nil } +// PeripheralID implements userinput.HandleInput interface. +func (p *Ports) PeripheralID(id plugging.PortID) plugging.PeripheralID { + switch id { + case plugging.PortPanel: + return p.Panel.ID() + case plugging.PortLeftPlayer: + return p.LeftPlayer.ID() + case plugging.PortRightPlayer: + return p.RightPlayer.ID() + } + + return plugging.PeriphNone +} + // WriteSWCHx implements the MemoryAccess interface. func (p *Ports) WriteSWCHx(id plugging.PortID, data uint8) { switch id { diff --git a/userinput/controllers.go b/userinput/controllers.go index 2e2475985..933b120d6 100644 --- a/userinput/controllers.go +++ b/userinput/controllers.go @@ -70,7 +70,7 @@ func (c *Controllers) keyboard(ev EventKeyboard, handle HandleInput) error { case "F5": err = handle.HandleEvent(plugging.PortPanel, ports.PanelTogglePlayer1Pro, nil) - // joystick + // joystick (left player) case "Left": err = handle.HandleEvent(plugging.PortLeftPlayer, ports.Left, ports.DataStickTrue) case "Right": @@ -82,6 +82,11 @@ func (c *Controllers) keyboard(ev EventKeyboard, handle HandleInput) error { case "Space": err = handle.HandleEvent(plugging.PortLeftPlayer, ports.Fire, true) + // joystick (right player) + // * keypad and joystick share some keys (see below for other inputs) + case "J": + err = handle.HandleEvent(plugging.PortRightPlayer, ports.Right, ports.DataStickTrue) + // keypad (left player) case "1", "2", "3": err = handle.HandleEvent(plugging.PortLeftPlayer, ports.KeypadDown, rune(ev.Key[0])) @@ -105,6 +110,7 @@ func (c *Controllers) keyboard(ev EventKeyboard, handle HandleInput) error { err = handle.HandleEvent(plugging.PortLeftPlayer, ports.KeypadDown, '#') // keypad (right player) + // * keypad and joystick share some keys (see below for other inputs) case "4": err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '1') case "5": @@ -115,20 +121,39 @@ func (c *Controllers) keyboard(ev EventKeyboard, handle HandleInput) error { err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '4') case "T": err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '5') - case "Y": - err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '6') - case "F": - err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '7') - case "G": - err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '8') - case "H": - err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '9') case "V": err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '*') case "B": err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '0') case "N": err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '#') + + // keypad (right player) *OR* joystick (right player) + // * keypad and joystick share some keys (see above for other inputs) + case "Y": + if handle.PeripheralID(plugging.PortRightPlayer) == plugging.PeriphKeypad { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '6') + } else { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.Up, ports.DataStickTrue) + } + case "F": + if handle.PeripheralID(plugging.PortRightPlayer) == plugging.PeriphKeypad { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '7') + } else { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.Fire, true) + } + case "G": + if handle.PeripheralID(plugging.PortRightPlayer) == plugging.PeriphKeypad { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '8') + } else { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.Left, ports.DataStickTrue) + } + case "H": + if handle.PeripheralID(plugging.PortRightPlayer) == plugging.PeriphKeypad { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadDown, '9') + } else { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.Down, ports.DataStickTrue) + } } } else { switch ev.Key { @@ -138,7 +163,7 @@ func (c *Controllers) keyboard(ev EventKeyboard, handle HandleInput) error { case "F2": err = handle.HandleEvent(plugging.PortPanel, ports.PanelReset, false) - // josytick + // josytick (left player) case "Left": err = handle.HandleEvent(plugging.PortLeftPlayer, ports.Left, ports.DataStickFalse) case "Right": @@ -150,13 +175,46 @@ func (c *Controllers) keyboard(ev EventKeyboard, handle HandleInput) error { case "Space": err = handle.HandleEvent(plugging.PortLeftPlayer, ports.Fire, false) + // joystick (right player) + // * keypad and joystick share some keys (see below for other inputs) + case "J": + err = handle.HandleEvent(plugging.PortRightPlayer, ports.Right, ports.DataStickFalse) + // keyboard (left player) case "1", "2", "3", "Q", "W", "E", "A", "S", "D", "Z", "X", "C": err = handle.HandleEvent(plugging.PortLeftPlayer, ports.KeypadUp, nil) // keyboard (right player) - case "4", "5", "6", "R", "T", "Y", "F", "G", "H", "V", "B", "N": + // * keypad and joystick share some keys (see below for other inputs) + case "4", "5", "6", "R", "T", "V", "B", "N": err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadUp, nil) + + // keypad (right player) *OR* joystick (right player) + // * keypad and joystick share some keys (see above for other inputs) + case "Y": + if handle.PeripheralID(plugging.PortRightPlayer) == plugging.PeriphKeypad { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadUp, nil) + } else { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.Up, ports.DataStickFalse) + } + case "F": + if handle.PeripheralID(plugging.PortRightPlayer) == plugging.PeriphKeypad { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadUp, nil) + } else { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.Fire, false) + } + case "G": + if handle.PeripheralID(plugging.PortRightPlayer) == plugging.PeriphKeypad { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadUp, nil) + } else { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.Left, ports.DataStickFalse) + } + case "H": + if handle.PeripheralID(plugging.PortRightPlayer) == plugging.PeriphKeypad { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.KeypadUp, nil) + } else { + err = handle.HandleEvent(plugging.PortRightPlayer, ports.Down, ports.DataStickFalse) + } } } diff --git a/userinput/userinput.go b/userinput/userinput.go index 91388555d..647cd7793 100644 --- a/userinput/userinput.go +++ b/userinput/userinput.go @@ -22,5 +22,10 @@ import ( // HandleInput conceptualises data being sent to the console ports. type HandleInput interface { + // HandleEvent forwards the Event and EventData to the device connected to the + // specified PortID. HandleEvent(id plugging.PortID, ev ports.Event, d ports.EventData) error + + // PeripheralID identifies the device currently attached to the port. + PeripheralID(id plugging.PortID) plugging.PeripheralID }
Left Hand PlayerLeft-Side Player Right Hand PlayerRight-Side Player
1