1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package platform
import window "window:window"
MAX_KEYS :: 153 // window.Key_Code has ~153 variants
MAX_MOUSE_BUTTONS :: 5
Input_State :: struct {
// Key states: current and previous frame
keys_current: [MAX_KEYS]bool,
keys_previous: [MAX_KEYS]bool,
// Mouse button states
mouse_current: [MAX_MOUSE_BUTTONS]bool,
mouse_previous: [MAX_MOUSE_BUTTONS]bool,
// Mouse position
mouse_x, mouse_y: f32,
mouse_prev_x, mouse_prev_y: f32,
// Raw mouse delta (from device events)
mouse_delta_x, mouse_delta_y: f32,
// Scroll wheel
scroll_delta: f32,
}
init_input :: proc(state: ^Input_State) {
state^ = {}
}
// Called at the start of each frame to swap current -> previous
begin_input_frame :: proc(state: ^Input_State) {
state.keys_previous = state.keys_current
state.mouse_previous = state.mouse_current
state.mouse_prev_x = state.mouse_x
state.mouse_prev_y = state.mouse_y
state.mouse_delta_x = 0
state.mouse_delta_y = 0
state.scroll_delta = 0
}
// Event handlers called from platform.poll_events
handle_key_input :: proc(state: ^Input_State, event: window.Key_Input) {
idx := int(event.key)
if idx >= 0 && idx < MAX_KEYS {
state.keys_current[idx] = event.state == .Pressed
}
}
handle_mouse_button_input :: proc(state: ^Input_State, event: window.Mouse_Button_Input) {
idx := int(event.button)
if idx >= 0 && idx < MAX_MOUSE_BUTTONS {
state.mouse_current[idx] = event.state == .Pressed
}
}
handle_pointer_moved :: proc(state: ^Input_State, event: window.Pointer_Moved) {
state.mouse_x = f32(event.position.x)
state.mouse_y = f32(event.position.y)
}
handle_raw_motion :: proc(state: ^Input_State, event: window.Pointer_Motion) {
state.mouse_delta_x += f32(event.delta_x)
state.mouse_delta_y += f32(event.delta_y)
}
handle_mouse_wheel :: proc(state: ^Input_State, event: window.Mouse_Wheel) {
switch d in event.delta {
case window.Line_Delta:
state.scroll_delta += d.y
case window.Pixel_Delta:
state.scroll_delta += d.y / 120.0 // normalize pixel delta
}
}
// Query functions
is_key_pressed :: proc(state: ^Platform_State, key: window.Key_Code) -> bool {
idx := int(key)
if idx < 0 || idx >= MAX_KEYS {
return false
}
return state.input.keys_current[idx] && !state.input.keys_previous[idx]
}
is_key_down :: proc(state: ^Platform_State, key: window.Key_Code) -> bool {
idx := int(key)
if idx < 0 || idx >= MAX_KEYS {
return false
}
return state.input.keys_current[idx]
}
is_key_released :: proc(state: ^Platform_State, key: window.Key_Code) -> bool {
idx := int(key)
if idx < 0 || idx >= MAX_KEYS {
return false
}
return !state.input.keys_current[idx] && state.input.keys_previous[idx]
}
is_mouse_button_pressed :: proc(state: ^Platform_State, btn: window.Mouse_Button) -> bool {
idx := int(btn)
if idx < 0 || idx >= MAX_MOUSE_BUTTONS {
return false
}
return state.input.mouse_current[idx] && !state.input.mouse_previous[idx]
}
is_mouse_button_down :: proc(state: ^Platform_State, btn: window.Mouse_Button) -> bool {
idx := int(btn)
if idx < 0 || idx >= MAX_MOUSE_BUTTONS {
return false
}
return state.input.mouse_current[idx]
}
get_mouse_position :: proc(state: ^Platform_State) -> [2]f32 {
return {state.input.mouse_x, state.input.mouse_y}
}
get_mouse_delta :: proc(state: ^Platform_State) -> [2]f32 {
// Prefer raw motion delta; fall back to position delta
dx := state.input.mouse_delta_x
dy := state.input.mouse_delta_y
if dx == 0 && dy == 0 {
dx = state.input.mouse_x - state.input.mouse_prev_x
dy = state.input.mouse_y - state.input.mouse_prev_y
}
return {dx, dy}
}
get_mouse_wheel_move :: proc(state: ^Platform_State) -> f32 {
return state.input.scroll_delta
}