mirror of
https://github.com/Karaka-Management/cOMS.git
synced 2026-01-11 11:18:40 +00:00
Simplified input handling AND prepared for contontroller usage by merging all input states
This commit is contained in:
parent
ed7d1cf5f8
commit
177affce99
355
input/Input.h
355
input/Input.h
|
|
@ -9,19 +9,17 @@
|
||||||
#ifndef TOS_INPUT_H
|
#ifndef TOS_INPUT_H
|
||||||
#define TOS_INPUT_H
|
#define TOS_INPUT_H
|
||||||
|
|
||||||
// @question Consider to change mouse to secondary input device and keyboard to primary input device and also rename the functions etc.
|
|
||||||
|
|
||||||
// How many concurrent mouse/secondary input device presses to we recognize
|
// How many concurrent mouse/secondary input device presses to we recognize
|
||||||
#define MAX_MOUSE_PRESSES 3
|
#define MAX_MOUSE_PRESSES 3
|
||||||
|
|
||||||
// How many concurrent primary key/button presses can be handled?
|
// How many concurrent primary key/button presses can be handled?
|
||||||
#define MAX_KEY_PRESSES 5
|
#define MAX_KEY_PRESSES 5
|
||||||
|
#define MAX_KEY_STATES (2 * MAX_KEY_PRESSES)
|
||||||
|
|
||||||
// How many keys/buttons do we support for the primary input device
|
// How many keys/buttons do we support for the devices
|
||||||
#define MAX_KEYBOARD_KEYS 255
|
#define MAX_KEYBOARD_KEYS 255
|
||||||
|
#define MAX_MOUSE_KEYS 10
|
||||||
// How many mouse/secondary input device keys/buttons do we support
|
#define MAX_CONTROLLER_KEYS 24
|
||||||
#define MAX_MOUSE_KEYS 5
|
|
||||||
|
|
||||||
#define MIN_INPUT_DEVICES 2
|
#define MIN_INPUT_DEVICES 2
|
||||||
|
|
||||||
|
|
@ -33,10 +31,12 @@
|
||||||
|
|
||||||
// These values are used as bit flags to hint if a "key" is a keyboard/primary or mouse/secondary input
|
// These values are used as bit flags to hint if a "key" is a keyboard/primary or mouse/secondary input
|
||||||
// When adding a keybind the "key" can only be uint8 but we expand it to an int and set the first bit accordingly
|
// When adding a keybind the "key" can only be uint8 but we expand it to an int and set the first bit accordingly
|
||||||
#define INPUT_KEYBOARD_PREFIX 80000000
|
|
||||||
#define INPUT_MOUSE_PREFIX 0
|
#define INPUT_MOUSE_PREFIX 0
|
||||||
|
#define INPUT_KEYBOARD_PREFIX 16384
|
||||||
|
#define INPUT_CONTROLLER_PREFIX 32768
|
||||||
|
|
||||||
#define INPUT_TYPE_MOUSE_KEYBOARD 0x01
|
#define INPUT_TYPE_MOUSE_KEYBOARD 0x01
|
||||||
|
#define INPUT_TYPE_CONTROLLER 0x02
|
||||||
#define INPUT_TYPE_OTHER 0x03
|
#define INPUT_TYPE_OTHER 0x03
|
||||||
|
|
||||||
#define MIN_CONTROLLER_DEVICES 4
|
#define MIN_CONTROLLER_DEVICES 4
|
||||||
|
|
@ -54,150 +54,179 @@
|
||||||
struct InputMapping {
|
struct InputMapping {
|
||||||
// A key/button can be bound to up to 5 different hotkeys
|
// A key/button can be bound to up to 5 different hotkeys
|
||||||
// This is used to check if a key/button has a hotkey association
|
// This is used to check if a key/button has a hotkey association
|
||||||
uint8 keys[MAX_KEYBOARD_KEYS + MAX_MOUSE_KEYS][MAX_KEY_TO_HOTKEY];
|
uint8 keys[MAX_MOUSE_KEYS + MAX_KEYBOARD_KEYS + MAX_CONTROLLER_KEYS][MAX_KEY_TO_HOTKEY];
|
||||||
|
|
||||||
// A hotkey can be bound to a combination of up to 3 key/button presses
|
// A hotkey can be bound to a combination of up to 3 key/button presses
|
||||||
uint8 hotkey_count;
|
uint8 hotkey_count;
|
||||||
uint8* hotkeys;
|
uint16* hotkeys;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum KeyState {
|
||||||
|
KEY_STATE_PRESSED,
|
||||||
|
KEY_STATE_HELD,
|
||||||
|
KEY_STATE_RELEASED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InputKey {
|
||||||
|
// Includes flag for mouse, keyboard, controller
|
||||||
|
uint16 key_id;
|
||||||
|
uint16 key_state;
|
||||||
|
uint16 value; // e.g. stick/trigger keys
|
||||||
|
uint64 time; // when was this action performed (useful to decide if key state is held vs pressed)
|
||||||
};
|
};
|
||||||
|
|
||||||
// @question Maybe we should also add a third key_down array for controllers and some special controller functions here to just handle everything in one struct
|
// @question Maybe we should also add a third key_down array for controllers and some special controller functions here to just handle everything in one struct
|
||||||
// Or think about completely splitting all states (mouse, keyboard, other)
|
// Or think about completely splitting all states (mouse, keyboard, other)
|
||||||
struct InputState {
|
struct InputState {
|
||||||
// State of the hotkeys, resulting from the device input
|
// State of the hotkeys, resulting from the device input
|
||||||
// @question maybe create a separate define and make it a little bit larger?
|
|
||||||
uint8 state_hotkeys[MAX_KEY_PRESSES];
|
uint8 state_hotkeys[MAX_KEY_PRESSES];
|
||||||
|
|
||||||
uint8 keys_down[MAX_KEY_PRESSES];
|
InputKey state_keys[MAX_KEY_STATES];
|
||||||
|
|
||||||
// @question Why do we even need this? shouldn't we only care about the current keys down?
|
|
||||||
uint8 keys_up[MAX_KEY_PRESSES];
|
|
||||||
|
|
||||||
uint32 mouse_down;
|
|
||||||
|
|
||||||
int32 dx;
|
int32 dx;
|
||||||
int32 dy;
|
int32 dy;
|
||||||
|
|
||||||
uint32 x;
|
uint32 x;
|
||||||
uint32 y;
|
uint32 y;
|
||||||
|
|
||||||
int16 wheel_delta = 0;
|
|
||||||
int16 hwheel_delta = 0;
|
|
||||||
|
|
||||||
uint64 keys_down_time[MAX_MOUSE_PRESSES + MAX_KEY_PRESSES];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Input {
|
struct Input {
|
||||||
// Device
|
// Device
|
||||||
bool is_connected = false;
|
bool is_connected = false;
|
||||||
byte type = INPUT_TYPE_OTHER;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// @todo maybe replace with id?!
|
// @todo maybe replace with id?!
|
||||||
// -> remove _WIN32 section
|
// -> remove _WIN32 section
|
||||||
HANDLE handle_keyboard;
|
HANDLE handle_keyboard;
|
||||||
HANDLE handle_mouse;
|
HANDLE handle_mouse;
|
||||||
|
HANDLE handle_controller;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool state_change_button = false;
|
bool state_change_button = false;
|
||||||
bool state_change_mouse = false;
|
bool state_change_mouse = false;
|
||||||
bool state_change_mouse_button = true;
|
|
||||||
|
|
||||||
bool mouse_movement;
|
bool mouse_movement;
|
||||||
|
|
||||||
InputState state;
|
InputState state;
|
||||||
InputMapping input_mapping;
|
InputMapping input_mapping;
|
||||||
|
|
||||||
// @todo we probably don't need this
|
|
||||||
InputState state_old;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ControllerInput {
|
|
||||||
uint32 id = 0;
|
|
||||||
bool is_connected = false;
|
|
||||||
|
|
||||||
// After handling the state change the game loop should set this to false
|
|
||||||
bool state_change = false;
|
|
||||||
|
|
||||||
// @question maybe make part of button
|
|
||||||
bool up = false;
|
|
||||||
bool down = false;
|
|
||||||
bool left = false;
|
|
||||||
bool right = false;
|
|
||||||
|
|
||||||
byte trigger_old[4];
|
|
||||||
byte trigger[4];
|
|
||||||
|
|
||||||
// these are bitfields
|
|
||||||
uint16 button_old;
|
|
||||||
uint16 button;
|
|
||||||
|
|
||||||
int16 stickl_x = 0;
|
|
||||||
int16 stickl_y = 0;
|
|
||||||
bool stickl_press = false;
|
|
||||||
|
|
||||||
int16 stickr_x = 0;
|
|
||||||
int16 stickr_y = 0;
|
|
||||||
bool stickr_press = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void mouse_backup_state(Input* input)
|
void input_clean_state(InputState* state)
|
||||||
{
|
{
|
||||||
input->state_old.mouse_down = input->state.mouse_down;
|
for (int i = 0; i < MAX_KEY_STATES; ++i) {
|
||||||
|
if (state->state_keys[i].key_state == KEY_STATE_RELEASED) {
|
||||||
input->state_old.x = input->state.x;
|
state->state_keys[i].key_id = 0;
|
||||||
input->state_old.y = input->state.y;
|
}
|
||||||
|
}
|
||||||
input->state_old.wheel_delta = input->state.wheel_delta;
|
|
||||||
input->state_old.hwheel_delta = input->state.wheel_delta;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void keyboard_clean_state(InputState* state)
|
bool input_action_exists(const InputState* state, uint16 key)
|
||||||
{
|
{
|
||||||
memset(state->keys_down, 0, MAX_KEY_PRESSES * sizeof(uint8));
|
return state->state_keys[0].key_id == key
|
||||||
memset(state->keys_up, 0, MAX_KEY_PRESSES * sizeof(uint8));
|
|| state->state_keys[1].key_id == key
|
||||||
memset(state->keys_down_time, 0, (MAX_MOUSE_PRESSES + MAX_KEY_PRESSES) * sizeof(uint64));
|
|| state->state_keys[2].key_id == key
|
||||||
|
|| state->state_keys[3].key_id == key
|
||||||
|
|| state->state_keys[4].key_id == key
|
||||||
|
|| state->state_keys[4].key_id == key
|
||||||
|
|| state->state_keys[5].key_id == key
|
||||||
|
|| state->state_keys[6].key_id == key
|
||||||
|
|| state->state_keys[7].key_id == key
|
||||||
|
|| state->state_keys[8].key_id == key
|
||||||
|
|| state->state_keys[9].key_id == key;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
void keyboard_backup_state(Input* input)
|
bool input_is_down(const InputState* state, uint16 key)
|
||||||
{
|
{
|
||||||
memcpy(input->state_old.keys_down, input->state.keys_down, MAX_KEY_PRESSES * sizeof(uint8));
|
return (state->state_keys[0].key_id == key && state->state_keys[0].key_state < KEY_STATE_RELEASED)
|
||||||
memcpy(input->state_old.keys_up, input->state.keys_up, MAX_KEY_PRESSES * sizeof(uint8));
|
|| (state->state_keys[1].key_id == key && state->state_keys[1].key_state < KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[2].key_id == key && state->state_keys[2].key_state < KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[3].key_id == key && state->state_keys[3].key_state < KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[4].key_id == key && state->state_keys[4].key_state < KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[4].key_id == key && state->state_keys[4].key_state < KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[5].key_id == key && state->state_keys[5].key_state < KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[6].key_id == key && state->state_keys[6].key_state < KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[7].key_id == key && state->state_keys[7].key_state < KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[8].key_id == key && state->state_keys[8].key_state < KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[9].key_id == key && state->state_keys[9].key_state < KEY_STATE_RELEASED);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool keyboard_is_pressed(const InputState* state, byte key)
|
bool input_is_pressed(const InputState* state, uint16 key)
|
||||||
{
|
{
|
||||||
return state->keys_down[0] == key
|
return (state->state_keys[0].key_id == key && state->state_keys[0].key_state == KEY_STATE_PRESSED)
|
||||||
|| state->keys_down[1] == key
|
|| (state->state_keys[1].key_id == key && state->state_keys[1].key_state == KEY_STATE_PRESSED)
|
||||||
|| state->keys_down[2] == key
|
|| (state->state_keys[2].key_id == key && state->state_keys[2].key_state == KEY_STATE_PRESSED)
|
||||||
|| state->keys_down[3] == key
|
|| (state->state_keys[3].key_id == key && state->state_keys[3].key_state == KEY_STATE_PRESSED)
|
||||||
|| state->keys_down[4] == key;
|
|| (state->state_keys[4].key_id == key && state->state_keys[4].key_state == KEY_STATE_PRESSED)
|
||||||
|
|| (state->state_keys[4].key_id == key && state->state_keys[4].key_state == KEY_STATE_PRESSED)
|
||||||
|
|| (state->state_keys[5].key_id == key && state->state_keys[5].key_state == KEY_STATE_PRESSED)
|
||||||
|
|| (state->state_keys[6].key_id == key && state->state_keys[6].key_state == KEY_STATE_PRESSED)
|
||||||
|
|| (state->state_keys[7].key_id == key && state->state_keys[7].key_state == KEY_STATE_PRESSED)
|
||||||
|
|| (state->state_keys[8].key_id == key && state->state_keys[8].key_state == KEY_STATE_PRESSED)
|
||||||
|
|| (state->state_keys[9].key_id == key && state->state_keys[9].key_state == KEY_STATE_PRESSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool keyboard_is_released(const InputState* state, byte key)
|
bool input_is_held(const InputState* state, uint16 key)
|
||||||
{
|
{
|
||||||
return state->keys_up[0] == key
|
return (state->state_keys[0].key_id == key && state->state_keys[0].key_state == KEY_STATE_HELD)
|
||||||
|| state->keys_up[1] == key
|
|| (state->state_keys[1].key_id == key && state->state_keys[1].key_state == KEY_STATE_HELD)
|
||||||
|| state->keys_up[2] == key
|
|| (state->state_keys[2].key_id == key && state->state_keys[2].key_state == KEY_STATE_HELD)
|
||||||
|| state->keys_up[3] == key
|
|| (state->state_keys[3].key_id == key && state->state_keys[3].key_state == KEY_STATE_HELD)
|
||||||
|| state->keys_up[4] == key;
|
|| (state->state_keys[4].key_id == key && state->state_keys[4].key_state == KEY_STATE_HELD)
|
||||||
|
|| (state->state_keys[4].key_id == key && state->state_keys[4].key_state == KEY_STATE_HELD)
|
||||||
|
|| (state->state_keys[5].key_id == key && state->state_keys[5].key_state == KEY_STATE_HELD)
|
||||||
|
|| (state->state_keys[6].key_id == key && state->state_keys[6].key_state == KEY_STATE_HELD)
|
||||||
|
|| (state->state_keys[7].key_id == key && state->state_keys[7].key_state == KEY_STATE_HELD)
|
||||||
|
|| (state->state_keys[8].key_id == key && state->state_keys[8].key_state == KEY_STATE_HELD)
|
||||||
|
|| (state->state_keys[9].key_id == key && state->state_keys[9].key_state == KEY_STATE_HELD);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool keyboard_are_pressed(
|
bool input_is_released(const InputState* state, uint16 key)
|
||||||
|
{
|
||||||
|
return (state->state_keys[0].key_id == key && state->state_keys[0].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[1].key_id == key && state->state_keys[1].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[2].key_id == key && state->state_keys[2].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[3].key_id == key && state->state_keys[3].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[4].key_id == key && state->state_keys[4].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[4].key_id == key && state->state_keys[4].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[5].key_id == key && state->state_keys[5].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[6].key_id == key && state->state_keys[6].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[7].key_id == key && state->state_keys[7].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[8].key_id == key && state->state_keys[8].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[9].key_id == key && state->state_keys[9].key_state == KEY_STATE_RELEASED);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
bool input_was_down(const InputState* state, uint16 key)
|
||||||
|
{
|
||||||
|
return (state->state_keys[0].key_id == key && state->state_keys[0].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[1].key_id == key && state->state_keys[1].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[2].key_id == key && state->state_keys[2].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[3].key_id == key && state->state_keys[3].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[4].key_id == key && state->state_keys[4].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[4].key_id == key && state->state_keys[4].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[5].key_id == key && state->state_keys[5].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[6].key_id == key && state->state_keys[6].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[7].key_id == key && state->state_keys[7].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[8].key_id == key && state->state_keys[8].key_state == KEY_STATE_RELEASED)
|
||||||
|
|| (state->state_keys[9].key_id == key && state->state_keys[9].key_state == KEY_STATE_RELEASED);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
bool inputs_are_down(
|
||||||
const InputState* state,
|
const InputState* state,
|
||||||
byte key0, byte key1 = 0, byte key2 = 0, byte key3 = 0, byte key4 = 0
|
uint16 key0, uint16 key1 = 0, uint16 key2 = 0, uint16 key3 = 0, uint16 key4 = 0
|
||||||
) {
|
) {
|
||||||
return (key0 != 0 && keyboard_is_pressed(state, key0))
|
return (key0 != 0 && input_is_down(state, key0))
|
||||||
&& (key1 == 0 || keyboard_is_pressed(state, key1))
|
&& (key1 == 0 || input_is_down(state, key1))
|
||||||
&& (key2 == 0 || keyboard_is_pressed(state, key2))
|
&& (key2 == 0 || input_is_down(state, key2))
|
||||||
&& (key3 == 0 || keyboard_is_pressed(state, key3))
|
&& (key3 == 0 || input_is_down(state, key3))
|
||||||
&& (key4 == 0 || keyboard_is_pressed(state, key4));
|
&& (key4 == 0 || input_is_down(state, key4));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are binding hotkeys bi-directional
|
// We are binding hotkeys bi-directional
|
||||||
|
|
@ -209,32 +238,37 @@ input_add_hotkey(
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
int key0_offset = ((bool) (key0 & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS;
|
|
||||||
int key1_offset = ((bool) (key1 & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS;
|
|
||||||
int key2_offset = ((bool) (key2 & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS;
|
|
||||||
|
|
||||||
key0 = key0 & ~INPUT_KEYBOARD_PREFIX;
|
|
||||||
key1 = key1 & ~INPUT_KEYBOARD_PREFIX;
|
|
||||||
key2 = key2 & ~INPUT_KEYBOARD_PREFIX;
|
|
||||||
|
|
||||||
// Define required keys for hotkey
|
// Define required keys for hotkey
|
||||||
if (key0 != 0) {
|
if (key0 != 0) {
|
||||||
// Note: -1 since the hotkeys MUST start at 1 (0 is a special value for empty)
|
// Note: -1 since the hotkeys MUST start at 1 (0 is a special value for empty)
|
||||||
mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION] = (uint8) (key0 + key0_offset);
|
mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION] = (uint16) key0;
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key1 != 0) {
|
if (key1 != 0) {
|
||||||
// Note: -1 since the hotkeys MUST start at 1 (0 is a special value for empty)
|
// Note: -1 since the hotkeys MUST start at 1 (0 is a special value for empty)
|
||||||
mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + count] = (uint8) (key1 + key1_offset);
|
mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + count] = (uint16) key1;
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key2 != 0) {
|
if (key2 != 0) {
|
||||||
// Note: -1 since the hotkeys MUST start at 1 (0 is a special value for empty)
|
// Note: -1 since the hotkeys MUST start at 1 (0 is a special value for empty)
|
||||||
mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + count] = (uint8) (key2 + key2_offset);
|
mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + count] = (uint16) key2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int key0_offset = ((bool) (key0 & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS
|
||||||
|
+ ((bool) (key0 & INPUT_CONTROLLER_PREFIX)) * (MAX_MOUSE_KEYS + MAX_KEYBOARD_KEYS);
|
||||||
|
|
||||||
|
int key1_offset = ((bool) (key1 & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS
|
||||||
|
+ ((bool) (key1 & INPUT_CONTROLLER_PREFIX)) * (MAX_MOUSE_KEYS + MAX_KEYBOARD_KEYS);
|
||||||
|
|
||||||
|
int key2_offset = ((bool) (key2 & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS
|
||||||
|
+ ((bool) (key2 & INPUT_CONTROLLER_PREFIX)) * (MAX_MOUSE_KEYS + MAX_KEYBOARD_KEYS);
|
||||||
|
|
||||||
|
key0 = (key0 & ~(INPUT_KEYBOARD_PREFIX | INPUT_CONTROLLER_PREFIX));
|
||||||
|
key1 = (key1 & ~(INPUT_KEYBOARD_PREFIX | INPUT_CONTROLLER_PREFIX));
|
||||||
|
key2 = (key2 & ~(INPUT_KEYBOARD_PREFIX | INPUT_CONTROLLER_PREFIX));
|
||||||
|
|
||||||
// Bind key to hotkey
|
// Bind key to hotkey
|
||||||
for (int i = 0; i < MAX_KEY_TO_HOTKEY; ++i) {
|
for (int i = 0; i < MAX_KEY_TO_HOTKEY; ++i) {
|
||||||
if (key0 == 0 && key1 == 0 && key2 == 0) {
|
if (key0 == 0 && key1 == 0 && key2 == 0) {
|
||||||
|
|
@ -270,64 +304,67 @@ bool hotkey_is_active(const InputState* state, uint8 hotkey)
|
||||||
|
|
||||||
// similar to hotkey_is_active but instead of just performing a lookup in the input_hotkey_state created results
|
// similar to hotkey_is_active but instead of just performing a lookup in the input_hotkey_state created results
|
||||||
// this is actively checking the current input state (not the hotkey state)
|
// this is actively checking the current input state (not the hotkey state)
|
||||||
// @performance This seems like a much better simpler solution no?
|
|
||||||
// However, it is probably a slower solution after calling this function many times?
|
|
||||||
// Remember, we would call this function for almost every possible hotkey (depending on context) per frame
|
|
||||||
inline
|
inline
|
||||||
bool hotkey_is_pressed(const InputState* __restrict state, const InputMapping* __restrict mapping, uint8 hotkey)
|
bool hotkey_keys_are_active(const InputState* __restrict state, const InputMapping* __restrict mapping, uint8 hotkey)
|
||||||
{
|
{
|
||||||
uint8 key0 = mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION];
|
uint16 key0 = mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION];
|
||||||
uint8 key1 = mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + 1];
|
uint16 key1 = mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + 1];
|
||||||
uint8 key2 = mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + 2];
|
uint16 key2 = mapping->hotkeys[(hotkey - 1) * MAX_HOTKEY_COMBINATION + 2];
|
||||||
|
|
||||||
bool is_pressed = false;
|
// This may seem a little bit confusing but we don't care if a input key is down or up
|
||||||
if (key0 > MAX_MOUSE_KEYS) {
|
// Any state means it was used recently BUT NOT YET HANDLED
|
||||||
key0 -= MAX_MOUSE_KEYS;
|
// If it was handled it would've been removed (at least in case of RELEASED)
|
||||||
is_pressed = keyboard_is_pressed(state, key0);
|
// Therefore, if a key has a state -> treat it as if active
|
||||||
} else if (key0 > 0) {
|
bool is_active = input_action_exists(state, key0);
|
||||||
is_pressed = IS_BIT_SET_R2L(state->mouse_down, key0 - 1);
|
if (!is_active || key1 == 0) {
|
||||||
|
return is_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_pressed || key1 == 0) {
|
is_active &= input_action_exists(state, key1);
|
||||||
return is_pressed;
|
if (!is_active || key2 == 0) {
|
||||||
|
return is_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key1 > MAX_MOUSE_KEYS) {
|
return (is_active &= input_action_exists(state, key2));
|
||||||
key1 -= MAX_MOUSE_KEYS;
|
}
|
||||||
is_pressed &= keyboard_is_pressed(state, key1);
|
|
||||||
} else if (key1 > 0) {
|
inline
|
||||||
is_pressed &= IS_BIT_SET_R2L(state->mouse_down, key1 - 1);
|
void input_set_state(InputState* state, uint16 key_id, uint16 new_state)
|
||||||
|
{
|
||||||
|
InputKey* free_state = NULL;
|
||||||
|
bool action_required = true;
|
||||||
|
|
||||||
|
for (int j = 0; j < MAX_KEY_STATES; ++j) {
|
||||||
|
if (!free_state && state->state_keys[j].key_id == 0) {
|
||||||
|
free_state = &state->state_keys[j];
|
||||||
|
} else if (state->state_keys[j].key_id == key_id) {
|
||||||
|
state->state_keys[j].key_state = new_state;
|
||||||
|
action_required = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_pressed || key2 == 0) {
|
if (!action_required || !free_state) {
|
||||||
return is_pressed;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key2 > MAX_MOUSE_KEYS) {
|
free_state->key_id = key_id;
|
||||||
key2 -= MAX_MOUSE_KEYS;
|
free_state->key_state = new_state;
|
||||||
is_pressed &= keyboard_is_pressed(state, key2);
|
// @todo implement
|
||||||
} else if (key2 > 0) {
|
// free_state->time = 0;
|
||||||
is_pressed &= IS_BIT_SET_R2L(state->mouse_down, key2 - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_pressed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
input_hotkey_state(InputState* __restrict state, const InputMapping* mapping)
|
input_hotkey_state(InputState* __restrict state, const InputMapping* mapping)
|
||||||
{
|
{
|
||||||
// @bug isn't there a bug, MAX_KEY_PRESSES is the keyboard limit, what about additional mouse inputs?
|
|
||||||
|
|
||||||
memset(state->state_hotkeys, 0, sizeof(uint8) * MAX_KEY_PRESSES);
|
memset(state->state_hotkeys, 0, sizeof(uint8) * MAX_KEY_PRESSES);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
// @performance It would be nice if we could skip this loop by checking keyboard_changed similar to the mouse loop further down
|
|
||||||
// The problem is that this loop checks both mouse and keyboard
|
|
||||||
|
|
||||||
// Check every key down state
|
// Check every key down state
|
||||||
for (int down_state = 0; down_state < MAX_KEY_PRESSES; ++down_state) {
|
for (int key_state = 0; key_state < MAX_KEY_STATES; ++key_state) {
|
||||||
if (state->keys_down[down_state] == 0) {
|
if (state->state_keys[key_state].key_id == 0
|
||||||
|
|| state->state_keys[key_state].key_state == KEY_STATE_RELEASED
|
||||||
|
) {
|
||||||
// no key defined for this down state
|
// no key defined for this down state
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -335,7 +372,12 @@ input_hotkey_state(InputState* __restrict state, const InputMapping* mapping)
|
||||||
// Is a key defined for this state AND is at least one hotkey defined for this key
|
// Is a key defined for this state AND is at least one hotkey defined for this key
|
||||||
// If no hotkey is defined we don't care
|
// If no hotkey is defined we don't care
|
||||||
// Careful, remember MAX_MOUSE_KEYS offset
|
// Careful, remember MAX_MOUSE_KEYS offset
|
||||||
const uint8* hotkeys_for_key = mapping->keys[state->keys_down[down_state] + MAX_MOUSE_KEYS - 1];
|
InputKey* input = &state->state_keys[key_state];
|
||||||
|
int32 internal_key_id = (input->key_id & ~(INPUT_KEYBOARD_PREFIX | INPUT_CONTROLLER_PREFIX))
|
||||||
|
+ ((bool) (input->key_id & INPUT_KEYBOARD_PREFIX)) * MAX_MOUSE_KEYS
|
||||||
|
+ ((bool) (input->key_id & INPUT_CONTROLLER_PREFIX)) * (MAX_MOUSE_KEYS + MAX_KEYBOARD_KEYS);
|
||||||
|
|
||||||
|
const uint8* hotkeys_for_key = mapping->keys[internal_key_id - 1];
|
||||||
if (hotkeys_for_key[0] == 0) {
|
if (hotkeys_for_key[0] == 0) {
|
||||||
// no possible hotkey associated with this key
|
// no possible hotkey associated with this key
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -349,42 +391,7 @@ input_hotkey_state(InputState* __restrict state, const InputMapping* mapping)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_pressed = hotkey_is_pressed(state, mapping, hotkeys_for_key[possible_hotkey_idx]);
|
bool is_pressed = hotkey_keys_are_active(state, mapping, hotkeys_for_key[possible_hotkey_idx]);
|
||||||
|
|
||||||
// store active hotkey, if it is not already active
|
|
||||||
if (is_pressed && !hotkey_is_active(state, hotkeys_for_key[possible_hotkey_idx])) {
|
|
||||||
state->state_hotkeys[i] = hotkeys_for_key[possible_hotkey_idx];
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @performance we could also check if the mouse state even changed
|
|
||||||
if (state->mouse_down == 0 || i >= MAX_KEY_PRESSES) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We now also need to check if there are hotkeys for the mouse buttons
|
|
||||||
// Some are already handled in the previous section, but some might not be handled, since they are mouse only
|
|
||||||
// But this also means, that we ONLY have to search for mouse only hotkeys. It's impossible to find NEW matches with keyboard keys.
|
|
||||||
for (int down_state = 0; down_state < MAX_MOUSE_KEYS; ++down_state) {
|
|
||||||
if (!IS_BIT_SET_R2L(state->mouse_down, down_state)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8* hotkeys_for_key = mapping->keys[down_state];
|
|
||||||
if (hotkeys_for_key[0] == 0) {
|
|
||||||
// no possible hotkey associated with this key
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int possible_hotkey_idx = 0; possible_hotkey_idx < MAX_KEY_TO_HOTKEY; ++possible_hotkey_idx) {
|
|
||||||
// We only support a slimited amount of active hotkeys
|
|
||||||
if (i >= MAX_KEY_PRESSES) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_pressed = hotkey_is_pressed(state, mapping, hotkeys_for_key[possible_hotkey_idx]);
|
|
||||||
|
|
||||||
// store active hotkey, if it is not already active
|
// store active hotkey, if it is not already active
|
||||||
if (is_pressed && !hotkey_is_active(state, hotkeys_for_key[possible_hotkey_idx])) {
|
if (is_pressed && !hotkey_is_active(state, hotkeys_for_key[possible_hotkey_idx])) {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include "../../../utils/MathUtils.h"
|
#include "../../../utils/MathUtils.h"
|
||||||
#include "../../../memory/RingMemory.h"
|
#include "../../../memory/RingMemory.h"
|
||||||
#include "../../../memory/BufferMemory.h"
|
#include "../../../memory/BufferMemory.h"
|
||||||
|
#include "../../../stdlib/simd/SIMD_I8.h"
|
||||||
#include <winDNS.h>
|
#include <winDNS.h>
|
||||||
|
|
||||||
#define INPUT_MOUSE_BUTTON_1 1
|
#define INPUT_MOUSE_BUTTON_1 1
|
||||||
|
|
@ -46,6 +47,7 @@ int input_init(HWND hwnd, Input* __restrict states, RingMemory* ring)
|
||||||
|
|
||||||
int32 mouse_found = 0;
|
int32 mouse_found = 0;
|
||||||
int32 keyboard_found = 0;
|
int32 keyboard_found = 0;
|
||||||
|
int32 controller_found = 0;
|
||||||
|
|
||||||
int32 i;
|
int32 i;
|
||||||
for (i = 0; i < device_count; ++i) {
|
for (i = 0; i < device_count; ++i) {
|
||||||
|
|
@ -53,29 +55,85 @@ int input_init(HWND hwnd, Input* __restrict states, RingMemory* ring)
|
||||||
RID_DEVICE_INFO rdi;
|
RID_DEVICE_INFO rdi;
|
||||||
GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICEINFO, &rdi, &cb_size);
|
GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICEINFO, &rdi, &cb_size);
|
||||||
|
|
||||||
|
RAWINPUTDEVICE rid[1];
|
||||||
|
|
||||||
switch (rdi.dwType) {
|
switch (rdi.dwType) {
|
||||||
case RIM_TYPEMOUSE: {
|
case RIM_TYPEMOUSE: {
|
||||||
// @bug Would need fixing once we support controllers here
|
|
||||||
if (states[mouse_found].handle_mouse != NULL) {
|
if (states[mouse_found].handle_mouse != NULL) {
|
||||||
++mouse_found;
|
++mouse_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
states[mouse_found].handle_mouse = pRawInputDeviceList[i].hDevice;
|
states[mouse_found].handle_mouse = pRawInputDeviceList[i].hDevice;
|
||||||
states[mouse_found].is_connected = true;
|
states[mouse_found].is_connected = true;
|
||||||
states[mouse_found].type = INPUT_TYPE_MOUSE_KEYBOARD;
|
|
||||||
|
// Mouse
|
||||||
|
rid[0].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games?
|
||||||
|
rid[0].usUsage = 0x02;
|
||||||
|
rid[0].dwFlags = RIDEV_DEVNOTIFY;
|
||||||
|
rid[0].hwndTarget = hwnd;
|
||||||
|
|
||||||
|
if (!RegisterRawInputDevices((PCRAWINPUTDEVICE) rid, 1, sizeof(RAWINPUTDEVICE))) {
|
||||||
|
// @todo Log
|
||||||
|
ASSERT_SIMPLE(false);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
case RIM_TYPEKEYBOARD: {
|
case RIM_TYPEKEYBOARD: {
|
||||||
// @bug Would need fixing once we support controllers here (keyboard + controller in one input bug)
|
|
||||||
if (states[keyboard_found].handle_keyboard != NULL) {
|
if (states[keyboard_found].handle_keyboard != NULL) {
|
||||||
++keyboard_found;
|
++keyboard_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
states[keyboard_found].handle_keyboard = pRawInputDeviceList[i].hDevice;
|
states[keyboard_found].handle_keyboard = pRawInputDeviceList[i].hDevice;
|
||||||
states[keyboard_found].is_connected = true;
|
states[keyboard_found].is_connected = true;
|
||||||
states[keyboard_found].type = INPUT_TYPE_MOUSE_KEYBOARD;
|
|
||||||
|
// Keyboard
|
||||||
|
rid[0].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games?
|
||||||
|
rid[0].usUsage = 0x06;
|
||||||
|
rid[0].dwFlags = RIDEV_DEVNOTIFY;
|
||||||
|
rid[0].hwndTarget = hwnd;
|
||||||
|
|
||||||
|
if (!RegisterRawInputDevices((PCRAWINPUTDEVICE) rid, 1, sizeof(RAWINPUTDEVICE))) {
|
||||||
|
// @todo Log
|
||||||
|
ASSERT_SIMPLE(false);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
case RIM_TYPEHID: {
|
case RIM_TYPEHID: {
|
||||||
states[i].type = INPUT_TYPE_OTHER;
|
if (rdi.hid.usUsage == 0x05) {
|
||||||
|
if (states[controller_found].handle_controller != NULL) {
|
||||||
|
++controller_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
states[controller_found].handle_controller = pRawInputDeviceList[i].hDevice;
|
||||||
|
states[controller_found].is_connected = true;
|
||||||
|
|
||||||
|
// Gamepad
|
||||||
|
rid[0].usUsagePage = 0x01;
|
||||||
|
rid[0].usUsage = 0x05;
|
||||||
|
rid[0].dwFlags = RIDEV_DEVNOTIFY;
|
||||||
|
rid[0].hwndTarget = hwnd;
|
||||||
|
|
||||||
|
if (!RegisterRawInputDevices((PCRAWINPUTDEVICE) rid, 1, sizeof(RAWINPUTDEVICE))) {
|
||||||
|
// @todo Log
|
||||||
|
ASSERT_SIMPLE(false);
|
||||||
|
}
|
||||||
|
} else if (rdi.hid.usUsage == 0x04) {
|
||||||
|
if (states[controller_found].handle_controller != NULL) {
|
||||||
|
++controller_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
states[controller_found].handle_controller = pRawInputDeviceList[i].hDevice;
|
||||||
|
states[controller_found].is_connected = true;
|
||||||
|
|
||||||
|
// Joystick
|
||||||
|
rid[0].usUsagePage = 0x01;
|
||||||
|
rid[0].usUsage = 0x04;
|
||||||
|
rid[0].dwFlags = RIDEV_DEVNOTIFY;
|
||||||
|
rid[0].hwndTarget = hwnd;
|
||||||
|
|
||||||
|
if (!RegisterRawInputDevices((PCRAWINPUTDEVICE) rid, 1, sizeof(RAWINPUTDEVICE))) {
|
||||||
|
// @todo Log
|
||||||
|
ASSERT_SIMPLE(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
|
|
||||||
|
|
@ -83,37 +141,6 @@ int input_init(HWND hwnd, Input* __restrict states, RingMemory* ring)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RAWINPUTDEVICE rid[4];
|
|
||||||
|
|
||||||
// Mouse
|
|
||||||
rid[0].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games?
|
|
||||||
rid[0].usUsage = 0x02;
|
|
||||||
rid[0].dwFlags = RIDEV_DEVNOTIFY;
|
|
||||||
rid[0].hwndTarget = hwnd;
|
|
||||||
|
|
||||||
// Joystick
|
|
||||||
rid[1].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games?
|
|
||||||
rid[1].usUsage = 0x04;
|
|
||||||
rid[1].dwFlags = RIDEV_DEVNOTIFY;
|
|
||||||
rid[1].hwndTarget = hwnd;
|
|
||||||
|
|
||||||
// Gamepad
|
|
||||||
rid[2].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games?
|
|
||||||
rid[2].usUsage = 0x05;
|
|
||||||
rid[2].dwFlags = RIDEV_DEVNOTIFY;
|
|
||||||
rid[2].hwndTarget = hwnd;
|
|
||||||
|
|
||||||
// Keyboard
|
|
||||||
rid[3].usUsagePage = 0x01; // @todo doesn't work with 0x05 for games?
|
|
||||||
rid[3].usUsage = 0x06;
|
|
||||||
rid[3].dwFlags = RIDEV_DEVNOTIFY;
|
|
||||||
rid[3].hwndTarget = hwnd;
|
|
||||||
|
|
||||||
if (!RegisterRawInputDevices((PCRAWINPUTDEVICE) rid, 4, sizeof(RAWINPUTDEVICE))) {
|
|
||||||
// @todo Log
|
|
||||||
ASSERT_SIMPLE(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,7 +157,7 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count,
|
||||||
{
|
{
|
||||||
uint32 i = 0;
|
uint32 i = 0;
|
||||||
if (raw->header.dwType == RIM_TYPEMOUSE) {
|
if (raw->header.dwType == RIM_TYPEMOUSE) {
|
||||||
// @todo Change so we can directly access the correct state (maybe map handle address to index?)
|
// @performance Change so we can directly access the correct state (maybe map handle address to index?)
|
||||||
while (i < state_count
|
while (i < state_count
|
||||||
&& states[i].handle_mouse != raw->header.hDevice
|
&& states[i].handle_mouse != raw->header.hDevice
|
||||||
) {
|
) {
|
||||||
|
|
@ -142,42 +169,44 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raw->data.mouse.usButtonFlags) {
|
if (raw->data.mouse.usButtonFlags) {
|
||||||
// @question should all of these be else ifs?
|
uint16 new_state;
|
||||||
|
uint16 button;
|
||||||
|
|
||||||
if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) {
|
if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) {
|
||||||
states[i].state.mouse_down |= INPUT_MOUSE_BUTTON_1;
|
new_state = KEY_STATE_PRESSED;
|
||||||
states[i].state.keys_down_time[0] = time;
|
button = 1;
|
||||||
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) {
|
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) {
|
||||||
states[i].state.mouse_down &= ~INPUT_MOUSE_BUTTON_1;
|
new_state = KEY_STATE_RELEASED;
|
||||||
}
|
button = 1;
|
||||||
|
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) {
|
||||||
if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) {
|
new_state = KEY_STATE_PRESSED;
|
||||||
states[i].state.mouse_down |= INPUT_MOUSE_BUTTON_2;
|
button = 2;
|
||||||
states[i].state.keys_down_time[1] = time;
|
|
||||||
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) {
|
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) {
|
||||||
states[i].state.mouse_down &= ~INPUT_MOUSE_BUTTON_2;
|
new_state = KEY_STATE_RELEASED;
|
||||||
}
|
button = 2;
|
||||||
|
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) {
|
||||||
if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) {
|
new_state = KEY_STATE_PRESSED;
|
||||||
states[i].state.mouse_down |= INPUT_MOUSE_BUTTON_3;
|
button = 3;
|
||||||
states[i].state.keys_down_time[2] = time;
|
|
||||||
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) {
|
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) {
|
||||||
states[i].state.mouse_down &= ~INPUT_MOUSE_BUTTON_3;
|
new_state = KEY_STATE_RELEASED;
|
||||||
}
|
button = 3;
|
||||||
|
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) {
|
||||||
if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) {
|
new_state = KEY_STATE_PRESSED;
|
||||||
states[i].state.mouse_down |= INPUT_MOUSE_BUTTON_4;
|
button = 4;
|
||||||
states[i].state.keys_down_time[3] = time;
|
|
||||||
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) {
|
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) {
|
||||||
states[i].state.mouse_down &= ~INPUT_MOUSE_BUTTON_4;
|
new_state = KEY_STATE_RELEASED;
|
||||||
}
|
button = 4;
|
||||||
|
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) {
|
||||||
if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) {
|
new_state = KEY_STATE_PRESSED;
|
||||||
states[i].state.mouse_down |= INPUT_MOUSE_BUTTON_5;
|
button = 5;
|
||||||
states[i].state.keys_down_time[4] = time;
|
|
||||||
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) {
|
} else if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) {
|
||||||
states[i].state.mouse_down &= ~INPUT_MOUSE_BUTTON_5;
|
new_state = KEY_STATE_RELEASED;
|
||||||
|
button = 5;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* @todo implement
|
||||||
if (raw->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) {
|
if (raw->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) {
|
||||||
states[i].state.wheel_delta += raw->data.mouse.usButtonData;
|
states[i].state.wheel_delta += raw->data.mouse.usButtonData;
|
||||||
}
|
}
|
||||||
|
|
@ -185,15 +214,15 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count,
|
||||||
if (raw->data.mouse.usButtonFlags & RI_MOUSE_HWHEEL) {
|
if (raw->data.mouse.usButtonFlags & RI_MOUSE_HWHEEL) {
|
||||||
states[i].state.hwheel_delta += raw->data.mouse.usButtonData;
|
states[i].state.hwheel_delta += raw->data.mouse.usButtonData;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
states[i].state_change_mouse = true;
|
|
||||||
states[i].state_change_mouse_button = true;
|
|
||||||
|
|
||||||
// @question is mouse wheel really considered a button change?
|
// @question is mouse wheel really considered a button change?
|
||||||
states[i].state_change_button = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (states[i].mouse_movement) {
|
button |= INPUT_MOUSE_PREFIX;
|
||||||
|
|
||||||
|
input_set_state(&states[i].state, button, new_state);
|
||||||
|
states[i].state_change_button = true;
|
||||||
|
} else if (states[i].mouse_movement) {
|
||||||
// do we want to handle mouse movement for every individual movement, or do we want to pull it
|
// do we want to handle mouse movement for every individual movement, or do we want to pull it
|
||||||
if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
|
if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
|
||||||
RECT rect;
|
RECT rect;
|
||||||
|
|
@ -241,65 +270,67 @@ void input_raw_handle(RAWINPUT* __restrict raw, Input* states, int state_count,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo change to MakeCode instead of VKey
|
int16 new_state = -1;
|
||||||
// @performance Some of the things down here seem unneccessary. We shouldn't have to loop all elements!
|
|
||||||
if (raw->data.keyboard.Flags == RI_KEY_BREAK) {
|
if (raw->data.keyboard.Flags == RI_KEY_BREAK) {
|
||||||
// Key is already released
|
new_state = KEY_STATE_RELEASED;
|
||||||
if (keyboard_is_released(&states[i].state, (uint8) raw->data.keyboard.VKey)) {
|
|
||||||
for (int j = 0; j < MAX_KEY_PRESSES; ++j) {
|
|
||||||
if (states[i].state.keys_down[j] == (uint8) raw->data.keyboard.VKey) {
|
|
||||||
states[i].state.keys_down[j] = 0;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty = true;
|
|
||||||
for (int j = 0; j < MAX_KEY_PRESSES; ++j) {
|
|
||||||
if (empty && states[i].state.keys_up[j] == 0) {
|
|
||||||
states[i].state.keys_up[j] = (uint8) raw->data.keyboard.VKey;
|
|
||||||
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove pressed key
|
|
||||||
if (states[i].state.keys_down[j] == (uint8) raw->data.keyboard.VKey) {
|
|
||||||
states[i].state.keys_down[j] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (raw->data.keyboard.Flags == RI_KEY_MAKE) {
|
} else if (raw->data.keyboard.Flags == RI_KEY_MAKE) {
|
||||||
// Key is already released
|
new_state = KEY_STATE_PRESSED;
|
||||||
if (keyboard_is_pressed(&states[i].state, (uint8) raw->data.keyboard.VKey)) {
|
|
||||||
for (int j = 0; j < MAX_KEY_PRESSES; ++j) {
|
|
||||||
if (states[i].state.keys_up[j] == (uint8) raw->data.keyboard.VKey) {
|
|
||||||
states[i].state.keys_up[j] = 0;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty = true;
|
|
||||||
for (int j = 0; j < MAX_KEY_PRESSES; ++j) {
|
|
||||||
if (empty && states[i].state.keys_down[j] == 0) {
|
|
||||||
states[i].state.keys_down[j] = (uint8) raw->data.keyboard.VKey;
|
|
||||||
states[i].state.keys_down_time[MAX_MOUSE_PRESSES + j] = time;
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove released key
|
|
||||||
if (states[i].state.keys_up[j] == (uint8) raw->data.keyboard.VKey) {
|
|
||||||
states[i].state.keys_up[j] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_state < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo change to MakeCode instead of VKey
|
||||||
|
uint16 key = raw->data.keyboard.VKey | INPUT_KEYBOARD_PREFIX;
|
||||||
|
|
||||||
|
input_set_state(&states[i].state, key, new_state);
|
||||||
states[i].state_change_button = true;
|
states[i].state_change_button = true;
|
||||||
|
} else if (raw->header.dwType == RIM_TYPEHID) {
|
||||||
|
if (raw->header.dwSize > sizeof(RAWINPUT)) {
|
||||||
|
// @todo Find a way to handle most common controllers
|
||||||
|
// DualShock 3
|
||||||
|
// Dualshock 4
|
||||||
|
// DualSense
|
||||||
|
// Xbox
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
while (i < state_count
|
||||||
|
&& states[i].handle_controller != raw->header.hDevice
|
||||||
|
) {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= state_count || !states[i].is_connected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @performance The code below is horrible, we need to probably make it controller dependant
|
||||||
|
// Sometimes a controller may have a time component or a gyro which results in the controller
|
||||||
|
// constantly sending input data
|
||||||
|
|
||||||
|
// @todo implement actual step usage
|
||||||
|
bool is_same = simd_compare(
|
||||||
|
raw->data.hid.bRawData,
|
||||||
|
states[i].state.controller_state,
|
||||||
|
raw->header.dwSize - sizeof(RAWINPUT),
|
||||||
|
8
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!is_same) {
|
||||||
|
memcpy(states[i].state.controller_state, raw->data.hid.bRawData, raw->header.dwSize - sizeof(RAWINPUT));
|
||||||
|
|
||||||
|
char buffer[100];
|
||||||
|
int j = 0;
|
||||||
|
for (j = 0; j < raw->header.dwSize - sizeof(RAWINPUT); ++j) {
|
||||||
|
buffer[j] = raw->data.hid.bRawData[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_OUTPUT(buffer);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,35 @@ DWORD WINAPI XInputSetStateStub(DWORD, XINPUT_VIBRATION*) {
|
||||||
global_persist x_input_set_state* XInputSetState_ = XInputSetStateStub;
|
global_persist x_input_set_state* XInputSetState_ = XInputSetStateStub;
|
||||||
#define XInputSetState XInputSetState_
|
#define XInputSetState XInputSetState_
|
||||||
|
|
||||||
|
struct ControllerInput {
|
||||||
|
uint32 id = 0;
|
||||||
|
bool is_connected = false;
|
||||||
|
|
||||||
|
// After handling the state change the game loop should set this to false
|
||||||
|
bool state_change = false;
|
||||||
|
|
||||||
|
// @question maybe make part of button
|
||||||
|
bool up = false;
|
||||||
|
bool down = false;
|
||||||
|
bool left = false;
|
||||||
|
bool right = false;
|
||||||
|
|
||||||
|
byte trigger_old[4];
|
||||||
|
byte trigger[4];
|
||||||
|
|
||||||
|
// these are bitfields
|
||||||
|
uint16 button_old;
|
||||||
|
uint16 button;
|
||||||
|
|
||||||
|
int16 stickl_x = 0;
|
||||||
|
int16 stickl_y = 0;
|
||||||
|
bool stickl_press = false;
|
||||||
|
|
||||||
|
int16 stickr_x = 0;
|
||||||
|
int16 stickr_y = 0;
|
||||||
|
bool stickr_press = false;
|
||||||
|
};
|
||||||
|
|
||||||
void xinput_load() {
|
void xinput_load() {
|
||||||
HMODULE lib = LoadLibraryExA((LPCSTR) "xinput1_4.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
HMODULE lib = LoadLibraryExA((LPCSTR) "xinput1_4.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||||
if(!lib) {
|
if(!lib) {
|
||||||
|
|
|
||||||
|
|
@ -459,7 +459,7 @@ inline int8_32 operator<=(int8_32 a, int8_32 b)
|
||||||
inline int8_64 operator<=(int8_64 a, int8_64 b)
|
inline int8_64 operator<=(int8_64 a, int8_64 b)
|
||||||
{
|
{
|
||||||
int8_64 simd;
|
int8_64 simd;
|
||||||
simd.s = _mm512_mask_blend_epi8(_mm512_knot(_mm512_cmpgt_epi8_mask(b.s, a.s)), b.s, a.s);
|
simd.s = _mm512_mask_blend_epi8(_mm512_cmple_epi8_mask(a.s, b.s), b.s, a.s);
|
||||||
|
|
||||||
return simd;
|
return simd;
|
||||||
}
|
}
|
||||||
|
|
@ -737,23 +737,23 @@ inline int8_64 clamp(int8_64 min_value, int8_64 a, int8_64 max_value)
|
||||||
return simd_min(simd_max(a, min_value), max_value);
|
return simd_min(simd_max(a, min_value), max_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int8 which_true(int8_16 a)
|
inline int32 which_true(int8_16 a)
|
||||||
{
|
{
|
||||||
int8 which_true = _mm_movemask_epi8(a.s);
|
int32 which_true = _mm_movemask_epi8(a.s);
|
||||||
|
|
||||||
return which_true;
|
return which_true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int8 which_true(int8_32 a)
|
inline int32 which_true(int8_32 a)
|
||||||
{
|
{
|
||||||
int8 which_true = _mm256_movemask_epi8(a.s);
|
int32 which_true = _mm256_movemask_epi8(a.s);
|
||||||
|
|
||||||
return which_true;
|
return which_true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int8 which_true(int8_64 a)
|
inline int64 which_true(int8_64 a)
|
||||||
{
|
{
|
||||||
int8 which_true = _mm512_movepi8_mask(a.s);
|
int64 which_true = _mm512_movepi8_mask(a.s);
|
||||||
|
|
||||||
return which_true;
|
return which_true;
|
||||||
}
|
}
|
||||||
|
|
@ -853,4 +853,104 @@ f32 simd_mult(const int8* a, f32 b, int size, int steps)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
bool simd_compare_64(const byte* a, const byte* b)
|
||||||
|
{
|
||||||
|
__m256i chunk1_a = _mm256_loadu_si256((__m256i*) a);
|
||||||
|
__m256i chunk1_b = _mm256_loadu_si256((__m256i*) b);
|
||||||
|
|
||||||
|
__m256i chunk2_a = _mm256_loadu_si256((__m256i*) (a + 32));
|
||||||
|
__m256i chunk2_b = _mm256_loadu_si256((__m256i*) (b + 32));
|
||||||
|
|
||||||
|
__m256i result1 = _mm256_cmpeq_epi8(chunk1_a, chunk1_b);
|
||||||
|
__m256i result2 = _mm256_cmpeq_epi8(chunk2_a, chunk2_b);
|
||||||
|
|
||||||
|
__m256i combined = _mm256_and_si256(result1, result2);
|
||||||
|
|
||||||
|
return _mm256_testc_si256(combined, _mm256_set1_epi8(-1)) != 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int simd_compare(const byte* a, const byte* b, uint32 size, uint32 steps = 8) {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (steps == 16) {
|
||||||
|
if (size >= 128) {
|
||||||
|
__m512i a_16;
|
||||||
|
__m512i b_16;
|
||||||
|
__mmask64 result_mask;
|
||||||
|
|
||||||
|
for (; i <= size - 64; i += 64) { // 64 bytes per iteration
|
||||||
|
a_16 = _mm512_loadu_si512((__m512i*) a);
|
||||||
|
b_16 = _mm512_loadu_si512((__m512i*) b);
|
||||||
|
|
||||||
|
result_mask = _mm512_cmpeq_epi8_mask(a_16, b_16);
|
||||||
|
|
||||||
|
if (result_mask != 0xFFFFFFFFFFFFFFFF) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
a += 64;
|
||||||
|
b += 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size - i >= 64) {
|
||||||
|
return simd_compare(a, b, size - i, 8);
|
||||||
|
} else if (size - i >= 32) {
|
||||||
|
return simd_compare(a, b, size - i, 4);
|
||||||
|
}
|
||||||
|
} else if (steps == 8) {
|
||||||
|
if (size >= 64) {
|
||||||
|
__m256i a_8;
|
||||||
|
__m256i b_8;
|
||||||
|
__m256i result_8;
|
||||||
|
|
||||||
|
for (; i <= size - steps; i += steps) {
|
||||||
|
a_8 = _mm256_loadu_si256((__m256i*) a);
|
||||||
|
b_8 = _mm256_loadu_si256((__m256i*) b);
|
||||||
|
|
||||||
|
result_8 = _mm256_cmpeq_epi8(a_8, b_8);
|
||||||
|
|
||||||
|
if (_mm256_testc_si256(result_8, _mm256_set1_epi8(-1)) != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
a += steps;
|
||||||
|
b += steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size - i >= 32) {
|
||||||
|
return simd_compare(a, b, size - i, 4);
|
||||||
|
}
|
||||||
|
} else if (steps == 4) {
|
||||||
|
if (size >= 16) {
|
||||||
|
__m128i a_4;
|
||||||
|
__m128i b_4;
|
||||||
|
__m128i result_4;
|
||||||
|
|
||||||
|
for (; i <= size - steps; i += steps) {
|
||||||
|
a_4 = _mm_loadu_si128((__m128i*) a);
|
||||||
|
b_4 = _mm_loadu_si128((__m128i*) b);
|
||||||
|
|
||||||
|
result_4 = _mm_cmpeq_epi8(a_4, b_4);
|
||||||
|
|
||||||
|
if (_mm_movemask_epi8(result_4) != 0xFFFF) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
a += steps;
|
||||||
|
b += steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < size; ++i) {
|
||||||
|
if (*a++ != *b++) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Loading…
Reference in New Issue
Block a user