make menus controllable with joystick
In most menus, keyboard commands are synthesized from controller buttons, leveraging the existing axis-to-button translation. Menu controls are currently fixed: - button 0 (A) is confirm (Enter) - button 1 (B) is cancel (Esc) - button 2 (X) is switch (Space) - button 3 (Y) is delete (Delete) - axes 0 and 1 (main analog pad) maps to cursor keys - all hats (D-pads) map to cursor keys Title screens and credits can be confirmed with any joystick button or axis motion too.
This commit is contained in:
parent
096a678ff7
commit
c24864b180
|
@ -14,6 +14,7 @@
|
|||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include "joy.h"
|
||||
#include "key.h"
|
||||
#include "dxxerror.h"
|
||||
#include "timer.h"
|
||||
#include "console.h"
|
||||
|
@ -466,5 +467,48 @@ int apply_deadzone(int value, int deadzone)
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool joy_translate_menu_key(const d_event &event) {
|
||||
if (event.type != EVENT_JOYSTICK_BUTTON_DOWN)
|
||||
return false;
|
||||
#if DXX_MAX_BUTTONS_PER_JOYSTICK || DXX_MAX_HATS_PER_JOYSTICK || DXX_MAX_AXES_PER_JOYSTICK
|
||||
// Find out which button has been pressed by decoding the button
|
||||
// description text. This might not be the ideal way to do things,
|
||||
// but we currently don't have data structures that allow us to do
|
||||
// such a mapping in a saner way, so we'll take what we can get.
|
||||
auto &e = static_cast<const d_event_joystickbutton &>(event);
|
||||
Assert((e.button >= 0) && (e.button < joybutton_text.size()));
|
||||
const char* name = &joybutton_text[e.button][0];
|
||||
Assert((name[0] == 'J') && name[1] && (name[2] == ' '));
|
||||
name = &name[3]; // skip 'Jx ' prefix
|
||||
int key = 0;
|
||||
if (!strcmp(name, "B1")) { key = KEY_ENTER; }
|
||||
else if (!strcmp(name, "B2")) { key = KEY_ESC; }
|
||||
else if (!strcmp(name, "B3")) { key = KEY_SPACEBAR; }
|
||||
else if (!strcmp(name, "B4")) { key = KEY_DELETE; }
|
||||
else if (!strcmp(name, "+A1")) { key = KEY_LEFT; }
|
||||
else if (!strcmp(name, "-A1")) { key = KEY_RIGHT; }
|
||||
else if (!strcmp(name, "+A2")) { key = KEY_UP; }
|
||||
else if (!strcmp(name, "-A2")) { key = KEY_DOWN; }
|
||||
else if (name[0] == 'H')
|
||||
{ // handle 'Hxx' / hat motion
|
||||
Assert(name[1]);
|
||||
switch (name[2])
|
||||
{
|
||||
case 0201: key = KEY_LEFT; break;
|
||||
case 0177: key = KEY_RIGHT; break;
|
||||
case 0202: key = KEY_UP; break;
|
||||
case 0200: key = KEY_DOWN; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (key)
|
||||
{
|
||||
event_keycommand_send(key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -587,6 +587,11 @@ void key_flush()
|
|||
restore_sticky_key(keystate, key);
|
||||
}
|
||||
|
||||
void event_keycommand_send(int key) {
|
||||
const d_event_keycommand event{EVENT_KEY_COMMAND, unsigned(key)};
|
||||
event_send(event);
|
||||
}
|
||||
|
||||
int event_key_get(const d_event &event)
|
||||
{
|
||||
auto &e = static_cast<const d_event_keycommand &>(event);
|
||||
|
|
|
@ -36,6 +36,7 @@ extern void joy_init();
|
|||
extern void joy_close();
|
||||
const d_event_joystick_axis_value &event_joystick_get_axis(const d_event &event);
|
||||
extern void joy_flush();
|
||||
extern bool joy_translate_menu_key(const d_event &event);
|
||||
extern int event_joystick_get_button(const d_event &event);
|
||||
extern int apply_deadzone(int value, int deadzone);
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ extern fix64 keyd_time_when_last_pressed;
|
|||
extern std::array<unsigned char, KEY_BUFFER_SIZE> unicode_frame_buffer;
|
||||
|
||||
extern void key_flush(); // Clears the 256 char buffer
|
||||
extern void event_keycommand_send(int key); // synthesize a key command event from a keycode
|
||||
extern int event_key_get(const d_event &event); // Get the keycode from the EVENT_KEY_COMMAND event
|
||||
extern int event_key_get_raw(const d_event &event); // same as above but without mod states
|
||||
unsigned char key_ascii();
|
||||
|
|
|
@ -115,6 +115,9 @@ static window_event_result credits_handler(window *, const d_event &event, credi
|
|||
}
|
||||
break;
|
||||
|
||||
case EVENT_JOYSTICK_BUTTON_DOWN:
|
||||
return window_event_result::close;
|
||||
|
||||
case EVENT_IDLE:
|
||||
if (cr->done>NUM_LINES)
|
||||
{
|
||||
|
|
|
@ -655,6 +655,9 @@ static window_event_result kconfig_key_command(window *, const d_event &event, k
|
|||
namespace dsx {
|
||||
static window_event_result kconfig_handler(window *wind,const d_event &event, kc_menu *menu)
|
||||
{
|
||||
if (!menu->changing && joy_translate_menu_key(event))
|
||||
return window_event_result::handled;
|
||||
|
||||
switch (event.type)
|
||||
{
|
||||
case EVENT_WINDOW_ACTIVATED:
|
||||
|
|
|
@ -1491,6 +1491,9 @@ static window_event_result newmenu_draw(window *wind, newmenu *menu)
|
|||
|
||||
static window_event_result newmenu_handler(window *wind,const d_event &event, newmenu *menu)
|
||||
{
|
||||
if (joy_translate_menu_key(event))
|
||||
return window_event_result::handled;
|
||||
|
||||
if (menu->subfunction)
|
||||
{
|
||||
int rval = (*menu->subfunction)(menu, event, menu->userdata);
|
||||
|
@ -2110,6 +2113,9 @@ static window_event_result listbox_handler(window *wind,const d_event &event, li
|
|||
return rval; // event handled
|
||||
}
|
||||
|
||||
if (joy_translate_menu_key(event))
|
||||
return window_event_result::handled;
|
||||
|
||||
switch (event.type)
|
||||
{
|
||||
case EVENT_WINDOW_ACTIVATED:
|
||||
|
|
|
@ -406,6 +406,9 @@ static window_event_result scores_handler(window *wind,const d_event &event, sco
|
|||
}
|
||||
break;
|
||||
|
||||
case EVENT_JOYSTICK_BUTTON_DOWN:
|
||||
return window_event_result::close;
|
||||
|
||||
case EVENT_IDLE:
|
||||
timer_delay2(50);
|
||||
break;
|
||||
|
|
|
@ -141,6 +141,13 @@ static window_event_result title_handler(window *, const d_event &event, title_s
|
|||
}
|
||||
return result;
|
||||
|
||||
case EVENT_JOYSTICK_BUTTON_DOWN:
|
||||
if (ts->allow_keys)
|
||||
{
|
||||
return window_event_result::close;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_IDLE:
|
||||
timer_delay2(50);
|
||||
|
||||
|
@ -1529,6 +1536,24 @@ static window_event_result briefing_handler(window *, const d_event &event, brie
|
|||
}
|
||||
break;
|
||||
|
||||
case EVENT_JOYSTICK_BUTTON_DOWN:
|
||||
// using joy_translate_menu_key doesn't work here for unclear
|
||||
// reasons, so we build a reasonable facsimile right here
|
||||
if (event_joystick_get_button(event) == 1)
|
||||
return window_event_result::close;
|
||||
if (br->new_screen)
|
||||
{
|
||||
if (!new_briefing_screen(br, 0))
|
||||
{
|
||||
return window_event_result::close;
|
||||
}
|
||||
}
|
||||
else if (br->new_page)
|
||||
init_new_page(br);
|
||||
else
|
||||
br->delay_count = 0;
|
||||
return window_event_result::handled;
|
||||
|
||||
case EVENT_KEY_COMMAND:
|
||||
{
|
||||
int key = event_key_get(event);
|
||||
|
|
Loading…
Reference in a new issue