279 lines
No EOL
6.9 KiB
C
279 lines
No EOL
6.9 KiB
C
/*
|
|
|
|
Main input juice:
|
|
|
|
bool is_key_down(Input_Key_Code code)
|
|
bool is_key_up(Input_Key_Code code)
|
|
bool is_key_just_pressed(Input_Key_Code code)
|
|
bool is_key_just_released(Input_Key_Code code)
|
|
|
|
bool consume_key_down(Input_Key_Code code)
|
|
bool consume_key_just_pressed(Input_Key_Code code)
|
|
bool consume_key_just_released(Input_Key_Code code)
|
|
|
|
To loop through events this frame:
|
|
|
|
for (u64 i = 0; i < input_frame.number_of_events; i++) {
|
|
Input_Event e = input_frame.events[i];
|
|
|
|
switch (e.kind) {
|
|
case INPUT_EVENT_KEY: ...; break;
|
|
case INPUT_EVENT_SCROLL: ...; break;
|
|
case INPUT_EVENT_TEXT: ...; break;
|
|
case INPUT_EVENT_GAMEPAD_AXIS: ...; break;
|
|
}
|
|
}
|
|
|
|
Gamepad input:
|
|
|
|
Vector2 input_frame.left_stick
|
|
Vector2 input_frame.right_stick
|
|
float32 input_frame.left_trigger
|
|
float32 input_frame.right_trigger
|
|
|
|
Gamepad buttons are treated as regular keys.
|
|
|
|
Example:
|
|
|
|
is_key_just_pressed(GAMEPAD_A);
|
|
is_key_down(GAMEPAD_DPAD_LEFT);
|
|
|
|
To handle multiple gamepads, you need to poll input events and use the event.gamepad_index.
|
|
|
|
For gamepad buttons: INPUT_EVENT_KEY
|
|
For gamepad axes: INPUT_EVENT_GAMEPAD_AXIS
|
|
|
|
Set axis deadzones with global variables:
|
|
Vector2 deadzone_left_stick
|
|
Vector2 deadzone_right_stick
|
|
float32 deadzone_left_trigger
|
|
float32 deadzone_right_trigger
|
|
|
|
Set vibration with:
|
|
set_gamepad_vibration(float32 left, float32 right)
|
|
set_specific_gamepad_vibration(int gamepad_index, float32 left, float32 right)
|
|
|
|
see input_example.c for example code in practice
|
|
*/
|
|
|
|
// #Global
|
|
forward_global const u64 MAX_NUMBER_OF_GAMEPADS; // Defined in os layer
|
|
|
|
typedef enum Input_Event_Kind {
|
|
INPUT_EVENT_KEY,
|
|
INPUT_EVENT_SCROLL,
|
|
INPUT_EVENT_TEXT,
|
|
INPUT_EVENT_GAMEPAD_AXIS,
|
|
} Input_Event_Kind;
|
|
|
|
typedef enum Input_Key_Code {
|
|
KEY_UNKNOWN = 0,
|
|
|
|
// Non-textual keys that have placements in the ASCII table
|
|
// (and thus in Unicode):
|
|
|
|
KEY_BACKSPACE = 8,
|
|
KEY_TAB = 9,
|
|
KEY_ENTER = 13,
|
|
KEY_ESCAPE = 27,
|
|
KEY_SPACEBAR = 32,
|
|
|
|
// The letters A-Z live in here as well and may be returned
|
|
// by keyboard events.
|
|
|
|
KEY_DELETE = 127,
|
|
|
|
KEY_ARROW_UP = 128,
|
|
KEY_ARROW_DOWN = 129,
|
|
KEY_ARROW_LEFT = 130,
|
|
KEY_ARROW_RIGHT = 131,
|
|
|
|
KEY_PAGE_UP = 132,
|
|
KEY_PAGE_DOWN = 133,
|
|
|
|
KEY_HOME = 134,
|
|
KEY_END = 135,
|
|
|
|
KEY_INSERT = 136,
|
|
|
|
KEY_PAUSE = 137,
|
|
KEY_SCROLL_LOCK = 138,
|
|
|
|
KEY_ALT,
|
|
KEY_CTRL,
|
|
KEY_SHIFT,
|
|
KEY_CMD,
|
|
KEY_META = KEY_CMD,
|
|
|
|
KEY_F1,
|
|
KEY_F2,
|
|
KEY_F3,
|
|
KEY_F4,
|
|
KEY_F5,
|
|
KEY_F6,
|
|
KEY_F7,
|
|
KEY_F8,
|
|
KEY_F9,
|
|
KEY_F10,
|
|
KEY_F11,
|
|
KEY_F12,
|
|
|
|
KEY_PRINT_SCREEN,
|
|
|
|
GAMEPAD_DPAD_UP,
|
|
GAMEPAD_DPAD_RIGHT,
|
|
GAMEPAD_DPAD_DOWN,
|
|
GAMEPAD_DPAD_LEFT,
|
|
|
|
GAMEPAD_A,
|
|
GAMEPAD_X,
|
|
GAMEPAD_Y,
|
|
GAMEPAD_B,
|
|
|
|
GAMEPAD_START,
|
|
GAMEPAD_BACK,
|
|
|
|
GAMEPAD_LEFT_STICK,
|
|
GAMEPAD_RIGHT_STICK,
|
|
|
|
GAMEPAD_LEFT_BUMPER,
|
|
GAMEPAD_RIGHT_BUMPER,
|
|
GAMEPAD_LEFT_TRIGGER,
|
|
GAMEPAD_RIGHT_TRIGGER,
|
|
|
|
MOUSE_BUTTON_LEFT,
|
|
MOUSE_BUTTON_MIDDLE,
|
|
MOUSE_BUTTON_RIGHT,
|
|
|
|
GAMEPAD_FIRST = GAMEPAD_START,
|
|
GAMEPAD_LAST = GAMEPAD_RIGHT_TRIGGER,
|
|
|
|
MOUSE_FIRST = MOUSE_BUTTON_LEFT,
|
|
MOUSE_LAST = MOUSE_BUTTON_RIGHT,
|
|
|
|
INPUT_KEY_CODE_COUNT
|
|
} Input_Key_Code;
|
|
|
|
typedef enum Input_State_Flags {
|
|
INPUT_STATE_DOWN = 1<<0,
|
|
INPUT_STATE_JUST_PRESSED = 1<<1,
|
|
INPUT_STATE_JUST_RELEASED = 1<<2,
|
|
INPUT_STATE_REPEAT = 1<<3,
|
|
} Input_State_Flags;
|
|
|
|
typedef enum Input_Axis_Flags {
|
|
INPUT_AXIS_LEFT_STICK = 1<<0,
|
|
INPUT_AXIS_RIGHT_STICK = 1<<1,
|
|
INPUT_AXIS_LEFT_TRIGGER = 1<<2,
|
|
INPUT_AXIS_RIGHT_TRIGGER = 1<<3,
|
|
} Input_Axis_Flags;
|
|
|
|
typedef struct Input_Event {
|
|
Input_Event_Kind kind;
|
|
|
|
// For INPUT_EVENT_KEY
|
|
Input_Key_Code key_code;
|
|
Input_State_Flags key_state;
|
|
// Also for INPUT_EVENT_GAMEPAD_AXIS
|
|
s64 gamepad_index; // -1 if key is not from a gamepad
|
|
|
|
// For INPUT_EVENT_SCROLL
|
|
float64 xscroll;
|
|
float64 yscroll;
|
|
|
|
// For INPUT_EVENT_TEXT_INPUT
|
|
union { u32 utf32; char ascii; };
|
|
|
|
// For INPUT_EVENT_GAMEPAD_AXIS
|
|
// Only the changed axes have valid values
|
|
Input_Axis_Flags axes_changed;
|
|
Vector2 left_stick;
|
|
Vector2 right_stick;
|
|
float32 left_trigger;
|
|
float32 right_trigger;
|
|
|
|
} Input_Event;
|
|
|
|
Input_Key_Code os_key_to_key_code(void* os_key);
|
|
void* key_code_to_os_key(Input_Key_Code key_code);
|
|
|
|
#define MAX_EVENTS_PER_FRAME 10000
|
|
typedef struct Input_Frame {
|
|
Input_Event events[MAX_EVENTS_PER_FRAME];
|
|
u64 number_of_events;
|
|
|
|
float32 mouse_x;
|
|
float32 mouse_y;
|
|
|
|
// Gamepad
|
|
// If you need to deal with more than 1 gamepad, use INPUT_EVENT_GAMEPAD_AXIS
|
|
Vector2 left_stick;
|
|
Vector2 right_stick;
|
|
float32 left_trigger;
|
|
float32 right_trigger;
|
|
|
|
Input_State_Flags key_states[INPUT_KEY_CODE_COUNT];
|
|
|
|
} Input_Frame;
|
|
|
|
// #Global
|
|
ogb_instance Input_Frame input_frame;
|
|
ogb_instance Vector2 deadzone_left_stick;
|
|
ogb_instance Vector2 deadzone_right_stick;
|
|
ogb_instance float32 deadzone_left_trigger;
|
|
ogb_instance float32 deadzone_right_trigger;
|
|
|
|
#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE
|
|
Input_Frame input_frame = ZERO(Input_Frame);
|
|
Vector2 deadzone_left_stick = {0.2, 0.2};
|
|
Vector2 deadzone_right_stick = {0.2, 0.2};
|
|
float32 deadzone_left_trigger = {0.07};
|
|
float32 deadzone_right_trigger = {0.07};
|
|
#endif
|
|
|
|
// 0.0 for no vibration, 1.0 for max vibration
|
|
void set_gamepad_vibration(float32 left, float32 right);
|
|
void set_specific_gamepad_vibration(u64 gamepad_index, float32 left, float32 right);
|
|
|
|
bool has_key_state(Input_Key_Code code, Input_State_Flags flags) {
|
|
assert(code > 0 && code < INPUT_KEY_CODE_COUNT, "Invalid key code %d!", code);
|
|
Input_State_Flags state = input_frame.key_states[code];
|
|
|
|
#if CONFIGURATION == DEBUG
|
|
{
|
|
Input_State_Flags impossible = (INPUT_STATE_JUST_RELEASED | INPUT_STATE_DOWN);
|
|
assert((impossible & state) != impossible, "Key state for key '%d' is corrupt!", code);
|
|
impossible = (INPUT_STATE_JUST_RELEASED | INPUT_STATE_JUST_PRESSED);
|
|
assert((impossible & state) != impossible, "Key state for key '%d' is corrupt!", code);
|
|
}
|
|
#endif
|
|
return (state & flags) == flags;
|
|
}
|
|
bool is_key_down(Input_Key_Code code) {
|
|
return has_key_state(code, INPUT_STATE_DOWN);
|
|
}
|
|
bool is_key_up(Input_Key_Code code) {
|
|
return input_frame.key_states[code] == 0 || has_key_state(code, INPUT_STATE_JUST_RELEASED);
|
|
}
|
|
bool is_key_just_pressed(Input_Key_Code code) {
|
|
return has_key_state(code, INPUT_STATE_JUST_PRESSED);
|
|
}
|
|
bool is_key_just_released(Input_Key_Code code) {
|
|
return has_key_state(code, INPUT_STATE_JUST_RELEASED);
|
|
}
|
|
|
|
bool consume_key_down(Input_Key_Code code) {
|
|
bool result = is_key_down(code);
|
|
input_frame.key_states[code] &= ~(INPUT_STATE_DOWN);
|
|
return result;
|
|
}
|
|
bool consume_key_just_pressed(Input_Key_Code code) {
|
|
bool result = is_key_just_pressed(code);
|
|
input_frame.key_states[code] &= ~(INPUT_STATE_JUST_PRESSED);
|
|
return result;
|
|
}
|
|
bool consume_key_just_released(Input_Key_Code code) {
|
|
bool result = is_key_just_released(code);
|
|
input_frame.key_states[code] &= ~(INPUT_STATE_JUST_RELEASED);
|
|
return result;
|
|
} |