package platform import window "window:window" MAX_ACTIONS :: 64 MAX_BINDINGS_PER_ACTION :: 4 Input_Source :: union { window.Key_Code, window.Mouse_Button, } Action_Binding :: struct { sources: [MAX_BINDINGS_PER_ACTION]Input_Source, count: int, name: string, } Action_State :: struct { bindings: [MAX_ACTIONS]Action_Binding, count: int, // next ID to assign (1-based, 0 = invalid) } // Register a named action, returns its handle. Returns 0 if full. register_action :: proc(state: ^Action_State, name: string) -> u32 { if state.count >= MAX_ACTIONS { return 0 } state.count += 1 id := state.count state.bindings[id].name = name return u32(id) } // Bind a key to an action. Silently ignored if bindings are full. bind_action_key :: proc(state: ^Action_State, action: u32, key: window.Key_Code) { if action == 0 || int(action) > state.count { return } b := &state.bindings[action] if b.count >= MAX_BINDINGS_PER_ACTION { return } b.sources[b.count] = key b.count += 1 } // Bind a mouse button to an action. Silently ignored if bindings are full. bind_action_mouse :: proc(state: ^Action_State, action: u32, btn: window.Mouse_Button) { if action == 0 || int(action) > state.count { return } b := &state.bindings[action] if b.count >= MAX_BINDINGS_PER_ACTION { return } b.sources[b.count] = btn b.count += 1 } // Clear all bindings for an action. unbind_action :: proc(state: ^Action_State, action: u32) { if action == 0 || int(action) > state.count { return } b := &state.bindings[action] b.count = 0 b.sources = {} } // Check if any binding for the action was pressed this frame. is_action_pressed :: proc(pstate: ^Platform_State, action: u32) -> bool { if action == 0 || int(action) > pstate.actions.count { return false } b := &pstate.actions.bindings[action] for i in 0 ..< b.count { switch src in b.sources[i] { case window.Key_Code: if is_key_pressed(pstate, src) { return true } case window.Mouse_Button: if is_mouse_button_pressed(pstate, src) { return true } } } return false } // Check if any binding for the action is held down. is_action_down :: proc(pstate: ^Platform_State, action: u32) -> bool { if action == 0 || int(action) > pstate.actions.count { return false } b := &pstate.actions.bindings[action] for i in 0 ..< b.count { switch src in b.sources[i] { case window.Key_Code: if is_key_down(pstate, src) { return true } case window.Mouse_Button: if is_mouse_button_down(pstate, src) { return true } } } return false } // Check if any binding for the action was released this frame. is_action_released :: proc(pstate: ^Platform_State, action: u32) -> bool { if action == 0 || int(action) > pstate.actions.count { return false } b := &pstate.actions.bindings[action] for i in 0 ..< b.count { switch src in b.sources[i] { case window.Key_Code: if is_key_released(pstate, src) { return true } case window.Mouse_Button: // Mouse buttons don't have released tracking yet, // check via current/previous state idx := int(src) if idx >= 0 && idx < MAX_MOUSE_BUTTONS { if !pstate.input.mouse_current[idx] && pstate.input.mouse_previous[idx] { return true } } } } return false } // Get the name of an action. get_action_name :: proc(state: ^Action_State, action: u32) -> string { if action == 0 || int(action) > state.count { return "" } return state.bindings[action].name } // Get active bindings for an action (for settings UI). Returns a slice into the fixed array. get_action_bindings :: proc(state: ^Action_State, action: u32) -> []Input_Source { if action == 0 || int(action) > state.count { return {} } b := &state.bindings[action] return b.sources[:b.count] }