- User input
- Input state polling & consuming - is_key_down, is_key_just_pressed, is_key_just_release - consume_key_down, consume_key_just_pressed, consume_key_just_released - Input events - Key event - Scroll event - Text event - unicode.c - utf16_to_utf32
This commit is contained in:
parent
c61f216d37
commit
8a0fc81576
13 changed files with 501 additions and 19 deletions
|
@ -4,6 +4,6 @@ mkdir build
|
||||||
|
|
||||||
pushd build
|
pushd build
|
||||||
|
|
||||||
cl ../build.c /Zi /Fecgame.exe /Od /DDEBUG /MD /DEBUG /std:c11
|
cl.exe /Fe:cgame.exe ..\build.c /Od /std:c11 /W4 /wd4273 /wd4018 /wd4100 /Zi gdi32.lib user32.lib opengl32.lib
|
||||||
|
|
||||||
popd
|
popd
|
4
build.c
4
build.c
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
///
|
///
|
||||||
// Build config stuff
|
// Build config stuff
|
||||||
#define VERY_DEBUG 0
|
|
||||||
#define RUN_TESTS 0
|
#define RUN_TESTS 0
|
||||||
|
|
||||||
|
// When we need very debug
|
||||||
|
// #define CONFIGURATION VERY_DEBUG
|
||||||
|
|
||||||
typedef struct Context_Extra {
|
typedef struct Context_Extra {
|
||||||
int monkee;
|
int monkee;
|
||||||
} Context_Extra;
|
} Context_Extra;
|
||||||
|
|
|
@ -4,6 +4,6 @@ mkdir build
|
||||||
|
|
||||||
pushd build
|
pushd build
|
||||||
|
|
||||||
clang -g -o cgame.exe ../build.c -O0 -DDEBUG -std=c11 -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -lgdi32 -luser32 -lopengl32
|
clang -g -o cgame.exe ../build.c -O0 -std=c11 -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -lgdi32 -luser32 -lopengl32
|
||||||
|
|
||||||
popd
|
popd
|
|
@ -7,7 +7,7 @@ pushd build
|
||||||
mkdir release
|
mkdir release
|
||||||
pushd release
|
pushd release
|
||||||
|
|
||||||
cl ../../build.c /Zi /Fecgame.exe /Ox /DRELEASE /MD /std:c11
|
cl.exe /Fe:cgame.exe ..\..\build.c /Ox /std:c11 /W4 /wd4273 /wd4018 /wd4100 gdi32.lib user32.lib opengl32.lib
|
||||||
|
|
||||||
popd
|
popd
|
||||||
popd
|
popd
|
|
@ -7,7 +7,7 @@ pushd build
|
||||||
mkdir release
|
mkdir release
|
||||||
pushd release
|
pushd release
|
||||||
|
|
||||||
clang -o cgame.exe ../../build.c -Ofast -DRELEASE -std=c11 -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -lgdi32 -luser32 -lopengl32
|
clang -o cgame.exe ../../build.c -Ofast -std=c11 -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -lgdi32 -luser32 -lopengl32
|
||||||
|
|
||||||
popd
|
popd
|
||||||
popd
|
popd
|
23
entry.c
23
entry.c
|
@ -15,15 +15,30 @@ int start(int argc, char **argv) {
|
||||||
reset_temporary_storage();
|
reset_temporary_storage();
|
||||||
context.allocator = temp;
|
context.allocator = temp;
|
||||||
|
|
||||||
os_update();
|
os_update();
|
||||||
|
|
||||||
float64 now = os_get_current_time_in_seconds();
|
float64 now = os_get_current_time_in_seconds();
|
||||||
float64 delta = now - last_time;
|
float64 delta = now - last_time;
|
||||||
last_time = now;
|
last_time = now;
|
||||||
|
|
||||||
|
if (is_key_just_released(KEY_ESCAPE)) {
|
||||||
|
window.should_close = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_key_just_released('E')) {
|
||||||
|
print("Mouse pos: %f, %f\n", input_frame.mouse_x, input_frame.mouse_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u64 i = 0; i < input_frame.number_of_events; i++) {
|
||||||
|
Input_Event e = input_frame.events[i];
|
||||||
|
|
||||||
// Print some random FPS samples every now and then
|
switch (e.kind) {
|
||||||
if ((get_random() % 4000) == 3)
|
case INPUT_EVENT_KEY: print("Key event key code %d\n", e.key_code); break;
|
||||||
print("%2.f FPS\n", 1.0/delta);
|
case INPUT_EVENT_SCROLL: print("Scroll event, x: %.3f, y: %.3f\n", e.xscroll, e.yscroll); break;
|
||||||
|
case INPUT_EVENT_TEXT: print("Text event, utf32: %d, ascii: %c\n", e.utf32, e.ascii); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
draw_rect_rotated(v2(-.25f, -.25f), v2(.5f, .5f), COLOR_RED, v2(.25, .25), (f32)now);
|
draw_rect_rotated(v2(-.25f, -.25f), v2(.5f, .5f), COLOR_RED, v2(.25, .25), (f32)now);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ typedef u8 bool;
|
||||||
|
|
||||||
#define thread_local _Thread_local
|
#define thread_local _Thread_local
|
||||||
|
|
||||||
|
#define local_persist static
|
||||||
|
|
||||||
#define ifnt(x) if (!(x))
|
#define ifnt(x) if (!(x))
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -40,17 +42,20 @@ void printf(const char* fmt, ...);
|
||||||
#define assert_line(line, cond, ...) if (!(cond)) { printf("Assertion failed in file " __FILE__ " on line " STR(line) "\nFailed Condition: " #cond ". Message: " __VA_ARGS__); os_break(); }
|
#define assert_line(line, cond, ...) if (!(cond)) { printf("Assertion failed in file " __FILE__ " on line " STR(line) "\nFailed Condition: " #cond ". Message: " __VA_ARGS__); os_break(); }
|
||||||
#define assert(cond, ...) assert_line(__LINE__, cond, __VA_ARGS__);
|
#define assert(cond, ...) assert_line(__LINE__, cond, __VA_ARGS__);
|
||||||
|
|
||||||
#ifdef RELEASE
|
#if CONFIGRATION == RELEASE
|
||||||
#undef assert
|
#undef assert
|
||||||
#define assert(...)
|
#define assert(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define panic(...) { print(__VA_ARGS__); os_break(); }
|
||||||
|
|
||||||
#define cast(t) (t)
|
#define cast(t) (t)
|
||||||
|
|
||||||
#define ZERO(t) (t){0}
|
#define ZERO(t) (t){0}
|
||||||
|
|
||||||
///
|
///
|
||||||
// Compiler specific stuff
|
// Compiler specific stuff
|
||||||
|
// We make inline actually inline.
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// Microsoft Visual C++
|
// Microsoft Visual C++
|
||||||
#define inline __forceinline
|
#define inline __forceinline
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
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_CLOSE: ...; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum Input_Event_Kind {
|
||||||
|
INPUT_EVENT_KEY,
|
||||||
|
INPUT_EVENT_SCROLL,
|
||||||
|
INPUT_EVENT_TEXT,
|
||||||
|
} 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,
|
||||||
|
|
||||||
|
MOUSE_BUTTON_LEFT,
|
||||||
|
MOUSE_BUTTON_MIDDLE,
|
||||||
|
MOUSE_BUTTON_RIGHT,
|
||||||
|
|
||||||
|
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 struct Input_Event {
|
||||||
|
Input_Event_Kind kind;
|
||||||
|
|
||||||
|
// For INPUT_EVENT_KEY
|
||||||
|
Input_Key_Code key_code;
|
||||||
|
Input_State_Flags key_state;
|
||||||
|
|
||||||
|
// For INPUT_EVENT_SCROLL
|
||||||
|
float64 xscroll;
|
||||||
|
float64 yscroll;
|
||||||
|
|
||||||
|
// For INPUT_EVENT_TEXT_INPUT
|
||||||
|
union { u32 utf32; char ascii; };
|
||||||
|
|
||||||
|
} 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;
|
||||||
|
|
||||||
|
Input_State_Flags key_states[INPUT_KEY_CODE_COUNT];
|
||||||
|
|
||||||
|
} Input_Frame;
|
||||||
|
Input_Frame input_frame = ZERO(Input_Frame);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -25,12 +25,16 @@ void lodepng_free(void* ptr) {
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
|
||||||
#if !defined(DEBUG) && !defined(RELEASE)
|
#define DEBUG 0
|
||||||
|
#define VERY_DEBUG 1
|
||||||
|
#define RELEASE 2
|
||||||
|
|
||||||
|
#if !defined(CONFIGURATION)
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define DEBUG
|
#define CONFIGURATION DEBUG
|
||||||
#elif defined(NDEBUG)
|
#elif defined(NDEBUG)
|
||||||
#define RELEASE
|
#define CONFIGURATION RELEASE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -76,6 +80,7 @@ void lodepng_free(void* ptr) {
|
||||||
|
|
||||||
|
|
||||||
#include "string.c"
|
#include "string.c"
|
||||||
|
#include "unicode.c"
|
||||||
#include "string_format.c"
|
#include "string_format.c"
|
||||||
|
|
||||||
#include "os_interface.c"
|
#include "os_interface.c"
|
||||||
|
|
|
@ -5,8 +5,49 @@
|
||||||
void* heap_alloc(u64);
|
void* heap_alloc(u64);
|
||||||
void heap_dealloc(void*);
|
void heap_dealloc(void*);
|
||||||
|
|
||||||
|
// Persistent
|
||||||
|
Input_State_Flags win32_key_states[INPUT_KEY_CODE_COUNT];
|
||||||
|
|
||||||
|
void win32_send_key_event(Input_Key_Code code, Input_State_Flags state) {
|
||||||
|
Input_Event e;
|
||||||
|
e.kind = INPUT_EVENT_KEY;
|
||||||
|
e.key_code = code;
|
||||||
|
e.key_state = state;
|
||||||
|
input_frame.events[input_frame.number_of_events] = e;
|
||||||
|
input_frame.number_of_events += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void win32_handle_key_up(Input_Key_Code code) {
|
||||||
|
if (code == KEY_UNKNOWN) return;
|
||||||
|
|
||||||
|
Input_State_Flags last_state = win32_key_states[code];
|
||||||
|
Input_State_Flags state = 0;
|
||||||
|
|
||||||
|
if (last_state & INPUT_STATE_DOWN) state |= INPUT_STATE_JUST_RELEASED;
|
||||||
|
|
||||||
|
win32_key_states[code] = state;
|
||||||
|
|
||||||
|
win32_send_key_event(code, state);
|
||||||
|
}
|
||||||
|
void win32_handle_key_down(Input_Key_Code code) {
|
||||||
|
if (code == KEY_UNKNOWN) return;
|
||||||
|
|
||||||
|
Input_State_Flags last_state = win32_key_states[code];
|
||||||
|
Input_State_Flags state = INPUT_STATE_DOWN;
|
||||||
|
|
||||||
|
if (!(last_state & INPUT_STATE_DOWN)) state |= INPUT_STATE_JUST_PRESSED;
|
||||||
|
|
||||||
|
win32_key_states[code] = state;
|
||||||
|
|
||||||
|
win32_send_key_event(code, state);
|
||||||
|
}
|
||||||
|
void win32_handle_key_repeat(Input_Key_Code code) {
|
||||||
|
if (code == KEY_UNKNOWN) return;
|
||||||
|
|
||||||
|
win32_key_states[code] |= INPUT_STATE_REPEAT;
|
||||||
|
|
||||||
|
win32_send_key_event(code, win32_key_states[code]);
|
||||||
|
}
|
||||||
LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wparam, LPARAM lparam) {
|
LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wparam, LPARAM lparam) {
|
||||||
|
|
||||||
if (window._initialized) {
|
if (window._initialized) {
|
||||||
|
@ -15,12 +56,76 @@ LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wpar
|
||||||
|
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
|
window.should_close = true;
|
||||||
DestroyWindow(window._os_handle);
|
DestroyWindow(window._os_handle);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
break;
|
break;
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
bool is_repeat = (lparam & 0x40000000) != 0;
|
||||||
|
|
||||||
|
if (is_repeat) win32_handle_key_repeat(os_key_to_key_code((void*)wparam));
|
||||||
|
else win32_handle_key_down (os_key_to_key_code((void*)wparam));
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
case WM_KEYUP:
|
||||||
|
win32_handle_key_up(os_key_to_key_code((void*)wparam));
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
case WM_LBUTTONDOWN:
|
||||||
|
win32_handle_key_down(MOUSE_BUTTON_LEFT);
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
case WM_RBUTTONDOWN:
|
||||||
|
win32_handle_key_down(MOUSE_BUTTON_RIGHT);
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
case WM_MBUTTONDOWN:
|
||||||
|
win32_handle_key_down(MOUSE_BUTTON_MIDDLE);
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
case WM_LBUTTONUP:
|
||||||
|
win32_handle_key_up(MOUSE_BUTTON_LEFT);
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
case WM_RBUTTONUP:
|
||||||
|
win32_handle_key_up(MOUSE_BUTTON_RIGHT);
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
case WM_MBUTTONUP:
|
||||||
|
win32_handle_key_up(MOUSE_BUTTON_MIDDLE);
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
case WM_MOUSEWHEEL: {
|
||||||
|
int delta = GET_WHEEL_DELTA_WPARAM(wparam);
|
||||||
|
int ticks = delta / WHEEL_DELTA;
|
||||||
|
Input_Event e;
|
||||||
|
e.kind = INPUT_EVENT_SCROLL;
|
||||||
|
e.yscroll = (float64)delta/(float64)WHEEL_DELTA;
|
||||||
|
e.xscroll = 0;
|
||||||
|
input_frame.events[input_frame.number_of_events] = e;
|
||||||
|
input_frame.number_of_events += 1;
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
}
|
||||||
|
case WM_MOUSEHWHEEL: {
|
||||||
|
int delta = GET_WHEEL_DELTA_WPARAM(wparam);
|
||||||
|
Input_Event e;
|
||||||
|
e.kind = INPUT_EVENT_SCROLL;
|
||||||
|
e.yscroll = 0;
|
||||||
|
e.xscroll = (float64)delta/(float64)WHEEL_DELTA;
|
||||||
|
input_frame.events[input_frame.number_of_events] = e;
|
||||||
|
input_frame.number_of_events += 1;
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
}
|
||||||
|
case WM_CHAR: {
|
||||||
|
wchar_t utf16 = (wchar_t)wparam;
|
||||||
|
|
||||||
|
Input_Event e;
|
||||||
|
e.kind = INPUT_EVENT_TEXT;
|
||||||
|
utf16_to_utf32(&utf16, 1, &e.utf32);
|
||||||
|
|
||||||
|
input_frame.events[input_frame.number_of_events] = e;
|
||||||
|
input_frame.number_of_events += 1;
|
||||||
|
|
||||||
|
goto DEFAULT_HANDLE;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
|
|
||||||
|
DEFAULT_HANDLE:
|
||||||
return DefWindowProc(passed_window, message, wparam, lparam);
|
return DefWindowProc(passed_window, message, wparam, lparam);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -346,7 +451,7 @@ bool os_compare_and_swap_bool(bool *a, bool b, bool old) {
|
||||||
|
|
||||||
void os_update() {
|
void os_update() {
|
||||||
|
|
||||||
static Os_Window last_window;
|
local_persist Os_Window last_window;
|
||||||
|
|
||||||
if (!strings_match(last_window.title, window.title)) {
|
if (!strings_match(last_window.title, window.title)) {
|
||||||
SetWindowText(window._os_handle, temp_convert_to_null_terminated_string(window.title));
|
SetWindowText(window._os_handle, temp_convert_to_null_terminated_string(window.title));
|
||||||
|
@ -400,9 +505,20 @@ void os_update() {
|
||||||
last_window = window;
|
last_window = window;
|
||||||
|
|
||||||
|
|
||||||
|
// Reflect what the backend did to input state before we query for OS inputs
|
||||||
|
memcpy(win32_key_states, input_frame.key_states, sizeof(input_frame.key_states));
|
||||||
|
input_frame.number_of_events = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for (u64 i = 0; i < INPUT_KEY_CODE_COUNT; i++) {
|
||||||
|
win32_key_states[i] &= ~(INPUT_STATE_REPEAT);
|
||||||
|
win32_key_states[i] &= ~(INPUT_STATE_JUST_PRESSED);
|
||||||
|
win32_key_states[i] &= ~(INPUT_STATE_JUST_RELEASED);
|
||||||
|
}
|
||||||
|
|
||||||
MSG msg;
|
MSG msg;
|
||||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
while (input_frame.number_of_events < MAX_EVENTS_PER_FRAME
|
||||||
|
&& PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
if (msg.message == WM_QUIT) {
|
if (msg.message == WM_QUIT) {
|
||||||
window.should_close = true;
|
window.should_close = true;
|
||||||
break;
|
break;
|
||||||
|
@ -410,4 +526,128 @@ void os_update() {
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(input_frame.key_states, win32_key_states, sizeof(input_frame.key_states));
|
||||||
|
POINT p;
|
||||||
|
GetCursorPos(&p);
|
||||||
|
ScreenToClient(window._os_handle, &p);
|
||||||
|
p.y = window.height - p.y;
|
||||||
|
input_frame.mouse_x = (float32)p.x;
|
||||||
|
input_frame.mouse_y = (float32)p.y;
|
||||||
|
|
||||||
|
if (window.should_close) {
|
||||||
|
win32_window_proc(window._os_handle, WM_CLOSE, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Input_Key_Code os_key_to_key_code(void* os_key) {
|
||||||
|
|
||||||
|
UINT win32_key = (UINT)(u64)os_key;
|
||||||
|
|
||||||
|
if (win32_key >= 'A' && win32_key <= 'Z') {
|
||||||
|
return (Input_Key_Code)win32_key;
|
||||||
|
}
|
||||||
|
if (win32_key >= '0' && win32_key <= '9') {
|
||||||
|
return (Input_Key_Code)win32_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (win32_key) {
|
||||||
|
case VK_BACK: return KEY_BACKSPACE;
|
||||||
|
case VK_TAB: return KEY_TAB;
|
||||||
|
case VK_RETURN: return KEY_ENTER;
|
||||||
|
case VK_ESCAPE: return KEY_ESCAPE;
|
||||||
|
case VK_SPACE: return KEY_SPACEBAR;
|
||||||
|
case VK_DELETE: return KEY_DELETE;
|
||||||
|
case VK_UP: return KEY_ARROW_UP;
|
||||||
|
case VK_DOWN: return KEY_ARROW_DOWN;
|
||||||
|
case VK_LEFT: return KEY_ARROW_LEFT;
|
||||||
|
case VK_RIGHT: return KEY_ARROW_RIGHT;
|
||||||
|
case VK_PRIOR: return KEY_PAGE_UP;
|
||||||
|
case VK_NEXT: return KEY_PAGE_DOWN;
|
||||||
|
case VK_HOME: return KEY_HOME;
|
||||||
|
case VK_END: return KEY_END;
|
||||||
|
case VK_INSERT: return KEY_INSERT;
|
||||||
|
case VK_PAUSE: return KEY_PAUSE;
|
||||||
|
case VK_SCROLL: return KEY_SCROLL_LOCK;
|
||||||
|
case VK_MENU: return KEY_ALT;
|
||||||
|
case VK_CONTROL: return KEY_CTRL;
|
||||||
|
case VK_SHIFT: return KEY_SHIFT;
|
||||||
|
case VK_LWIN: return KEY_CMD;
|
||||||
|
case VK_RWIN: return KEY_CMD;
|
||||||
|
case VK_F1: return KEY_F1;
|
||||||
|
case VK_F2: return KEY_F2;
|
||||||
|
case VK_F3: return KEY_F3;
|
||||||
|
case VK_F4: return KEY_F4;
|
||||||
|
case VK_F5: return KEY_F5;
|
||||||
|
case VK_F6: return KEY_F6;
|
||||||
|
case VK_F7: return KEY_F7;
|
||||||
|
case VK_F8: return KEY_F8;
|
||||||
|
case VK_F9: return KEY_F9;
|
||||||
|
case VK_F10: return KEY_F10;
|
||||||
|
case VK_F11: return KEY_F11;
|
||||||
|
case VK_F12: return KEY_F12;
|
||||||
|
case VK_SNAPSHOT: return KEY_PRINT_SCREEN;
|
||||||
|
case VK_LBUTTON: return MOUSE_BUTTON_LEFT;
|
||||||
|
case VK_MBUTTON: return MOUSE_BUTTON_MIDDLE;
|
||||||
|
case VK_RBUTTON: return MOUSE_BUTTON_RIGHT;
|
||||||
|
default: return KEY_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* key_code_to_os_key(Input_Key_Code key_code) {
|
||||||
|
|
||||||
|
if (key_code >= 'A' && key_code <= 'Z') {
|
||||||
|
return (void*)key_code;
|
||||||
|
}
|
||||||
|
if (key_code >= '0' && key_code <= '9') {
|
||||||
|
return (void*)key_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key_code) {
|
||||||
|
case KEY_BACKSPACE: return (void*)VK_BACK;
|
||||||
|
case KEY_TAB: return (void*)VK_TAB;
|
||||||
|
case KEY_ENTER: return (void*)VK_RETURN;
|
||||||
|
case KEY_ESCAPE: return (void*)VK_ESCAPE;
|
||||||
|
case KEY_SPACEBAR: return (void*)VK_SPACE;
|
||||||
|
case KEY_DELETE: return (void*)VK_DELETE;
|
||||||
|
case KEY_ARROW_UP: return (void*)VK_UP;
|
||||||
|
case KEY_ARROW_DOWN: return (void*)VK_DOWN;
|
||||||
|
case KEY_ARROW_LEFT: return (void*)VK_LEFT;
|
||||||
|
case KEY_ARROW_RIGHT: return (void*)VK_RIGHT;
|
||||||
|
case KEY_PAGE_UP: return (void*)VK_PRIOR;
|
||||||
|
case KEY_PAGE_DOWN: return (void*)VK_NEXT;
|
||||||
|
case KEY_HOME: return (void*)VK_HOME;
|
||||||
|
case KEY_END: return (void*)VK_END;
|
||||||
|
case KEY_INSERT: return (void*)VK_INSERT;
|
||||||
|
case KEY_PAUSE: return (void*)VK_PAUSE;
|
||||||
|
case KEY_SCROLL_LOCK: return (void*)VK_SCROLL;
|
||||||
|
case KEY_ALT: return (void*)VK_MENU;
|
||||||
|
case KEY_CTRL: return (void*)VK_CONTROL;
|
||||||
|
case KEY_SHIFT: return (void*)VK_SHIFT;
|
||||||
|
case KEY_CMD: return (void*)VK_LWIN; // Assuming left win key for both
|
||||||
|
case KEY_F1: return (void*)VK_F1;
|
||||||
|
case KEY_F2: return (void*)VK_F2;
|
||||||
|
case KEY_F3: return (void*)VK_F3;
|
||||||
|
case KEY_F4: return (void*)VK_F4;
|
||||||
|
case KEY_F5: return (void*)VK_F5;
|
||||||
|
case KEY_F6: return (void*)VK_F6;
|
||||||
|
case KEY_F7: return (void*)VK_F7;
|
||||||
|
case KEY_F8: return (void*)VK_F8;
|
||||||
|
case KEY_F9: return (void*)VK_F9;
|
||||||
|
case KEY_F10: return (void*)VK_F10;
|
||||||
|
case KEY_F11: return (void*)VK_F11;
|
||||||
|
case KEY_F12: return (void*)VK_F12;
|
||||||
|
case KEY_PRINT_SCREEN: return (void*)VK_SNAPSHOT;
|
||||||
|
case MOUSE_BUTTON_LEFT: return (void*)VK_LBUTTON;
|
||||||
|
case MOUSE_BUTTON_MIDDLE: return (void*)VK_MBUTTON;
|
||||||
|
case MOUSE_BUTTON_RIGHT: return (void*)VK_RBUTTON;
|
||||||
|
|
||||||
|
|
||||||
|
case INPUT_KEY_CODE_COUNT:
|
||||||
|
case KEY_UNKNOWN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("Invalid key code %d", key_code);
|
||||||
|
return 0;
|
||||||
}
|
}
|
|
@ -58,7 +58,7 @@ inline int crt_vprintf(const char* fmt, va_list args) {
|
||||||
return os.crt_vprintf(fmt, args);
|
return os.crt_vprintf(fmt, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(COMPILER_HAS_MEMCPY_INTRINSICS) || defined(DEBUG)
|
#if !defined(COMPILER_HAS_MEMCPY_INTRINSICS) || CONFIGURATION == DEBUG
|
||||||
inline void* naive_memcpy(void* dest, const void* source, size_t size) {
|
inline void* naive_memcpy(void* dest, const void* source, size_t size) {
|
||||||
for (u64 i = 0; i < (u64)size; i++) ((u8*)dest)[i] = ((u8*)source)[i];
|
for (u64 i = 0; i < (u64)size; i++) ((u8*)dest)[i] = ((u8*)source)[i];
|
||||||
return dest;
|
return dest;
|
||||||
|
@ -139,7 +139,7 @@ void os_lock_mutex(Mutex_Handle m);
|
||||||
void os_unlock_mutex(Mutex_Handle m);
|
void os_unlock_mutex(Mutex_Handle m);
|
||||||
|
|
||||||
///
|
///
|
||||||
// Spinlock primitive
|
// Spinlock "primitive"
|
||||||
typedef struct Spinlock {
|
typedef struct Spinlock {
|
||||||
bool locked;
|
bool locked;
|
||||||
} Spinlock;
|
} Spinlock;
|
||||||
|
|
|
@ -11,7 +11,7 @@ Usage:
|
||||||
|
|
||||||
string balls = const_string("balls");
|
string balls = const_string("balls");
|
||||||
// tprint for temporary allocation
|
// tprint for temporary allocation
|
||||||
string b = tprint(const_string("Hello, %s!\n"), balls); // %s for string
|
string b = tprint("Hello, %s!\n", balls); // %s for string
|
||||||
|
|
||||||
// Allocate a new string of length 12 (with context allocator)
|
// Allocate a new string of length 12 (with context allocator)
|
||||||
string c = alloc_string(12);
|
string c = alloc_string(12);
|
||||||
|
|
38
oogabooga/unicode.c
Normal file
38
oogabooga/unicode.c
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
|
||||||
|
#define UTF16_SURROGATE_HIGH_START 0xD800
|
||||||
|
#define UTF16_SURROGATE_HIGH_END 0xDBFF
|
||||||
|
#define UTF16_SURROGATE_LOW_START 0xDC00
|
||||||
|
#define UTF16_SURROGATE_LOW_END 0xDFFF
|
||||||
|
#define UTF16_SURROGATE_OFFSET 0x10000
|
||||||
|
#define UTF16_SURROGATE_MASK 0x3FF
|
||||||
|
|
||||||
|
// Returns how many utf16 units were converted
|
||||||
|
int utf16_to_utf32(const u16 *utf16, u64 length, u32 *utf32) {
|
||||||
|
if (length == 0 || utf16 == NULL || utf32 == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 first = utf16[0];
|
||||||
|
|
||||||
|
if (first >= UTF16_SURROGATE_HIGH_START && first <= UTF16_SURROGATE_HIGH_END) {
|
||||||
|
if (length < 2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 second = utf16[1];
|
||||||
|
if (second >= UTF16_SURROGATE_LOW_START && second <= UTF16_SURROGATE_LOW_END) {
|
||||||
|
*utf32 = ((first - UTF16_SURROGATE_HIGH_START) << 10)
|
||||||
|
+ (second - UTF16_SURROGATE_LOW_START)
|
||||||
|
+ UTF16_SURROGATE_OFFSET;
|
||||||
|
return 2;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (first >= UTF16_SURROGATE_LOW_START && first <= UTF16_SURROGATE_LOW_END) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
*utf32 = first;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue