trueno/modules/Input/module.jai

267 lines
6.6 KiB
Plaintext

// Input handler routines, platform-independent.
// The Jai Input module ported to use sokol events.
#load "sokol.jai";
Event_Type :: enum u32 { // If we set this to u8, our packing will stop matching C's.
UNINITIALIZED :: 0;
KEYBOARD :: 1;
TEXT_INPUT :: 2;
WINDOW :: 3;
MOUSE_WHEEL :: 4;
QUIT :: 5;
DRAG_AND_DROP_FILES :: 6;
TOUCH :: 7;
}
Key_Current_State :: enum_flags u32 {
NONE :: 0x0;
DOWN :: 0x1;
START :: 0x4;
END :: 0x8;
}
// We reserve 32 buttons for each gamepad.
GAMEPAD_BUTTON_COUNT :: 32;
Key_Code :: enum u32 {
UNKNOWN :: 0;
// Non-textual keys that have placements in the ASCII table
// (and thus in Unicode):
BACKSPACE :: 8;
TAB :: 9;
LINEFEED :: 10;
ENTER :: 13;
ESCAPE :: 27;
SPACEBAR :: 32;
// The letters A-Z live in here as well and may be returned
// by keyboard events.
DELETE :: 127;
ARROW_UP :: 128;
ARROW_DOWN :: 129;
ARROW_LEFT :: 130;
ARROW_RIGHT :: 131;
PAGE_UP :: 132;
PAGE_DOWN :: 133;
HOME :: 134;
END :: 135;
INSERT :: 136;
PAUSE :: 137;
SCROLL_LOCK :: 138;
ALT;
CTRL;
SHIFT;
CMD;
META :: CMD;
F1;
F2;
F3;
F4;
F5;
F6;
F7;
F8;
F9;
F10;
F11;
F12;
F13;
F14;
F15;
F16;
F17;
F18;
F19;
F20;
F21;
F22;
F23;
F24;
PRINT_SCREEN;
MOUSE_BUTTON_LEFT;
MOUSE_BUTTON_MIDDLE;
MOUSE_BUTTON_RIGHT;
MOUSE_WHEEL_UP;
MOUSE_WHEEL_DOWN;
// We reserve button codes for up to 4 gamepads.
GAMEPAD_0_BEGIN;
GAMEPAD_0_END :: GAMEPAD_0_BEGIN + xx GAMEPAD_BUTTON_COUNT;
GAMEPAD_1_BEGIN;
GAMEPAD_1_END :: GAMEPAD_1_BEGIN + xx GAMEPAD_BUTTON_COUNT;
GAMEPAD_2_BEGIN;
GAMEPAD_2_END :: GAMEPAD_2_BEGIN + xx GAMEPAD_BUTTON_COUNT;
GAMEPAD_3_BEGIN;
GAMEPAD_3_END :: GAMEPAD_3_BEGIN + xx GAMEPAD_BUTTON_COUNT;
TOUCH;
// WARNING!
//
// We make an array whose size is controlled
// by the last enum value in this array, so if you make
// really big values to match Unicode code points, our
// memory usage will become quite sorry.
//
// -jblow, 19 March 2017
//
}
// Modifier_Flags used to use #place, but I rewrote it to use a union
// instead .... it is not necessarily clearer though! So I am switching
// it back for now...
Event :: struct {
Modifier_Flags :: union {
// Eventually we'd like the *_pressed modifiers to be 1 bit each,
// but still be nameable as booleans. But for now they're 1 byte each.
// You can compare them as a u32 using the 'packed' member.
struct {
// @@ This is confusing. Below key_pressed means the key was just pressed, here _pressed means the key is held down.
shift_pressed := false;
ctrl_pressed := false;
alt_pressed := false;
cmd_meta_pressed := false; // Cmd on macOS, Meta on Linux
}
packed: u32 = 0;
}
type: Event_Type = Event_Type.UNINITIALIZED;
// If keyboard event:
key_pressed: u32; // If not pressed, it's a key release.
key_code := Key_Code.UNKNOWN;
using modifier_flags: Modifier_Flags; // Only set for Event_Type.KEYBOARD.
utf32: u32; // If TEXT_INPUT.
repeat := false; // If KEYBOARD event.
text_input_count: u16; // If KEYBOARD event that also generated TEXT_INPUT events, this will tell you how many TEXT_INPUT events after this KEYBOARD event were generated.
typical_wheel_delta: s32; // Used only for mouse events.
wheel_delta: s32; // Used only for mouse events.
files: [..] string; // Used only for drag and drop events. Both the array and its contents are heap-allocated, lives until events are reset for the next frame.
touch_type: enum u8 { // Used only for touch events.
MOVED :: 0;
PRESSED :: 1;
RELEASED :: 2;
}
touch_index: s32; // Used only for touch events. Index of which touch this is.
}
// Per-frame mouse deltas:
mouse_delta_x: int;
mouse_delta_y: int;
mouse_delta_z: int;
events_this_frame: [..] Event;
input_button_states: [NUM_BUTTON_STATES] Key_Current_State;
input_application_has_focus := false;
NUM_BUTTON_STATES :: #run enum_highest_value(Key_Code) + 1;
Window_Resize_Record :: struct {
window: Window_Type;
width: s32;
height: s32;
}
Window_Move_Record :: struct {
window: Window_Type;
x: s32;
y: s32;
}
get_window_resizes :: () -> [] Window_Resize_Record {
// The return value here will stick around in memory until the next call
// to get_window_resizes (from any thread. Actually this whole module does
// not deal with threading, so don't do that!)
if resizes_to_free array_reset(*resizes_to_free);
if !pending_resizes return .[];
array_copy(*resizes_to_free, pending_resizes);
this_allocation_is_not_a_leak(resizes_to_free.data);
pending_resizes.count = 0;
return resizes_to_free;
}
get_window_moves :: () -> [] Window_Move_Record {
// See notes on get_window_resizes. This works the same way.
if moves_to_free array_reset(*moves_to_free);
if !pending_moves return .[];
array_copy(*moves_to_free, pending_moves);
pending_moves.count = 0;
return moves_to_free;
}
input_per_frame_event_and_flag_update :: () {
// Called once per frame, probably.
for events_this_frame {
allocator := it.files.allocator; // Same allocator for filenames and the array itself.
for file: it.files {
free(file,, allocator);
}
array_free(it.files,, allocator);
}
array_reset(*events_this_frame);
mask := ~Key_Current_State.START;
end_mask := ~(Key_Current_State.END | .DOWN | .START);
// @Speed: Could just keep a list of who is not currently set.
for * input_button_states {
if it.* & .END {
it.* &= end_mask;
} else {
it.* &= mask;
}
}
mouse_delta_x = 0;
mouse_delta_y = 0;
mouse_delta_z = 0;
}
#scope_module
pending_moves: [..] Window_Move_Record;
moves_to_free: [..] Window_Move_Record;
pending_resizes: [..] Window_Resize_Record;
resizes_to_free: [..] Window_Resize_Record;
#import "Basic";
#import "Window_Type";