1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
6 #include "vg/vg_loader.h"
8 VG_STATIC
inline float vg_get_axis( const char *axis
);
9 VG_STATIC
inline int vg_get_button( const char *button
);
12 * Cannot be used in fixed update
14 VG_STATIC
inline int vg_get_button_down( const char *button
);
15 VG_STATIC
inline int vg_get_button_up( const char *button
);
19 k_button_state_down
= 1,
20 k_button_state_up
= 3,
21 k_button_state_pressed
= 2,
22 k_button_state_none
= 0
33 k_input_type_axis_norm
,
36 k_input_type_keyboard_key
,
37 k_input_type_mouse_button
, /* ? TODO */
38 k_input_type_gamepad_axis
,
39 k_input_type_gamepad_button
47 SDL_GameControllerAxis gamepad_axis
;
48 SDL_Keycode keyboard_positive
,
58 SDL_GameControllerButton gamepad_id
;
59 SDL_Keycode keyboard_id
;
71 struct input_binding named_inputs
[ 32 ];
72 u32 named_input_count
;
74 const char *controller_name
;
75 SDL_GameController
*controller_handle
; /* null if unplugged */
76 SDL_JoystickID controller_joystick_id
;
77 int controller_should_use_trackpad_look
;
79 float controller_axises
[ SDL_CONTROLLER_AXIS_MAX
];
80 int controller_buttons
[ SDL_CONTROLLER_BUTTON_MAX
];
84 VG_STATIC
void vg_create_unnamed_input( struct input_binding
*bind
,
85 enum input_type type
)
87 memset( bind
, 0, sizeof(struct input_binding
) );
89 bind
->name
= "API DEFINED";
93 bind
->axis
.gamepad_axis
= -1;
94 bind
->axis
.keyboard_positive
= -1;
95 bind
->axis
.keyboard_negative
= -1;
96 bind
->button
.gamepad_id
= -1;
97 bind
->button
.keyboard_id
= -1;
100 VG_STATIC
struct input_binding
*vg_create_named_input( const char *name
,
101 enum input_type type
)
103 struct input_binding
*bind
=
104 &vg_input
.named_inputs
[ vg_input
.named_input_count
++ ];
105 memset( bind
, 0, sizeof(struct input_binding
) );
111 bind
->axis
.gamepad_axis
= -1;
112 bind
->axis
.keyboard_positive
= -1;
113 bind
->axis
.keyboard_negative
= -1;
114 bind
->button
.gamepad_id
= -1;
115 bind
->button
.keyboard_id
= -1;
120 VG_STATIC
struct input_binding
*vg_get_named_input( const char *name
)
122 if( name
[0] == '+' || name
[0] == '-' )
125 for( u32 i
=0; i
<vg_input
.named_input_count
; i
++ )
127 struct input_binding
*bind
= &vg_input
.named_inputs
[i
];
128 if( !strcmp( bind
->name
, name
) )
137 enum input_type type
;
142 vg_all_bindable_inputs
[] =
144 {k_input_type_keyboard_key
, "space", SDLK_SPACE
},
145 {k_input_type_keyboard_key
, ";", SDLK_SEMICOLON
},
146 {k_input_type_keyboard_key
, "-", SDLK_MINUS
},
147 {k_input_type_keyboard_key
, ".", SDLK_PERIOD
},
148 {k_input_type_keyboard_key
, ",", SDLK_COMMA
},
149 {k_input_type_keyboard_key
, "=", SDLK_EQUALS
},
150 {k_input_type_keyboard_key
, "[", SDLK_LEFTBRACKET
},
151 {k_input_type_keyboard_key
, "]", SDLK_RIGHTBRACKET
},
152 {k_input_type_keyboard_key
, "left", SDLK_LEFT
},
153 {k_input_type_keyboard_key
, "right", SDLK_RIGHT
},
154 {k_input_type_keyboard_key
, "up", SDLK_UP
},
155 {k_input_type_keyboard_key
, "down", SDLK_DOWN
},
156 {k_input_type_keyboard_key
, "shift", SDLK_LSHIFT
},
157 {k_input_type_keyboard_key
, "control", SDLK_LCTRL
},
158 {k_input_type_keyboard_key
, "\2enter", SDLK_RETURN
},
159 {k_input_type_keyboard_key
, "\2escape", SDLK_ESCAPE
},
161 {k_input_type_gamepad_axis
, "gp-lt", SDL_CONTROLLER_AXIS_TRIGGERLEFT
},
162 {k_input_type_gamepad_axis
, "gp-rt", SDL_CONTROLLER_AXIS_TRIGGERRIGHT
},
163 {k_input_type_gamepad_axis
, "gp-ls-h", SDL_CONTROLLER_AXIS_LEFTX
},
164 {k_input_type_gamepad_axis
, "gp-ls-v", SDL_CONTROLLER_AXIS_LEFTY
},
165 {k_input_type_gamepad_axis
, "gp-rs-h", SDL_CONTROLLER_AXIS_RIGHTX
},
166 {k_input_type_gamepad_axis
, "gp-rs-v", SDL_CONTROLLER_AXIS_RIGHTY
},
168 {k_input_type_gamepad_button
, "gp-a", SDL_CONTROLLER_BUTTON_A
},
169 {k_input_type_gamepad_button
, "gp-b", SDL_CONTROLLER_BUTTON_B
},
170 {k_input_type_gamepad_button
, "gp-x", SDL_CONTROLLER_BUTTON_X
},
171 {k_input_type_gamepad_button
, "gp-y", SDL_CONTROLLER_BUTTON_Y
},
172 {k_input_type_gamepad_button
, "gp-rb", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
},
173 {k_input_type_gamepad_button
, "gp-lb", SDL_CONTROLLER_BUTTON_LEFTSHOULDER
},
174 {k_input_type_gamepad_button
, "gp-rs", SDL_CONTROLLER_BUTTON_RIGHTSTICK
},
175 {k_input_type_gamepad_button
, "gp-ls", SDL_CONTROLLER_BUTTON_LEFTSTICK
},
176 {k_input_type_gamepad_button
, "gp-dpad-down", SDL_CONTROLLER_BUTTON_DPAD_DOWN
},
177 {k_input_type_gamepad_button
, "gp-dpad-left", SDL_CONTROLLER_BUTTON_DPAD_LEFT
},
178 {k_input_type_gamepad_button
,"gp-dpad-right",SDL_CONTROLLER_BUTTON_DPAD_RIGHT
},
179 {k_input_type_gamepad_button
, "gp-dpad-up", SDL_CONTROLLER_BUTTON_DPAD_UP
},
180 {k_input_type_gamepad_button
, "\2gp-menu", SDL_CONTROLLER_BUTTON_BACK
}
183 VG_STATIC
const char *vg_input_to_str( u32 input
, enum input_type input_type
)
188 if( input_type
== k_input_type_keyboard_key
)
190 if( (input
>= SDLK_a
) && (input
<= SDLK_z
) )
192 return &"a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0k\0l\0m\0n\0o\0p\0"
193 "q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0"[(input
-SDLK_a
)*2];
196 if( (input
>= SDLK_0
) && (input
<= SDLK_9
) )
198 return &"0\0" "1\0" "2\0" "3\0" "4\0"
199 "5\0" "6\0" "7\0" "8\0" "9\0"[(input
-SDLK_0
)*2];
203 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ )
205 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
207 if( (desc
->type
== input_type
) && (desc
->id
== input
) )
214 VG_STATIC
enum input_type
vg_str_to_input( const char *str
, u32
*input
)
219 return k_input_type_unknown
;
222 u32 len
= strlen(str
);
227 return k_input_type_unknown
;
234 if( (uch
>= (u8
)'a') && (uch
<= (u8
)'z') )
236 *input
= SDLK_a
+ (uch
-(u8
)'a');
237 return k_input_type_keyboard_key
;
240 if( (uch
>= (u8
)'0') && (uch
<= (u8
)'9') )
242 *input
= SDLK_0
+ (uch
-(u8
)'0');
243 return k_input_type_keyboard_key
;
247 for( int i
=0; i
<vg_list_size(vg_all_bindable_inputs
); i
++ )
249 struct input_en
*desc
= &vg_all_bindable_inputs
[i
];
251 if( !strcmp( desc
->alias
, str
) )
259 return k_input_type_unknown
;
262 VG_STATIC
void vg_print_binding_info( struct input_binding
*bind
)
264 vg_info( " name: %s\n", bind
->name
);
265 vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
267 vg_info( " save this? %d\n", bind
->save_this
);
269 if( (bind
->type
== k_input_type_axis
) ||
270 (bind
->type
== k_input_type_axis_norm
) )
272 vg_info( " gamepad_axis: %s\n",
273 vg_input_to_str(bind
->axis
.gamepad_axis
, k_input_type_gamepad_axis
));
275 vg_info( " keyboard_positive: %s\n",
276 vg_input_to_str(bind
->axis
.keyboard_positive
,
277 k_input_type_keyboard_key
));
279 vg_info( " keyboard_negative: %s\n",
280 vg_input_to_str(bind
->axis
.keyboard_negative
,
281 k_input_type_keyboard_key
));
285 vg_info( " gamepad_id: %s\n",
286 vg_input_to_str(bind
->button
.gamepad_id
, k_input_type_gamepad_button
));
287 vg_info( " keyboard_id: %s\n",
288 vg_input_to_str(bind
->button
.keyboard_id
,
289 k_input_type_keyboard_key
));
293 VG_STATIC
void vg_apply_bind_str( struct input_binding
*bind
,
299 if( (mod
[0] == '-') || (mod
[0] == '+') )
307 if( (str
[0] == '-' ) )
314 enum input_type type
= vg_str_to_input( str
, &id
);
316 if( bind
->type
== k_input_type_button
)
320 vg_error( "Cannot use axis modifiers on button input!\n" );
326 vg_error( "Cannot invert button input!\n" );
330 if( type
== k_input_type_keyboard_key
)
331 bind
->button
.keyboard_id
= id
;
332 else if( type
== k_input_type_gamepad_button
)
333 bind
->button
.gamepad_id
= id
;
336 vg_error( "Unknown button or key '%s'\n", str
);
340 else if( (bind
->type
== k_input_type_axis
) ||
341 (bind
->type
== k_input_type_axis_norm
))
345 if( type
== k_input_type_keyboard_key
)
349 vg_error( "Cannot invert a keyboard key!\n" );
354 bind
->axis
.keyboard_positive
= id
;
356 bind
->axis
.keyboard_negative
= id
;
360 vg_error( "You can only bind keyboard keys to +- axises\n" );
366 if( type
== k_input_type_gamepad_axis
)
368 bind
->axis
.gamepad_inverted
= invert
;
369 bind
->axis
.gamepad_axis
= id
;
373 vg_error( "You can only bind gamepad axises to this\n" );
384 * bind -gp-ls-h horizontal
387 VG_STATIC
int vg_rebind_input_cmd( int argc
, const char *argv
[] )
391 vg_info( "Usage: bind jump x\n" );
392 vg_info( " bind -steerh j\n" );
393 vg_info( " bind steerh gp-ls-h\n" );
397 const char *str_bind_name
= argv
[0];
398 struct input_binding
*bind
= vg_get_named_input( str_bind_name
);
402 vg_error( "There is no bind with that name '%s'\n", str_bind_name
);
408 vg_print_binding_info( bind
);
414 const char *str_input_id
= argv
[1];
416 vg_apply_bind_str( bind
, str_bind_name
, str_input_id
);
423 VG_STATIC u8
vg_getkey( SDL_Keycode kc
)
425 SDL_Scancode sc
= SDL_GetScancodeFromKey( kc
);
426 return vg_input
.sdl_keys
[sc
];
429 VG_STATIC
void vg_input_update( u32 num
, struct input_binding
*binds
)
431 if( vg_console
.enabled
)
433 for( i32 i
=0; i
<num
; i
++ )
435 struct input_binding
*bind
= &binds
[i
];
437 if( bind
->type
== k_input_type_button
)
439 bind
->button
.prev
= bind
->button
.value
;
440 bind
->button
.value
= 0;
447 for( i32 i
=0; i
<num
; i
++ )
449 struct input_binding
*bind
= &binds
[i
];
451 if( bind
->type
== k_input_type_button
)
453 bind
->button
.prev
= bind
->button
.value
;
454 bind
->button
.value
= 0;
456 if( bind
->button
.gamepad_id
!= -1 )
457 bind
->button
.value
|=
458 vg_input
.controller_buttons
[ bind
->button
.gamepad_id
];
460 if( bind
->button
.keyboard_id
!= -1 )
461 bind
->button
.value
|= vg_getkey( bind
->button
.keyboard_id
);
463 else if( bind
->type
== k_input_type_axis
)
465 float keyboard_value
= 0.0f
,
466 gamepad_value
= 0.0f
;
468 if( bind
->axis
.keyboard_positive
!= -1 )
469 if( vg_getkey( bind
->axis
.keyboard_positive
) )
470 keyboard_value
+= 1.0f
;
472 if( bind
->axis
.keyboard_negative
!= -1 )
473 if( vg_getkey( bind
->axis
.keyboard_negative
) )
474 keyboard_value
-= 1.0f
;
476 if( bind
->axis
.gamepad_axis
!= -1 )
479 vg_input
.controller_axises
[ bind
->axis
.gamepad_axis
];
481 if( bind
->axis
.gamepad_inverted
)
482 gamepad_value
*= -1.0f
;
485 if( fabsf(gamepad_value
) <= 0.01f
)
486 gamepad_value
= 0.0f
;
488 if( fabsf(keyboard_value
) > fabsf(gamepad_value
) )
489 bind
->axis
.value
= keyboard_value
;
491 bind
->axis
.value
= gamepad_value
;
493 else if( bind
->type
== k_input_type_axis_norm
)
496 if( bind
->axis
.keyboard_positive
!= -1 )
497 if( vg_getkey( bind
->axis
.keyboard_positive
))
500 if( bind
->axis
.gamepad_axis
!= -1 )
501 value
= vg_maxf( value
,
502 vg_input
.controller_axises
[bind
->axis
.gamepad_axis
] );
504 bind
->axis
.value
= value
;
509 VG_STATIC
void vg_input_controller_event( SDL_Event
*ev
)
511 if( ev
->type
== SDL_CONTROLLERAXISMOTION
)
513 if( ev
->caxis
.which
== vg_input
.controller_joystick_id
)
515 vg_input
.controller_axises
[ ev
->caxis
.axis
] =
516 (float)ev
->caxis
.value
/ 32767.0f
;
519 else if( ev
->type
== SDL_CONTROLLERBUTTONDOWN
)
521 if( ev
->cbutton
.which
== vg_input
.controller_joystick_id
)
522 vg_input
.controller_buttons
[ ev
->cbutton
.button
] = 1;
524 else if( ev
->type
== SDL_CONTROLLERBUTTONUP
)
526 if( ev
->cbutton
.which
== vg_input
.controller_joystick_id
)
527 vg_input
.controller_buttons
[ ev
->cbutton
.button
] = 0;
531 VG_STATIC
void vg_try_attach_controller(void)
533 int joy_count
= SDL_NumJoysticks();
534 for( int i
=0; i
<joy_count
; i
++ )
536 if( SDL_IsGameController(i
) )
538 vg_input
.controller_handle
= SDL_GameControllerOpen(i
);
539 vg_input
.controller_joystick_id
= i
;
540 vg_success( "Attached game controller with joystick ID %d\n", i
);
547 VG_STATIC
void vg_update_inputs(void)
549 vg_input
.sdl_keys
= SDL_GetKeyboardState(NULL
);
551 if( vg_input
.controller_handle
)
553 if( !SDL_GameControllerGetAttached( vg_input
.controller_handle
) )
555 SDL_GameControllerClose( vg_input
.controller_handle
);
556 vg_input
.controller_handle
= NULL
;
560 if( !vg_input
.controller_handle
)
562 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
563 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
564 vg_try_attach_controller();
567 /* update all inputs */
568 vg_input_update( vg_input
.named_input_count
, vg_input
.named_inputs
);
571 VG_STATIC
int vg_console_enabled(void);
572 VG_STATIC
int vg_input_button_down( struct input_binding
*bind
)
574 if( bind
->button
.value
&& !bind
->button
.prev
)
579 VG_STATIC
void vg_input_init(void)
581 vg_acquire_thread_sync();
583 vg_function_push( (struct vg_cmd
)
586 .function
= vg_rebind_input_cmd
589 vg_info( "Checking for controller\n" );
590 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
592 int joy_count
= SDL_NumJoysticks();
593 for( int i
=0; i
<joy_count
; i
++ )
595 vg_info( "joystick %d: %s [gamecontroller: %d]\n",
596 i
, SDL_JoystickNameForIndex( i
),
597 SDL_IsGameController(i
) );
600 vg_try_attach_controller();
602 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERLEFT
] = -1.0f
;
603 vg_input
.controller_axises
[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
] = -1.0f
;
605 vg_release_thread_sync();
608 VG_STATIC
void vg_input_free(void)
610 if( vg_input
.controller_handle
)
612 SDL_GameControllerClose( vg_input
.controller_handle
);
613 vg_input
.controller_handle
= NULL
;