Harbor

branch main
showing the latest snapshot on main
input.odin 3.6 KB · Plain text
platform/input.odin 0644 Raw
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
}