// Keyboard, mouse, and joystick input polling. // // Call jlInputPoll() once per frame (typically right before // drawing) to refresh keyboard, mouse, and joystick state. After // polling, the joeyKey* predicates return the current state of every // key: // // jlKeyDown(k) -- is key k held down right now // jlKeyPressed(k) -- rising edge since the previous poll // jlKeyReleased(k) -- falling edge since the previous poll // // Typed-character input (text entry) is a separate path: // // jlInputGetChar() -- pop the next typed character, or -1 // // The key predicates are the right shape for games (is the fire key // held?); the character queue is the right shape for text fields // (which character did the user type, with shift and the machine's // keyboard layout already applied). Both are refreshed by the same // jlInputPoll() and coexist freely. // // The mouse predicates return the pointer state: // // jlMouseX/Y() -- pointer position in surface // coords (0..SURFACE_WIDTH-1, // 0..SURFACE_HEIGHT-1) // jlMouseDown(b) -- is button b held right now // jlMousePressed(b) -- rising edge since last poll // jlMouseReleased(b) -- falling edge since last poll // // The joystick predicates return per-stick state: // // jlJoystickConnected(js) -- true if the platform reports a // stick on this port // jlJoystickX/Y(js) -- axis values, signed -127..+127. // Digital sticks snap to the // extremes; analog sticks return // the raw centered value. // jlJoyDown(js, b) -- is button b held on stick js // jlJoyPressed(js, b) -- rising edge since last poll // jlJoyReleased(js, b) -- falling edge since last poll // // Edge predicates are one-shot: they return true only in the // frame the transition occurred and false thereafter. #ifndef JOEYLIB_INPUT_H #define JOEYLIB_INPUT_H #include "platform.h" #include "types.h" typedef enum { KEY_NONE = 0, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_SPACE, KEY_ESCAPE, KEY_RETURN, KEY_TAB, KEY_BACKSPACE, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_LSHIFT, KEY_RSHIFT, KEY_LCTRL, KEY_LALT, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_COUNT } jlKeyE; typedef enum { MOUSE_BUTTON_NONE = 0, MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_COUNT } jlMouseButtonE; typedef enum { JOYSTICK_0 = 0, JOYSTICK_1, JOYSTICK_COUNT } jlJoystickE; typedef enum { JOY_BUTTON_0 = 0, JOY_BUTTON_1, JOY_BUTTON_COUNT } jlJoyButtonE; #define JOYSTICK_AXIS_MAX 127 #define JOYSTICK_AXIS_MIN (-127) // Control characters delivered through jlInputGetChar alongside // printable ASCII. Everything else below 0x20, plus 0x7F, is // filtered out of the queue. #define JL_CHAR_BACKSPACE 0x08 #define JL_CHAR_TAB 0x09 #define JL_CHAR_RETURN 0x0D #define JL_CHAR_ESCAPE 0x1B // The FORWARD delete (the key labelled Del/Delete on a PC, ST or Amiga keyboard - not backspace). A text // editor needs both: backspace removes the character BEFORE the caret, this one removes the character // UNDER it. 0x7F is ASCII DEL, which is what every one of these keyboards already reports. #define JL_CHAR_DELETE 0x7F // Typed-character queue capacity (ring buffer; one slot stays empty, // so JL_CHAR_QUEUE_SIZE - 1 characters can be pending). Must be a // power of two. #define JL_CHAR_QUEUE_SIZE 32 void jlInputPoll(void); // Pop the next typed character as a 7-bit code, or -1 if the queue // is empty. Codes: printable ASCII 0x20..0x7E, plus JL_CHAR_BACKSPACE, // JL_CHAR_TAB, JL_CHAR_RETURN, JL_CHAR_ESCAPE, JL_CHAR_DELETE. Shift, caps lock, and // the keyboard layout are already applied by the backend, so // punctuation and shifted symbols arrive correctly on every port. // (The layout is the machine's own on IIgs/Amiga/ST/X68000; the DOS // port translates with a fixed US layout -- see docs/input.md.) // // The queue is refilled by jlInputPoll() -- no extra bring-up is // needed. It holds JL_CHAR_QUEUE_SIZE - 1 characters; when full, // further characters are dropped (drop-newest) until the app pops. // OS auto-repeat may deliver repeated characters on ports whose // keyboard services repeat (the caller manages repeat policy). // 7-bit ASCII only; no Unicode / IME. Arrow keys are not characters // and stay on the predicate API (jlKeyDown(KEY_UP) etc.). // jlWaitForAnyKey empties the queue when it returns -- its dismissing // keystroke is consumed by the wait, not delivered as text. // // Returns int (not a stdint type) deliberately: getchar()-style // "byte or -1" is the interface contract consumers expect. int jlInputGetChar(void); // Block until the user presses any key. Internally polls via // jlInputPoll, so per-port jlpInputPoll machinery (including // audio-friendly IRQ-driven samplers) keeps working while the // wait loop runs. void jlWaitForAnyKey(void); bool jlKeyDown(jlKeyE key); bool jlKeyPressed(jlKeyE key); bool jlKeyReleased(jlKeyE key); // True when the platform confirmed an attached mouse at init (DOS: the INT 33h driver reset; // Amiga/ST/IIgs/X68000: the OS mouse is always wired). bool jlMousePresent(void); int16_t jlMouseX(void); int16_t jlMouseY(void); bool jlMouseDown(jlMouseButtonE button); bool jlMousePressed(jlMouseButtonE button); bool jlMouseReleased(jlMouseButtonE button); bool jlJoystickConnected(jlJoystickE js); int8_t jlJoystickX(jlJoystickE js); int8_t jlJoystickY(jlJoystickE js); bool jlJoyDown(jlJoystickE js, jlJoyButtonE button); bool jlJoyPressed(jlJoystickE js, jlJoyButtonE button); bool jlJoyReleased(jlJoystickE js, jlJoyButtonE button); // Re-enable joystick polling and recalibrate the resting (center) // position. The IIgs port auto-disables polling after a short window // of detecting no stick (saves ~3 ms/frame of busy-wait). It does NOT // auto-re-probe -- the application must call this function to resume // polling after plugging a stick in. // // The next poll after this call captures the stick's CURRENT raw // position as the new center -- so the user must hold the stick // centered when calling. Subsequent polls report position relative // to that center; raw readings within `deadZone` units of the center // clamp to 0 (use 0 to disable the dead zone). // // On platforms with truly digital sticks (Amiga / ST / DOS) the // recalibration is a no-op -- those ports already report -1 / 0 / +1 // directly -- and `deadZone` is ignored. The function still clears // any auto-disconnect state so polling resumes. void jlJoystickReset(jlJoystickE js, uint8_t deadZone); #endif