input: allow binding controller buttons/axes to more than 1 player
Issue #68
This commit is contained in:
parent
30b8c0d4d4
commit
4cb361bf9f
|
@ -55,188 +55,229 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
|
|||
_input_detected = nullptr;
|
||||
return true;
|
||||
}
|
||||
if (!input_mapper || _maple_port < 0 || _maple_port >= (int)ARRAY_SIZE(kcode))
|
||||
return false;
|
||||
DreamcastKey key = input_mapper->get_button_id(code);
|
||||
if (key == EMU_BTN_NONE)
|
||||
if (!input_mapper || _maple_port < 0 || _maple_port > (int)ARRAY_SIZE(kcode))
|
||||
return false;
|
||||
|
||||
if (key < 0x10000)
|
||||
auto handle_key = [&](u32 port, DreamcastKey key)
|
||||
{
|
||||
if (pressed)
|
||||
if (key == EMU_BTN_NONE)
|
||||
return false;
|
||||
|
||||
if (key < 0x10000)
|
||||
{
|
||||
kcode[_maple_port] &= ~(u16)key;
|
||||
// Avoid two opposite dpad keys being pressed simultaneously
|
||||
switch (key)
|
||||
if (pressed)
|
||||
{
|
||||
case DC_DPAD_UP:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_DOWN;
|
||||
break;
|
||||
case DC_DPAD_DOWN:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_UP;
|
||||
break;
|
||||
case DC_DPAD_LEFT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_RIGHT;
|
||||
break;
|
||||
case DC_DPAD_RIGHT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_LEFT;
|
||||
break;
|
||||
case DC_DPAD2_UP:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_DOWN;
|
||||
break;
|
||||
case DC_DPAD2_DOWN:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_UP;
|
||||
break;
|
||||
case DC_DPAD2_LEFT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_RIGHT;
|
||||
break;
|
||||
case DC_DPAD2_RIGHT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_LEFT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
kcode[port] &= ~(u16)key;
|
||||
// Avoid two opposite dpad keys being pressed simultaneously
|
||||
switch (key)
|
||||
{
|
||||
case DC_DPAD_UP:
|
||||
kcode[port] |= (u16)DC_DPAD_DOWN;
|
||||
break;
|
||||
case DC_DPAD_DOWN:
|
||||
kcode[port] |= (u16)DC_DPAD_UP;
|
||||
break;
|
||||
case DC_DPAD_LEFT:
|
||||
kcode[port] |= (u16)DC_DPAD_RIGHT;
|
||||
break;
|
||||
case DC_DPAD_RIGHT:
|
||||
kcode[port] |= (u16)DC_DPAD_LEFT;
|
||||
break;
|
||||
case DC_DPAD2_UP:
|
||||
kcode[port] |= (u16)DC_DPAD2_DOWN;
|
||||
break;
|
||||
case DC_DPAD2_DOWN:
|
||||
kcode[port] |= (u16)DC_DPAD2_UP;
|
||||
break;
|
||||
case DC_DPAD2_LEFT:
|
||||
kcode[port] |= (u16)DC_DPAD2_RIGHT;
|
||||
break;
|
||||
case DC_DPAD2_RIGHT:
|
||||
kcode[port] |= (u16)DC_DPAD2_LEFT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
kcode[port] |= (u16)key;
|
||||
#ifdef TEST_AUTOMATION
|
||||
if (record_input != NULL)
|
||||
fprintf(record_input, "%ld button %x %04x\n", sh4_sched_now64(), port, kcode[port]);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
kcode[_maple_port] |= (u16)key;
|
||||
#ifdef TEST_AUTOMATION
|
||||
if (record_input != NULL)
|
||||
fprintf(record_input, "%ld button %x %04x\n", sh4_sched_now64(), _maple_port, kcode[_maple_port]);
|
||||
#endif
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case EMU_BTN_ESCAPE:
|
||||
if (pressed)
|
||||
dc_exit();
|
||||
break;
|
||||
case EMU_BTN_MENU:
|
||||
if (pressed)
|
||||
gui_open_settings();
|
||||
break;
|
||||
case EMU_BTN_FFORWARD:
|
||||
if (pressed)
|
||||
fast_forward_mode = !fast_forward_mode;
|
||||
break;
|
||||
case EMU_BTN_TRIGGER_LEFT:
|
||||
lt[port] = pressed ? 255 : 0;
|
||||
break;
|
||||
case EMU_BTN_TRIGGER_RIGHT:
|
||||
rt[port] = pressed ? 255 : 0;
|
||||
break;
|
||||
case EMU_BTN_ANA_UP:
|
||||
joyy[port] = pressed ? -128 : 0;
|
||||
break;
|
||||
case EMU_BTN_ANA_DOWN:
|
||||
joyy[port] = pressed ? 127 : 0;
|
||||
break;
|
||||
case EMU_BTN_ANA_LEFT:
|
||||
joyx[port] = pressed ? -128 : 0;
|
||||
break;
|
||||
case EMU_BTN_ANA_RIGHT:
|
||||
joyx[port] = pressed ? 127 : 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG(INPUT, "%d: BUTTON %s %x -> %d. kcode=%x", port, pressed ? "down" : "up", code, key, kcode[port]);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool rc = false;
|
||||
if (_maple_port == 4)
|
||||
{
|
||||
for (int port = 0; port < 4; port++)
|
||||
{
|
||||
DreamcastKey key = input_mapper->get_button_id(port, code);
|
||||
rc = handle_key(port, key) || rc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case EMU_BTN_ESCAPE:
|
||||
if (pressed)
|
||||
dc_exit();
|
||||
break;
|
||||
case EMU_BTN_MENU:
|
||||
if (pressed)
|
||||
gui_open_settings();
|
||||
break;
|
||||
case EMU_BTN_FFORWARD:
|
||||
if (pressed)
|
||||
fast_forward_mode = !fast_forward_mode;
|
||||
break;
|
||||
case EMU_BTN_TRIGGER_LEFT:
|
||||
lt[_maple_port] = pressed ? 255 : 0;
|
||||
break;
|
||||
case EMU_BTN_TRIGGER_RIGHT:
|
||||
rt[_maple_port] = pressed ? 255 : 0;
|
||||
break;
|
||||
case EMU_BTN_ANA_UP:
|
||||
joyy[_maple_port] = pressed ? -128 : 0;
|
||||
break;
|
||||
case EMU_BTN_ANA_DOWN:
|
||||
joyy[_maple_port] = pressed ? 127 : 0;
|
||||
break;
|
||||
case EMU_BTN_ANA_LEFT:
|
||||
joyx[_maple_port] = pressed ? -128 : 0;
|
||||
break;
|
||||
case EMU_BTN_ANA_RIGHT:
|
||||
joyx[_maple_port] = pressed ? 127 : 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
DreamcastKey key = input_mapper->get_button_id(0, code);
|
||||
rc = handle_key(_maple_port, key);
|
||||
}
|
||||
|
||||
DEBUG_LOG(INPUT, "%d: BUTTON %s %x -> %d. kcode=%x", _maple_port, pressed ? "down" : "up", code, key, kcode[_maple_port]);
|
||||
return true;
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool GamepadDevice::gamepad_axis_input(u32 code, int value)
|
||||
{
|
||||
s32 v;
|
||||
if (input_mapper->get_axis_inverted(code))
|
||||
if (input_mapper->get_axis_inverted(0, code))
|
||||
v = (get_axis_min_value(code) + get_axis_range(code) - value) * 255 / get_axis_range(code) - 128;
|
||||
else
|
||||
v = (value - get_axis_min_value(code)) * 255 / get_axis_range(code) - 128; //-128 ... +127 range
|
||||
if (_input_detected != NULL && !_detecting_button
|
||||
if (_input_detected != NULL && !_detecting_button
|
||||
&& os_GetSeconds() >= _detection_start_time && (v >= 64 || v <= -64))
|
||||
{
|
||||
_input_detected(code);
|
||||
_input_detected = NULL;
|
||||
return true;
|
||||
}
|
||||
if (!input_mapper || _maple_port < 0 || _maple_port >= (int)ARRAY_SIZE(kcode))
|
||||
if (!input_mapper || _maple_port < 0 || _maple_port > 4)
|
||||
return false;
|
||||
DreamcastKey key = input_mapper->get_axis_id(code);
|
||||
|
||||
if ((int)key < 0x10000)
|
||||
auto handle_axis = [&](u32 port, DreamcastKey key)
|
||||
{
|
||||
kcode[_maple_port] |= key | (key << 1);
|
||||
if (v <= -64)
|
||||
kcode[_maple_port] &= ~key;
|
||||
else if (v >= 64)
|
||||
kcode[_maple_port] &= ~(key << 1);
|
||||
|
||||
// printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2));
|
||||
}
|
||||
else if (((int)key >> 16) == 1) // Triggers
|
||||
{
|
||||
//printf("T-AXIS %d Mapped to %d -> %d\n",key, value, v + 128);
|
||||
|
||||
if (key == DC_AXIS_LT)
|
||||
lt[_maple_port] = (u8)(v + 128);
|
||||
else if (key == DC_AXIS_RT)
|
||||
rt[_maple_port] = (u8)(v + 128);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (((int)key >> 16) == 2) // Analog axes
|
||||
{
|
||||
//printf("AXIS %d Mapped to %d -> %d\n", key, value, v);
|
||||
s8 *this_axis;
|
||||
s8 *other_axis;
|
||||
switch (key)
|
||||
if ((int)key < 0x10000)
|
||||
{
|
||||
case DC_AXIS_X:
|
||||
this_axis = &joyx[_maple_port];
|
||||
other_axis = &joyy[_maple_port];
|
||||
break;
|
||||
kcode[port] |= key | (key << 1);
|
||||
if (v <= -64)
|
||||
kcode[port] &= ~key;
|
||||
else if (v >= 64)
|
||||
kcode[port] &= ~(key << 1);
|
||||
|
||||
case DC_AXIS_Y:
|
||||
this_axis = &joyy[_maple_port];
|
||||
other_axis = &joyx[_maple_port];
|
||||
break;
|
||||
|
||||
case DC_AXIS_X2:
|
||||
this_axis = &joyrx[_maple_port];
|
||||
other_axis = &joyry[_maple_port];
|
||||
break;
|
||||
|
||||
case DC_AXIS_Y2:
|
||||
this_axis = &joyry[_maple_port];
|
||||
other_axis = &joyrx[_maple_port];
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
// printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2));
|
||||
}
|
||||
// Radial dead zone
|
||||
// FIXME compute both axes at the same time
|
||||
if ((float)(v * v + *other_axis * *other_axis) < input_mapper->dead_zone * input_mapper->dead_zone * 128.f * 128.f)
|
||||
else if (((int)key >> 16) == 1) // Triggers
|
||||
{
|
||||
*this_axis = 0;
|
||||
*other_axis = 0;
|
||||
//printf("T-AXIS %d Mapped to %d -> %d\n",key, value, v + 128);
|
||||
|
||||
if (key == DC_AXIS_LT)
|
||||
lt[port] = (u8)(v + 128);
|
||||
else if (key == DC_AXIS_RT)
|
||||
rt[port] = (u8)(v + 128);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (((int)key >> 16) == 2) // Analog axes
|
||||
{
|
||||
//printf("AXIS %d Mapped to %d -> %d\n", key, value, v);
|
||||
s8 *this_axis;
|
||||
s8 *other_axis;
|
||||
switch (key)
|
||||
{
|
||||
case DC_AXIS_X:
|
||||
this_axis = &joyx[port];
|
||||
other_axis = &joyy[port];
|
||||
break;
|
||||
|
||||
case DC_AXIS_Y:
|
||||
this_axis = &joyy[port];
|
||||
other_axis = &joyx[port];
|
||||
break;
|
||||
|
||||
case DC_AXIS_X2:
|
||||
this_axis = &joyrx[port];
|
||||
other_axis = &joyry[port];
|
||||
break;
|
||||
|
||||
case DC_AXIS_Y2:
|
||||
this_axis = &joyry[port];
|
||||
other_axis = &joyrx[port];
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
// Radial dead zone
|
||||
// FIXME compute both axes at the same time
|
||||
if ((float)(v * v + *other_axis * *other_axis) < input_mapper->dead_zone * input_mapper->dead_zone * 128.f * 128.f)
|
||||
{
|
||||
*this_axis = 0;
|
||||
*other_axis = 0;
|
||||
}
|
||||
else
|
||||
*this_axis = (s8)v;
|
||||
}
|
||||
else if (((int)key >> 16) == 4) // Map triggers to digital buttons
|
||||
{
|
||||
if (v <= -64)
|
||||
kcode[port] |= (key & ~0x40000); // button released
|
||||
else if (v >= 64)
|
||||
kcode[port] &= ~(key & ~0x40000); // button pressed
|
||||
}
|
||||
else
|
||||
*this_axis = (s8)v;
|
||||
}
|
||||
else if (((int)key >> 16) == 4) // Map triggers to digital buttons
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool rc = false;
|
||||
if (_maple_port == 4)
|
||||
{
|
||||
if (v <= -64)
|
||||
kcode[_maple_port] |= (key & ~0x40000); // button released
|
||||
else if (v >= 64)
|
||||
kcode[_maple_port] &= ~(key & ~0x40000); // button pressed
|
||||
for (u32 port = 0; port < 4; port++)
|
||||
{
|
||||
DreamcastKey key = input_mapper->get_axis_id(port, code);
|
||||
rc = handle_axis(port, key) || rc;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
{
|
||||
DreamcastKey key = input_mapper->get_axis_id(0, code);
|
||||
rc = handle_axis(_maple_port, key);
|
||||
}
|
||||
|
||||
return true;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int GamepadDevice::get_axis_min_value(u32 axis) {
|
||||
|
|
|
@ -96,35 +96,35 @@ axis_list[] =
|
|||
|
||||
std::map<std::string, std::shared_ptr<InputMapping>> InputMapping::loaded_mappings;
|
||||
|
||||
void InputMapping::set_button(DreamcastKey id, u32 code)
|
||||
void InputMapping::set_button(u32 port, DreamcastKey id, u32 code)
|
||||
{
|
||||
if (id != EMU_BTN_NONE)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
u32 code = get_button_code(id);
|
||||
u32 code = get_button_code(port, id);
|
||||
if (code == (u32)-1)
|
||||
break;
|
||||
buttons[code] = EMU_BTN_NONE;
|
||||
buttons[port][code] = EMU_BTN_NONE;
|
||||
}
|
||||
buttons[code] = id;
|
||||
buttons[port][code] = id;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void InputMapping::set_axis(DreamcastKey id, u32 code, bool is_inverted)
|
||||
void InputMapping::set_axis(u32 port, DreamcastKey id, u32 code, bool is_inverted)
|
||||
{
|
||||
if (id != EMU_AXIS_NONE)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
u32 code = get_axis_code(id);
|
||||
u32 code = get_axis_code(port, id);
|
||||
if (code == (u32)-1)
|
||||
break;
|
||||
axes[code] = EMU_AXIS_NONE;
|
||||
axes[port][code] = EMU_AXIS_NONE;
|
||||
}
|
||||
axes[code] = id;
|
||||
axes_inverted[code] = is_inverted;
|
||||
axes[port][code] = id;
|
||||
axes_inverted[port][code] = is_inverted;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
@ -144,29 +144,44 @@ void InputMapping::load(FILE* fp)
|
|||
|
||||
this->dead_zone = (float)dz / 100.f;
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(button_list); i++)
|
||||
for (int port = 0; port < 4; port++)
|
||||
{
|
||||
int button_code = mf.get_int(button_list[i].section, button_list[i].option, -1);
|
||||
if (button_code >= 0)
|
||||
for (u32 i = 0; i < ARRAY_SIZE(button_list); i++)
|
||||
{
|
||||
this->set_button(button_list[i].id, button_code);
|
||||
std::string option;
|
||||
if (port == 0)
|
||||
option = button_list[i].option;
|
||||
else
|
||||
option = button_list[i].option + std::to_string(port);
|
||||
int button_code = mf.get_int(button_list[i].section, option, -1);
|
||||
if (button_code >= 0)
|
||||
this->set_button(port, button_list[i].id, button_code);
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++)
|
||||
{
|
||||
int axis_code = mf.get_int(axis_list[i].section, axis_list[i].option, -1);
|
||||
if (axis_code >= 0)
|
||||
for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++)
|
||||
{
|
||||
this->set_axis(axis_list[i].id, axis_code, mf.get_bool(axis_list[i].section_inverted, axis_list[i].option_inverted, false));
|
||||
std::string option;
|
||||
if (port == 0)
|
||||
option = axis_list[i].option;
|
||||
else
|
||||
option = axis_list[i].option + std::to_string(port);
|
||||
int axis_code = mf.get_int(axis_list[i].section, option, -1);
|
||||
if (axis_code >= 0)
|
||||
{
|
||||
if (port == 0)
|
||||
option = axis_list[i].option_inverted;
|
||||
else
|
||||
option = axis_list[i].option_inverted + std::to_string(port);
|
||||
this->set_axis(port, axis_list[i].id, axis_code, mf.get_bool(axis_list[i].section_inverted, option, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
u32 InputMapping::get_button_code(DreamcastKey key)
|
||||
u32 InputMapping::get_button_code(u32 port, DreamcastKey key)
|
||||
{
|
||||
for (auto& it : buttons)
|
||||
for (auto& it : buttons[port])
|
||||
{
|
||||
if (it.second == key)
|
||||
return it.first;
|
||||
|
@ -174,9 +189,9 @@ u32 InputMapping::get_button_code(DreamcastKey key)
|
|||
return -1;
|
||||
}
|
||||
|
||||
u32 InputMapping::get_axis_code(DreamcastKey key)
|
||||
u32 InputMapping::get_axis_code(u32 port, DreamcastKey key)
|
||||
{
|
||||
for (auto& it : axes)
|
||||
for (auto& it : axes[port])
|
||||
{
|
||||
if (it.second == key)
|
||||
return it.first;
|
||||
|
@ -221,23 +236,43 @@ bool InputMapping::save(const char *name)
|
|||
mf.set("emulator", "mapping_name", this->name);
|
||||
mf.set_int("emulator", "dead_zone", (int)std::round(this->dead_zone * 100.f));
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(button_list); i++)
|
||||
for (int port = 0; port < 4; port++)
|
||||
{
|
||||
for (auto& it : buttons)
|
||||
for (u32 i = 0; i < ARRAY_SIZE(button_list); i++)
|
||||
{
|
||||
if (it.second == button_list[i].id)
|
||||
mf.set_int(button_list[i].section, button_list[i].option, (int)it.first);
|
||||
}
|
||||
}
|
||||
std::string option;
|
||||
if (port == 0)
|
||||
option = button_list[i].option;
|
||||
else
|
||||
option = button_list[i].option + std::to_string(port);
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++)
|
||||
{
|
||||
for (auto& it : axes)
|
||||
{
|
||||
if (it.second == axis_list[i].id)
|
||||
for (auto& it : buttons[port])
|
||||
{
|
||||
mf.set_int(axis_list[i].section, axis_list[i].option, (int)it.first);
|
||||
mf.set_bool(axis_list[i].section_inverted, axis_list[i].option_inverted, axes_inverted[it.first]);
|
||||
if (it.second == button_list[i].id)
|
||||
mf.set_int(button_list[i].section, option, (int)it.first);
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(axis_list); i++)
|
||||
{
|
||||
std::string option;
|
||||
if (port == 0)
|
||||
option = axis_list[i].option;
|
||||
else
|
||||
option = axis_list[i].option + std::to_string(port);
|
||||
std::string option_inverted;
|
||||
if (port == 0)
|
||||
option_inverted = axis_list[i].option_inverted;
|
||||
else
|
||||
option_inverted = axis_list[i].option_inverted + std::to_string(port);
|
||||
|
||||
for (auto& it : axes[port])
|
||||
{
|
||||
if (it.second == axis_list[i].id)
|
||||
{
|
||||
mf.set_int(axis_list[i].section, option, (int)it.first);
|
||||
mf.set_bool(axis_list[i].section_inverted, option_inverted, axes_inverted[port][it.first]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,43 +31,48 @@ public:
|
|||
InputMapping(const InputMapping& other) {
|
||||
name = other.name;
|
||||
dead_zone = other.dead_zone;
|
||||
buttons = other.buttons;
|
||||
axes = other.axes;
|
||||
axes_inverted = other.axes_inverted;
|
||||
for (int port = 0; port < 4; port++)
|
||||
{
|
||||
buttons[port] = other.buttons[port];
|
||||
axes[port] = other.axes[port];
|
||||
axes_inverted[port] = other.axes_inverted[port];
|
||||
}
|
||||
}
|
||||
|
||||
std::string name;
|
||||
float dead_zone;
|
||||
float dead_zone = 0.1f;
|
||||
|
||||
DreamcastKey get_button_id(u32 code)
|
||||
DreamcastKey get_button_id(u32 port, u32 code)
|
||||
{
|
||||
auto it = buttons.find(code);
|
||||
if (it != buttons.end())
|
||||
auto it = buttons[port].find(code);
|
||||
if (it != buttons[port].end())
|
||||
return it->second;
|
||||
else
|
||||
return EMU_BTN_NONE;
|
||||
}
|
||||
void set_button(DreamcastKey id, u32 code);
|
||||
u32 get_button_code(DreamcastKey key);
|
||||
void set_button(u32 port, DreamcastKey id, u32 code);
|
||||
void set_button(DreamcastKey id, u32 code) { set_button(0, id, code); }
|
||||
u32 get_button_code(u32 port, DreamcastKey id);
|
||||
|
||||
DreamcastKey get_axis_id(u32 code)
|
||||
DreamcastKey get_axis_id(u32 port, u32 code)
|
||||
{
|
||||
auto it = axes.find(code);
|
||||
if (it != axes.end())
|
||||
auto it = axes[port].find(code);
|
||||
if (it != axes[port].end())
|
||||
return it->second;
|
||||
else
|
||||
return EMU_AXIS_NONE;
|
||||
}
|
||||
bool get_axis_inverted(u32 code)
|
||||
bool get_axis_inverted(u32 port, u32 code)
|
||||
{
|
||||
auto it = axes_inverted.find(code);
|
||||
if (it != axes_inverted.end())
|
||||
auto it = axes_inverted[port].find(code);
|
||||
if (it != axes_inverted[port].end())
|
||||
return it->second;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
u32 get_axis_code(DreamcastKey key);
|
||||
void set_axis(DreamcastKey id, u32 code, bool inverted);
|
||||
u32 get_axis_code(u32 port, DreamcastKey key);
|
||||
void set_axis(u32 port, DreamcastKey id, u32 code, bool inverted);
|
||||
void set_axis(DreamcastKey id, u32 code, bool inverted) { set_axis(0, id, code, inverted); }
|
||||
|
||||
void load(FILE* fp);
|
||||
bool save(const char *name);
|
||||
|
@ -81,9 +86,9 @@ protected:
|
|||
bool dirty = false;
|
||||
|
||||
private:
|
||||
std::map<u32, DreamcastKey> buttons;
|
||||
std::map<u32, DreamcastKey> axes;
|
||||
std::map<u32, bool> axes_inverted;
|
||||
std::map<u32, DreamcastKey> buttons[4];
|
||||
std::map<u32, DreamcastKey> axes[4];
|
||||
std::map<u32, bool> axes_inverted[4];
|
||||
|
||||
static std::map<std::string, std::shared_ptr<InputMapping>> loaded_mappings;
|
||||
};
|
||||
|
@ -96,12 +101,12 @@ public:
|
|||
dead_zone = 0.1f;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
set_button((DreamcastKey)(1 << i), 1 << i);
|
||||
set_axis(DC_AXIS_X, DC_AXIS_X, false);
|
||||
set_axis(DC_AXIS_Y, DC_AXIS_Y, false);
|
||||
set_axis(DC_AXIS_LT, DC_AXIS_LT, false);
|
||||
set_axis(DC_AXIS_RT, DC_AXIS_RT, false);
|
||||
set_axis(DC_AXIS_X2, DC_AXIS_X2, false);
|
||||
set_axis(DC_AXIS_Y2, DC_AXIS_Y2, false);
|
||||
set_button(0, (DreamcastKey)(1 << i), 1 << i);
|
||||
set_axis(0, DC_AXIS_X, DC_AXIS_X, false);
|
||||
set_axis(0, DC_AXIS_Y, DC_AXIS_Y, false);
|
||||
set_axis(0, DC_AXIS_LT, DC_AXIS_LT, false);
|
||||
set_axis(0, DC_AXIS_RT, DC_AXIS_RT, false);
|
||||
set_axis(0, DC_AXIS_X2, DC_AXIS_X2, false);
|
||||
set_axis(0, DC_AXIS_Y2, DC_AXIS_Y2, false);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -442,7 +442,7 @@ static const char *maple_expansion_device_name(MapleDeviceType type)
|
|||
}
|
||||
}
|
||||
|
||||
const char *maple_ports[] = { "None", "A", "B", "C", "D" };
|
||||
const char *maple_ports[] = { "None", "A", "B", "C", "D", "All" };
|
||||
const DreamcastKey button_keys[] = {
|
||||
DC_BTN_START, DC_BTN_A, DC_BTN_B, DC_BTN_X, DC_BTN_Y, DC_DPAD_UP, DC_DPAD_DOWN, DC_DPAD_LEFT, DC_DPAD_RIGHT,
|
||||
EMU_BTN_MENU, EMU_BTN_ESCAPE, EMU_BTN_FFORWARD, EMU_BTN_TRIGGER_LEFT, EMU_BTN_TRIGGER_RIGHT,
|
||||
|
@ -500,6 +500,7 @@ static std::shared_ptr<GamepadDevice> mapped_device;
|
|||
static u32 mapped_code;
|
||||
static double map_start_time;
|
||||
static bool arcade_button_mode;
|
||||
static u32 gamepad_port;
|
||||
|
||||
static void input_detected(u32 code)
|
||||
{
|
||||
|
@ -525,15 +526,15 @@ static void detect_input_popup(int index, bool analog)
|
|||
{
|
||||
if (analog)
|
||||
{
|
||||
u32 previous_mapping = input_mapping->get_axis_code(axis_keys[index]);
|
||||
u32 previous_mapping = input_mapping->get_axis_code(gamepad_port, axis_keys[index]);
|
||||
bool inverted = false;
|
||||
if (previous_mapping != (u32)-1)
|
||||
inverted = input_mapping->get_axis_inverted(previous_mapping);
|
||||
inverted = input_mapping->get_axis_inverted(gamepad_port, previous_mapping);
|
||||
// FIXME Allow inverted to be set
|
||||
input_mapping->set_axis(axis_keys[index], mapped_code, inverted);
|
||||
input_mapping->set_axis(gamepad_port, axis_keys[index], mapped_code, inverted);
|
||||
}
|
||||
else
|
||||
input_mapping->set_button(button_keys[index], mapped_code);
|
||||
input_mapping->set_button(gamepad_port, button_keys[index], mapped_code);
|
||||
}
|
||||
mapped_device = NULL;
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
@ -569,6 +570,26 @@ static void controller_mapping_popup(std::shared_ptr<GamepadDevice> gamepad)
|
|||
gamepad->save_mapping();
|
||||
}
|
||||
ImGui::SetItemDefaultFocus();
|
||||
|
||||
if (gamepad->maple_port() == MAPLE_PORTS)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
float w = ImGui::CalcItemWidth();
|
||||
ImGui::PushItemWidth(w / 2);
|
||||
if (ImGui::BeginCombo("Port", maple_ports[gamepad_port + 1]))
|
||||
{
|
||||
for (u32 j = 0; j < MAPLE_PORTS; j++)
|
||||
{
|
||||
bool is_selected = gamepad_port == j;
|
||||
if (ImGui::Selectable(maple_ports[j + 1], &is_selected))
|
||||
gamepad_port = j;
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImGui::SameLine(ImGui::GetContentRegionAvailWidth() - ImGui::CalcTextSize("Arcade button names").x
|
||||
- ImGui::GetStyle().FramePadding.x * 3.0f - ImGui::GetStyle().ItemSpacing.x);
|
||||
ImGui::Checkbox("Arcade button names", &arcade_button_mode);
|
||||
|
@ -587,7 +608,7 @@ static void controller_mapping_popup(std::shared_ptr<GamepadDevice> gamepad)
|
|||
ImGui::PushID(key_id);
|
||||
ImGui::Text("%s", arcade_button_mode ? arcade_button_names[j] : button_names[j]);
|
||||
ImGui::NextColumn();
|
||||
u32 code = input_mapping->get_button_code(button_keys[j]);
|
||||
u32 code = input_mapping->get_button_code(gamepad_port, button_keys[j]);
|
||||
if (code != (u32)-1)
|
||||
{
|
||||
const char *label = gamepad->get_button_name(code);
|
||||
|
@ -627,7 +648,7 @@ static void controller_mapping_popup(std::shared_ptr<GamepadDevice> gamepad)
|
|||
ImGui::PushID(key_id);
|
||||
ImGui::Text("%s", arcade_button_mode ? arcade_axis_names[j] : axis_names[j]);
|
||||
ImGui::NextColumn();
|
||||
u32 code = input_mapping->get_axis_code(axis_keys[j]);
|
||||
u32 code = input_mapping->get_axis_code(gamepad_port, axis_keys[j]);
|
||||
if (code != (u32)-1)
|
||||
{
|
||||
const char *label = gamepad->get_axis_name(code);
|
||||
|
@ -1015,7 +1036,7 @@ static void gui_display_settings()
|
|||
ImGui::PushID(port_name);
|
||||
if (ImGui::BeginCombo(port_name, maple_ports[gamepad->maple_port() + 1]))
|
||||
{
|
||||
for (int j = -1; j < MAPLE_PORTS; j++)
|
||||
for (int j = -1; j < (int)ARRAY_SIZE(maple_ports) - 1; j++)
|
||||
{
|
||||
bool is_selected = gamepad->maple_port() == j;
|
||||
if (ImGui::Selectable(maple_ports[j + 1], &is_selected))
|
||||
|
@ -1028,7 +1049,10 @@ static void gui_display_settings()
|
|||
}
|
||||
ImGui::NextColumn();
|
||||
if (gamepad->remappable() && ImGui::Button("Map"))
|
||||
{
|
||||
gamepad_port = 0;
|
||||
ImGui::OpenPopup("Controller Mapping");
|
||||
}
|
||||
|
||||
controller_mapping_popup(gamepad);
|
||||
|
||||
|
|
Loading…
Reference in New Issue