331 lines
12 KiB
Text
331 lines
12 KiB
Text
== Input
|
|
|
|
Declared in `<joey/input.h>`.
|
|
|
|
Call `jlInputPoll()` exactly once per frame to refresh keyboard, mouse, and
|
|
joystick state. Everything else in this section reads the state that poll
|
|
captured.
|
|
|
|
Two parallel keyboard interfaces share that one poll. The *predicates* answer
|
|
"is the fire key held?", which is the right shape for games. The *character
|
|
queue* answers "which character did the user type?", with shift, caps lock, and
|
|
the machine's keyboard layout already applied, which is the right shape for
|
|
text entry. They coexist freely.
|
|
|
|
Edge predicates are one-shot: they return `true` only in the frame the
|
|
transition happened.
|
|
|
|
=== Enumerations
|
|
|
|
[source,c]
|
|
----
|
|
typedef enum {
|
|
JL_KEY_NONE = 0,
|
|
JL_KEY_A .. JL_KEY_Z,
|
|
JL_KEY_0 .. JL_KEY_9,
|
|
JL_KEY_SPACE, JL_KEY_ESCAPE, JL_KEY_RETURN, JL_KEY_TAB, JL_KEY_BACKSPACE,
|
|
JL_KEY_UP, JL_KEY_DOWN, JL_KEY_LEFT, JL_KEY_RIGHT,
|
|
JL_KEY_LSHIFT, JL_KEY_RSHIFT, JL_KEY_LCTRL, JL_KEY_LALT,
|
|
JL_KEY_F1 .. JL_KEY_F10,
|
|
JL_KEY_COUNT
|
|
} jlKeyE;
|
|
|
|
typedef enum {
|
|
JL_MOUSE_BUTTON_NONE = 0, JL_MOUSE_BUTTON_LEFT, JL_MOUSE_BUTTON_RIGHT,
|
|
JL_MOUSE_BUTTON_COUNT
|
|
} jlMouseButtonE;
|
|
|
|
typedef enum { JL_JOYSTICK_0 = 0, JL_JOYSTICK_1, JL_JOYSTICK_COUNT } jlJoystickE;
|
|
typedef enum { JL_JOY_BUTTON_0 = 0, JL_JOY_BUTTON_1, JL_JOY_BUTTON_COUNT } jlJoyButtonE;
|
|
----
|
|
|
|
Constants: `JL_JOYSTICK_AXIS_MAX` (127) and `JL_JOYSTICK_AXIS_MIN` (-127);
|
|
`JL_CHAR_QUEUE_SIZE` (32).
|
|
|
|
Control codes delivered through the character queue: `JL_CHAR_BACKSPACE`
|
|
(0x08), `JL_CHAR_TAB` (0x09), `JL_CHAR_RETURN` (0x0D), `JL_CHAR_ESCAPE` (0x1B),
|
|
and `JL_CHAR_DELETE` (0x7F). That last one is *forward* delete, the key marked
|
|
Del -- a text editor needs both it and backspace. The IIgs never delivers it:
|
|
its Delete key is the backspace key, and types `JL_CHAR_BACKSPACE`.
|
|
|
|
=== jlInputPoll
|
|
|
|
[source,c]
|
|
----
|
|
void jlInputPoll(void);
|
|
----
|
|
|
|
Refreshes all input state and refills the typed-character queue. Call once per
|
|
frame, typically just before drawing. A key pressed and let go between two
|
|
polls still reads down for one poll, so `jlKeyPressed` sees a quick tap
|
|
(except on DVX, which reads its keyboard only as it is at the poll).
|
|
|
|
*Parameters:* none. *Returns:* nothing.
|
|
|
|
[WARNING]
|
|
====
|
|
Exactly once per frame. Polling twice makes edge predicates miss transitions;
|
|
not polling means nothing ever changes.
|
|
====
|
|
|
|
=== jlInputGetChar
|
|
|
|
[source,c]
|
|
----
|
|
int jlInputGetChar(void);
|
|
----
|
|
|
|
Pops the next typed character. Shift, caps lock, and the keyboard layout have
|
|
already been applied by the backend, so punctuation and shifted symbols arrive
|
|
correctly. The layout is the machine's own on the IIgs, Amiga, ST, and
|
|
X68000. It is DVX's own on DVX, and the operating system's on SDL3, the web,
|
|
Win32, Win16, Haiku, and BeOS. DOS, and the PSP's on-screen keyboard, use a
|
|
fixed US layout. On the ST a key held with Alt types nothing, so the
|
|
characters a national TOS puts on Alt cannot be typed.
|
|
|
|
Arrow keys are not characters and stay on the predicate API.
|
|
|
|
*Parameters:* none.
|
|
|
|
*Returns:* a 7-bit code -- printable ASCII 0x20..0x7E, or one of the
|
|
`JL_CHAR_*` control codes -- or `-1` if the queue is empty.
|
|
|
|
[NOTE]
|
|
====
|
|
The queue holds `JL_CHAR_QUEUE_SIZE - 1` characters, so 31. When full, further
|
|
characters are dropped until you pop some. A chord types nothing on any port:
|
|
Ctrl+M is not Return and Ctrl+1 is not 1, and Alt chords type nothing where
|
|
Alt is a command key (DOS, DVX, Windows, the Be ports' Command key, the PSP's
|
|
on-screen keyboard); the Amiga's Alt and Windows' AltGr type their layout's
|
|
characters, and so does the ST's Alt, the characters its national
|
|
keyboard's Alt layer gives (a German keyboard's @ [ ] { } \;
|
|
<<portsDifferInput>>). A held key
|
|
repeats its character on every port (the ST at the rate TOS is set to);
|
|
repeat policy is yours to manage. 7-bit ASCII only -- no Unicode, no input
|
|
methods.
|
|
|
|
The return type is plain `int`, not a stdint type, deliberately: this is the
|
|
`getchar()`-style "byte or -1" contract.
|
|
====
|
|
|
|
=== jlWaitForAnyKey
|
|
|
|
[source,c]
|
|
----
|
|
void jlWaitForAnyKey(void);
|
|
----
|
|
|
|
Blocks until the user presses a key -- one JoeyLib names (with a `jlKeyE`),
|
|
or one that types a character, punctuation for instance -- polling internally
|
|
so per-port input machinery, including interrupt-driven audio samplers, keeps
|
|
running during the wait. The mouse and joystick buttons do not end it, and a
|
|
key already held when the wait starts must be let go and pressed again (its
|
|
auto-repeat does not count).
|
|
|
|
*Parameters:* none. *Returns:* nothing. The character queue is emptied on
|
|
return, so the dismissing keystroke is consumed rather than delivered as text.
|
|
|
|
=== jlKeyDown / jlKeyPressed / jlKeyReleased
|
|
|
|
[source,c]
|
|
----
|
|
bool jlKeyDown(jlKeyE key);
|
|
bool jlKeyPressed(jlKeyE key);
|
|
bool jlKeyReleased(jlKeyE key);
|
|
----
|
|
|
|
[cols="1,1,4", options="header"]
|
|
|===
|
|
|Parameter |Type |Description
|
|
|`key` |`jlKeyE` |Key to test.
|
|
|===
|
|
|
|
*Returns:* `jlKeyDown` is `true` while the key is held. `jlKeyPressed` is
|
|
`true` only in the frame the key went down; `jlKeyReleased` only in the frame
|
|
it came up.
|
|
|
|
A named key that two physical keys give is down while either is held, and
|
|
comes up with the last of them: `JL_KEY_RETURN` is Return and the keypad's
|
|
Enter; `JL_KEY_UP`, `JL_KEY_DOWN`, `JL_KEY_LEFT`, and `JL_KEY_RIGHT` are the
|
|
arrow keys and the keypad's 8, 2, 4, and 6; and `JL_KEY_LCTRL` and
|
|
`JL_KEY_LALT` are the left and right Ctrl and Alt, where the keyboard has
|
|
both (on the X68000, OPT.1 and OPT.2 are Alt). The keypad's keys still type
|
|
what the machine's keypad types (`jlInputGetChar`). The IIgs knows keys by
|
|
their characters, so its keypad reads as the digits
|
|
(<<portsDifferInput>>).
|
|
|
|
=== jlMousePresent
|
|
|
|
[source,c]
|
|
----
|
|
bool jlMousePresent(void);
|
|
----
|
|
|
|
*Parameters:* none.
|
|
|
|
*Returns:* `true` if the platform confirmed a mouse at init. On DOS that means
|
|
the INT 33h driver reset successfully; on the Amiga, that JoeyLib's input
|
|
window opened; on Win32 and Win16, that Windows reports a mouse; on SDL3 and
|
|
the web, that SDL reports one. The IIgs, ST, X68000, DVX, Haiku, BeOS, and
|
|
PSP always report one; the PSP's is its analog nub.
|
|
|
|
=== jlMouseX / jlMouseY
|
|
|
|
[source,c]
|
|
----
|
|
int16_t jlMouseX(void);
|
|
int16_t jlMouseY(void);
|
|
----
|
|
|
|
*Parameters:* none.
|
|
|
|
*Returns:* pointer position in surface coordinates, 0..319 and 0..199.
|
|
Until the platform reports the pointer, it is the middle of the stage,
|
|
(160, 100), on every port.
|
|
|
|
On DVX the position is the pointer's over the program's window, divided by
|
|
the window's scale; it keeps its last value while the pointer is elsewhere. On
|
|
DVX's full screen it is the pointer's place on the stage (DVX draws no pointer
|
|
there). On the hosted ports it is the pointer's place on the stage however the
|
|
window scales it, held to the stage's edge while the pointer is beside it; the
|
|
OS pointer is hidden over the window. On DOS the mouse driver keeps it in
|
|
range.
|
|
|
|
=== jlMouseDown / jlMousePressed / jlMouseReleased
|
|
|
|
[source,c]
|
|
----
|
|
bool jlMouseDown(jlMouseButtonE button);
|
|
bool jlMousePressed(jlMouseButtonE button);
|
|
bool jlMouseReleased(jlMouseButtonE button);
|
|
----
|
|
|
|
[cols="1,1,4", options="header"]
|
|
|===
|
|
|Parameter |Type |Description
|
|
|`button` |`jlMouseButtonE` |Which button.
|
|
|===
|
|
|
|
*Returns:* held state, rising edge, and falling edge respectively.
|
|
|
|
Every port has two buttons, `JL_MOUSE_BUTTON_LEFT` and `JL_MOUSE_BUTTON_RIGHT`,
|
|
whatever its mouse has. A left click made with Ctrl held is the right button,
|
|
on every port: it is down from the press until the button is let go, even if
|
|
Ctrl is let go first, and it is never the left button too (Ctrl pressed after
|
|
the button changes nothing). So a one-button mouse, the IIgs's or many a
|
|
Mac's, has both, and a program can tell its users "Ctrl-click" on any machine.
|
|
A middle button, where a mouse has one, is not reported. The PSP's buttons are
|
|
L (left) and R (right).
|
|
|
|
=== jlJoystickConnected
|
|
|
|
[source,c]
|
|
----
|
|
bool jlJoystickConnected(jlJoystickE js);
|
|
----
|
|
|
|
[cols="1,1,4", options="header"]
|
|
|===
|
|
|Parameter |Type |Description
|
|
|`js` |`jlJoystickE` |Which stick, `JL_JOYSTICK_0` or `JL_JOYSTICK_1`.
|
|
|===
|
|
|
|
*Returns:* `true` if the platform reports a stick on that port. On the ST and
|
|
X68000 both ports always report one: an empty port cannot be told from a stick
|
|
at rest. The Amiga (`lowlevel.library`) has the same blind spot the other
|
|
way: it reports a stick only once it has moved, and never a mouse. The IIgs
|
|
has one stick, `JL_JOYSTICK_0`, and stops looking for it after about a second
|
|
with none seen, until `jlJoystickReset`. On DOS a stick is connected while the
|
|
game port times both its axes. SDL3, the web, and the PSP see SDL's gamepads
|
|
and joysticks both, a joystick SDL has no gamepad mapping for read by its first
|
|
two axes, its first hat, and its first two buttons; Win32, Win16, Haiku, and
|
|
BeOS see the system's joysticks, and Haiku and BeOS notice a new one within a
|
|
second.
|
|
|
|
=== jlJoystickX / jlJoystickY
|
|
|
|
[source,c]
|
|
----
|
|
int8_t jlJoystickX(jlJoystickE js);
|
|
int8_t jlJoystickY(jlJoystickE js);
|
|
----
|
|
|
|
[cols="1,1,4", options="header"]
|
|
|===
|
|
|Parameter |Type |Description
|
|
|`js` |`jlJoystickE` |Which stick.
|
|
|===
|
|
|
|
*Returns:* axis value, -127 to +127. Digital sticks (the Amiga, ST, and
|
|
X68000) snap to the extremes; analog sticks (the IIgs, DOS, DVX, and the
|
|
hosted ports) return their offset from the center, scaled to that range, with
|
|
the dead zone applied. On the IIgs and DOS the axes read 0 until the stick's
|
|
center has been read (<<_jljoystickreset>>). Test against a threshold rather
|
|
than for exact values, so the same code works with both.
|
|
|
|
=== jlJoyDown / jlJoyPressed / jlJoyReleased
|
|
|
|
[source,c]
|
|
----
|
|
bool jlJoyDown(jlJoystickE js, jlJoyButtonE button);
|
|
bool jlJoyPressed(jlJoystickE js, jlJoyButtonE button);
|
|
bool jlJoyReleased(jlJoystickE js, jlJoyButtonE button);
|
|
----
|
|
|
|
[cols="1,1,4", options="header"]
|
|
|===
|
|
|Parameter |Type |Description
|
|
|`js` |`jlJoystickE` |Which stick.
|
|
|`button` |`jlJoyButtonE` |Which button.
|
|
|===
|
|
|
|
*Returns:* held state, rising edge, and falling edge respectively.
|
|
|
|
Every stick has two buttons. On the ST and STe's own joystick ports, and on
|
|
the Amiga until a stick's second button is first pressed, a stick is taken to
|
|
have one: a quick press of it is `JL_JOY_BUTTON_0`, down for the one poll after
|
|
it is let go, and a press held for half a second is `JL_JOY_BUTTON_1`, down
|
|
from then until it is let go. So act on button 0 with `jlJoyPressed`, and do
|
|
not count on it staying down while the button is held. Elsewhere the two
|
|
buttons are the stick's own, and a one-button stick never reports
|
|
`JL_JOY_BUTTON_1`.
|
|
|
|
=== jlJoystickReset
|
|
|
|
[source,c]
|
|
----
|
|
void jlJoystickReset(jlJoystickE js, uint8_t deadZone);
|
|
----
|
|
|
|
Sets the stick's dead zone and, where the port can, re-centers it and looks
|
|
for it again:
|
|
|
|
* *IIgs*: polling starts again if it had stopped for want of a stick, and the
|
|
stick is re-centered at its next reading.
|
|
* *DOS*: the game port is probed again, and the stick is re-centered at its
|
|
next reading.
|
|
* *Amiga*: the port goes back to `lowlevel.library`'s own detection.
|
|
* *Elsewhere* only the dead zone changes.
|
|
|
|
On the IIgs polling for a stick that is not there stops. If a user may plug a
|
|
stick in while your program runs, call this, with the stick centered, to pick
|
|
it up.
|
|
|
|
[cols="1,1,4", options="header"]
|
|
|===
|
|
|Parameter |Type |Description
|
|
|`js` |`jlJoystickE` |Which stick.
|
|
|`deadZone` |`uint8_t` |Axis values within this many units of 0 (on the
|
|
-127..127 scale) read 0, on the ports with analog sticks: the IIgs, DOS, DVX,
|
|
and the hosted ports. Each stick starts with 8, so a stick left alone reads 0
|
|
though its pots jitter. Pass 0 to disable the dead zone.
|
|
|===
|
|
|
|
*Returns:* nothing.
|
|
|
|
[IMPORTANT]
|
|
====
|
|
On the IIgs and DOS the next reading after this call is taken as the stick's
|
|
center, so the user must be holding the stick centered when you call it. The
|
|
call is safe to make unconditionally.
|
|
====
|