Files
sml-projects/shell/glfw-gamepad.sml

265 lines
7.2 KiB
Standard ML

structure GlfwGamepad =
struct
datatype mode =
PENDING
(* we need to wait for all keys to be released after pressing a button *)
| WAIT_FOR_KEY_RELEASE
| TRIANGLE
| TRIANGLE_CIRCLE
| CIRCLE
| CIRCLE_CROSS
| CROSS
| CROSS_SQUARE
| SQUARE
(* maybe SQUARE_TRIANGLE for numbers and symbols? *)
| SQUARE_TRIANGLE
structure IM = InputMsg
type gamepad_state =
{ mode: mode
, shiftChr: bool
, trianglePressed: bool
, circlePressed: bool
, crossPressed: bool
, squarePressed: bool
}
fun releaseKeysAndUnshift (gamepadState: gamepad_state) =
let
val
{ mode = _
, shiftChr = _
, trianglePressed
, circlePressed
, crossPressed
, squarePressed
} = gamepadState
in
{ mode = WAIT_FOR_KEY_RELEASE
, shiftChr = false
, trianglePressed = false
, circlePressed = false
, crossPressed = false
, squarePressed = false
}
end
fun onWaitForKeyRelease
( gamepadState: gamepad_state
, trianglePressed
, circlePressed
, crossPressed
, squarePressed
, actions
) =
if
trianglePressed orelse circlePressed orelse crossPressed
orelse squarePressed
then
(gamepadState, actions)
else
let
val newState =
{ mode = PENDING
, shiftChr = #shiftChr gamepadState
, trianglePressed = false
, circlePressed = false
, crossPressed = false
, squarePressed = false
}
in
(newState, actions)
end
fun onPendingMode
( state: gamepad_state
, trianglePressed
, circlePressed
, crossPressed
, squarePressed
, actions: IM.t list
) =
if
trianglePressed orelse circlePressed orelse crossPressed
orelse squarePressed
then
(* some button is being pressed,
* so we record that in the returned state,
* in addition to whatever buttons were previously pressed *)
let
val trianglePressed = #trianglePressed state orelse trianglePressed
val circlePressed = #circlePressed state orelse circlePressed
val crossPressed = #crossPressed state orelse crossPressed
val squarePressed = #squarePressed state orelse squarePressed
val newState =
{ mode = #mode state
, shiftChr = #shiftChr state
, trianglePressed = trianglePressed
, circlePressed = circlePressed
, crossPressed = crossPressed
, squarePressed = squarePressed
}
in
(newState, actions)
end
else
(* nothing is currently pressed,
* so we check if there is a valid mode indicated by the state
* and change the mode if so *)
let
val
{ trianglePressed
, circlePressed
, crossPressed
, squarePressed
, shiftChr
, mode = _
} = state
val newMode =
if trianglePressed andalso not (crossPressed orelse squarePressed) then
if not circlePressed then TRIANGLE else TRIANGLE_CIRCLE
else if circlePressed andalso not squarePressed then
if not crossPressed then CIRCLE else CIRCLE_CROSS
else if crossPressed then
if not squarePressed then CROSS else CROSS_SQUARE
else if squarePressed then
if not trianglePressed then SQUARE else SQUARE_TRIANGLE
else
(* some buttons are being pressed,
* but not a valid combination to switch
* to another mode, so we are still on PENDING *)
PENDING
val newState =
{ mode = newMode
, shiftChr = shiftChr
, trianglePressed = false
, circlePressed = false
, crossPressed = false
, squarePressed = false
}
in
(newState, actions)
end
fun onTriangleMode
( gamepadState
, trianglePressed
, circlePressed
, crossPressed
, squarePressed
, actions
) =
if trianglePressed then
let
val newState = releaseKeysAndUnshift gamepadState
val actions = IM.CHAR_EVENT #"a" :: actions
in
(newState, actions)
end
else if circlePressed then
let
val newState = releaseKeysAndUnshift gamepadState
val actions = IM.CHAR_EVENT #"b" :: actions
in
(newState, actions)
end
else if crossPressed then
let
val newState = releaseKeysAndUnshift gamepadState
val actions = IM.CHAR_EVENT #"c" :: actions
in
(newState, actions)
end
else if squarePressed then
let
val newState = releaseKeysAndUnshift gamepadState
val actions = IM.CHAR_EVENT #"d" :: actions
in
(newState, actions)
end
else
(gamepadState, actions)
fun handleButtons
( gamepadState
, trianglePressed
, circlePressed
, crossPressed
, squarePressed
, l1Pressed
, r1Pressed
) =
let
val actions = if l1Pressed then [IM.KEY_BACKSPACE] else []
val actions =
if r1Pressed then (IM.CHAR_EVENT #" ") :: actions else actions
in
case #mode gamepadState of
PENDING =>
onPendingMode
( gamepadState
, trianglePressed
, circlePressed
, crossPressed
, squarePressed
, actions
)
| WAIT_FOR_KEY_RELEASE =>
onWaitForKeyRelease
( gamepadState
, trianglePressed
, circlePressed
, crossPressed
, squarePressed
, actions
)
| TRIANGLE =>
onTriangleMode
( gamepadState
, trianglePressed
, circlePressed
, crossPressed
, squarePressed
, actions
)
end
(* impure functions below *)
fun getGamepadState () =
Input.getGamepadState 0 <> 0 orelse Input.getGamepadState 1 <> 0
orelse Input.getGamepadState 2 <> 0 orelse Input.getGamepadState 3 <> 0
orelse Input.getGamepadState 4 <> 0 orelse Input.getGamepadState 5 <> 0
orelse Input.getGamepadState 6 <> 0 orelse Input.getGamepadState 7 <> 0
orelse Input.getGamepadState 8 <> 0 orelse Input.getGamepadState 9 <> 0
orelse Input.getGamepadState 10 <> 0 orelse Input.getGamepadState 11 <> 0
orelse Input.getGamepadState 12 <> 0 orelse Input.getGamepadState 13 <> 0
orelse Input.getGamepadState 14 <> 0 orelse Input.getGamepadState 15 <> 0
fun query gamepadState =
if getGamepadState () then
let
val trianglePressed = Input.isTriangleButtonPressed () <> 0
val circlePressed = Input.isCircleButtonPressed () <> 0
val crossPressed = Input.isCrossButtonPressed () <> 0
val squarePressed = Input.isSquareButtonPressed () <> 0
val l1Pressed = Input.isL1ButtonPressed () <> 0
val r1Pressed = Input.isR1ButtonPressed () <> 0
in
handleButtons
( gamepadState
, trianglePressed
, circlePressed
, crossPressed
, squarePressed
, l1Pressed
, r1Pressed
)
end
else
(* nothing to do, so return same state *)
(gamepadState, [])
end