New input handling/mapping system, SDL only for now. Gui wip

This commit is contained in:
Flyinghead 2019-02-12 11:30:24 +01:00
parent 66dc13b376
commit 8b5c2a3fac
25 changed files with 1456 additions and 497 deletions

View File

@ -11,7 +11,7 @@ RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ hw/mod
hw/extdev/ hw/arm/ hw/naomi/ imgread/ ./ deps/coreio/ deps/zlib/ deps/chdr/ deps/crypto/ \
deps/libelf/ deps/chdpsr/ arm_emitter/ rend/ reios/ deps/libpng/ deps/xbrz/ \
deps/picotcp/modules/ deps/picotcp/stack/ deps/xxhash/ deps/libzip/ deps/imgui/ \
archive/
archive/ input/
ifdef CHD5_LZMA
RZDCY_MODULES += deps/lzma/

View File

@ -113,36 +113,35 @@ void mcfg_CreateAtomisWaveControllers()
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 3
}
void mcfg_CreateController(u32 bus, MapleDeviceType maple_type1, MapleDeviceType maple_type2)
void mcfg_CreateDevices()
{
mcfg_Create(MDT_SegaController, bus, 5);
for (int bus = 0; bus < MAPLE_PORTS; ++bus)
{
switch ((MapleDeviceType)settings.input.maple_devices[bus])
{
case MDT_SegaController:
mcfg_Create(MDT_SegaController, bus, 5);
if (settings.input.maple_expansion_devices[bus][0] != MDT_None)
mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][0], bus, 0);
if (settings.input.maple_expansion_devices[bus][1] != MDT_None)
mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][1], bus, 1);
break;
if (maple_type1 != MDT_None)
mcfg_Create(maple_type1, bus, 0);
case MDT_Keyboard:
mcfg_Create(MDT_Keyboard, bus, 5);
break;
if (maple_type2 != MDT_None)
mcfg_Create(maple_type2, bus, 1);
}
case MDT_Mouse:
mcfg_Create(MDT_Mouse, bus, 5);
break;
void mcfg_CreateDevicesFromConfig()
{
// Create the configure controller count
int numberOfControl = cfgLoadInt("players", "nb", 1);
if (numberOfControl <= 0)
numberOfControl = 1;
if (numberOfControl > 4)
numberOfControl = 4;
for (int i = 0; i < numberOfControl; i++)
// Default to two VMUs on each controller
mcfg_CreateController(i, MDT_SegaVMU, MDT_SegaVMU);
if (settings.input.DCKeyboard && numberOfControl < 4)
mcfg_Create(MDT_Keyboard, numberOfControl++, 5);
if (settings.input.DCMouse != 0 && numberOfControl < 4)
mcfg_Create(MDT_Mouse, numberOfControl++, 5);
case MDT_LightGun:
mcfg_Create(MDT_LightGun, bus, 5);
if (settings.input.maple_expansion_devices[bus][0] != MDT_None)
mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][0], bus, 0);
break;
}
}
}
void mcfg_DestroyDevices()

View File

@ -59,8 +59,7 @@ struct IMapleConfigMap
};
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
void mcfg_CreateDevicesFromConfig();
void mcfg_CreateController(u32 bus, MapleDeviceType maple_type1, MapleDeviceType maple_type2);
void mcfg_CreateDevices();
#else
void mcfg_CreateNAOMIJamma();
void mcfg_CreateAtomisWaveControllers();

60
core/input/gamepad.h Normal file
View File

@ -0,0 +1,60 @@
/*
This file is part of reicast.
reicast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
reicast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
enum DreamcastKey
{
// Real buttons
DC_BTN_C = 1 << 0,
DC_BTN_B = 1 << 1,
DC_BTN_A = 1 << 2,
DC_BTN_START = 1 << 3,
DC_DPAD_UP = 1 << 4,
DC_DPAD_DOWN = 1 << 5,
DC_DPAD_LEFT = 1 << 6,
DC_DPAD_RIGHT = 1 << 7,
DC_BTN_Z = 1 << 8,
DC_BTN_Y = 1 << 9,
DC_BTN_X = 1 << 10,
DC_BTN_D = 1 << 11,
DC_DPAD2_UP = 1 << 12,
DC_DPAD2_DOWN = 1 << 13,
DC_DPAD2_LEFT = 1 << 14,
DC_DPAD2_RIGHT = 1 << 15,
// System buttons
EMU_BTN_NONE = 0,
EMU_BTN_ESCAPE = 1 << 16,
EMU_BTN_TRIGGER_LEFT = 1 << 17,
EMU_BTN_TRIGGER_RIGHT = 1 << 18,
EMU_BTN_MENU = 1 << 19,
// Real axes
DC_AXIS_LT = 0x10000,
DC_AXIS_RT = 0x10001,
DC_AXIS_X = 0x20000,
DC_AXIS_Y = 0x20001,
DC_AXIS_X2 = 0x20002,
DC_AXIS_Y2 = 0x20003,
// System axes
EMU_AXIS_NONE = 0x00000,
EMU_AXIS_DPAD1_X = 0x00001,
EMU_AXIS_DPAD1_Y = 0x00002,
EMU_AXIS_DPAD2_X = 0x00003,
EMU_AXIS_DPAD2_Y = 0x00004,
};

View File

@ -0,0 +1,195 @@
/*
Copyright 2019 flyinghead
This file is part of reicast.
reicast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
reicast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <limits.h>
#include "gamepad_device.h"
#include "rend/gui.h"
extern void dc_stop();
extern u16 kcode[4];
extern u8 rt[4], lt[4];
extern s8 joyx[4], joyy[4];
std::vector<GamepadDevice *> GamepadDevice::_gamepads;
std::mutex GamepadDevice::_gamepads_mutex;
void GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
{
if (_input_detected != NULL && _detecting_button && pressed)
{
_input_detected(code);
_input_detected = NULL;
}
if (input_mapper == NULL || _maple_port < 0 || _maple_port >= ARRAY_SIZE(kcode))
return;
DreamcastKey key = input_mapper->get_button_id(code);
printf("%d: BUTTON %x -> %d\n", _maple_port, code, key);
if (key < 0x10000)
{
if (pressed)
kcode[_maple_port] &= ~(u16)key;
else
kcode[_maple_port] |= (u16)key;
}
else
{
switch (key)
{
case EMU_BTN_ESCAPE:
dc_stop();
break;
case EMU_BTN_MENU:
gui_open_settings();
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;
default:
break;
}
}
}
void GamepadDevice::gamepad_axis_input(u32 code, int value)
{
s32 v = (value - get_axis_min_value(code)) * 255 / get_axis_range(code) - 128; //-128 ... + 127 range
if (_input_detected != NULL && !_detecting_button && (v >= 64 || v <= -64))
{
_input_detected(code);
_input_detected = NULL;
}
if (input_mapper == NULL || _maple_port < 0 || _maple_port >= ARRAY_SIZE(kcode))
return;
DreamcastKey key = input_mapper->get_axis_id(code);
if ((int)key < 0x10000)
{
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 if (((int)key >> 16) == 2) // Analog axes
{
//printf("AXIS %d Mapped to %d -> %d\n", key, value, v);
if (key == DC_AXIS_X)
joyx[_maple_port] = (s8)v;
else if (key == DC_AXIS_Y)
joyy[_maple_port] = (s8)v;
}
}
int GamepadDevice::get_axis_min_value(u32 axis) {
auto it = axis_min_values.find(axis);
if (it == axis_min_values.end()) {
load_axis_min_max(axis);
it = axis_min_values.find(axis);
if (it == axis_min_values.end())
return INT_MIN;
}
return it->second;
}
unsigned int GamepadDevice::get_axis_range(u32 axis) {
auto it = axis_ranges.find(axis);
if (it == axis_ranges.end()) {
load_axis_min_max(axis);
it = axis_ranges.find(axis);
if (it == axis_ranges.end())
return UINT_MAX;
}
return it->second;
}
std::string GamepadDevice::make_mapping_filename()
{
std::string mapping_file = std::string(api_name()) + "_" + name();
std::replace(mapping_file.begin(), mapping_file.end(), '/', '-');
std::replace(mapping_file.begin(), mapping_file.end(), '\\', '-');
std::replace(mapping_file.begin(), mapping_file.end(), ':', '-');
std::replace(mapping_file.begin(), mapping_file.end(), '?', '-');
std::replace(mapping_file.begin(), mapping_file.end(), '*', '-');
std::replace(mapping_file.begin(), mapping_file.end(), '|', '-');
std::replace(mapping_file.begin(), mapping_file.end(), '"', '-');
std::replace(mapping_file.begin(), mapping_file.end(), '<', '-');
std::replace(mapping_file.begin(), mapping_file.end(), '>', '-');
mapping_file += ".cfg";
return mapping_file;
}
bool GamepadDevice::find_mapping(const char *custom_mapping /* = NULL */)
{
std::string mapping_file;
if (custom_mapping != NULL)
mapping_file = custom_mapping;
else
mapping_file = make_mapping_filename();
input_mapper = InputMapping::LoadMapping(mapping_file.c_str());
return input_mapper != NULL;
}
int GamepadDevice::GetGamepadCount()
{
_gamepads_mutex.lock();
int count = _gamepads.size();
_gamepads_mutex.unlock();
return count;
}
GamepadDevice *GamepadDevice::GetGamepad(int index)
{
_gamepads_mutex.lock();
GamepadDevice *dev;
if (index >= 0 && index < _gamepads.size())
dev = _gamepads[index];
else
dev = NULL;
_gamepads_mutex.unlock();
return dev;
}
void GamepadDevice::save_mapping()
{
if (input_mapper == NULL)
return;
std::string filename = make_mapping_filename();
if (!input_mapper->is_dirty())
return;
input_mapper->save(make_mapping_filename().c_str());
}

View File

@ -0,0 +1,91 @@
/*
Copyright 2019 flyinghead
This file is part of reicast.
reicast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
reicast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <mutex>
#include "types.h"
#include "mapping.h"
class GamepadDevice
{
typedef void (*input_detected_cb)(u32 code);
public:
virtual const char* api_name() = 0;
virtual const char* name() = 0;
int maple_port() { return _maple_port; }
void set_maple_port(int port) { _maple_port = port; }
void gamepad_btn_input(u32 code, bool pressed);
void gamepad_axis_input(u32 code, int value);
virtual ~GamepadDevice() {
save_mapping();
_gamepads_mutex.lock();
for (auto it = _gamepads.begin(); it != _gamepads.end(); it++)
if (*it == this)
{
_gamepads.erase(it);
break;
}
_gamepads_mutex.unlock();
}
void detect_btn_input(input_detected_cb button_pressed)
{
_input_detected = button_pressed;
_detecting_button = true;
}
void detect_axis_input(input_detected_cb axis_moved)
{
_input_detected = axis_moved;
_detecting_button = false;
}
void cancel_detect_input()
{
_input_detected = NULL;
}
InputMapping *get_input_mapping() { return input_mapper; }
void save_mapping();
static int GetGamepadCount();
static GamepadDevice *GetGamepad(int index);
protected:
GamepadDevice(int maple_port) : _maple_port(maple_port), input_mapper(NULL), _input_detected(NULL) {
_gamepads_mutex.lock();
_gamepads.push_back(this);
_gamepads_mutex.unlock();
}
bool find_mapping(const char *custom_mapping = NULL);
virtual void load_axis_min_max(u32 axis) {}
InputMapping *input_mapper;
std::map<u32, int> axis_min_values;
std::map<u32, unsigned int> axis_ranges;
private:
int get_axis_min_value(u32 axis);
unsigned int get_axis_range(u32 axis);
std::string make_mapping_filename();
int _maple_port;
bool _detecting_button = false;
input_detected_cb _input_detected;
static std::vector<GamepadDevice *> _gamepads;
static std::mutex _gamepads_mutex;
};

View File

@ -0,0 +1,96 @@
/*
Copyright 2019 flyinghead
This file is part of reicast.
reicast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
reicast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "types.h"
#include "mapping.h"
template <typename Keycode>
class KeyboardDevice
{
public:
virtual const char* name() = 0;
int maple_port() { return _maple_port; }
virtual void keyboard_input(Keycode keycode, bool pressed, int modifier_keys = 0);
virtual ~KeyboardDevice() {}
protected:
KeyboardDevice(int maple_port) : _maple_port(maple_port), _kb_used(0), _modifier_keys(0) {}
virtual u8 convert_keycode(Keycode keycode) = 0;
private:
int _maple_port;
int _modifier_keys;
int _kb_used;
};
extern u8 kb_key[6]; // normal keys pressed
extern u8 kb_shift; // shift keys pressed (bitmask)
template <typename Keycode>
void KeyboardDevice<Keycode>::keyboard_input(Keycode keycode, bool pressed, int modifier_keys)
{
u8 dc_keycode = convert_keycode(keycode);
if (dc_keycode == 0xE1 || dc_keycode == 0xE5) // SHIFT
{
if (pressed)
_modifier_keys |= 0x02 | 0x20;
else
_modifier_keys &= ~(0x02 | 0x20);
}
else if (dc_keycode == 0xE0 || dc_keycode == 0xE4) // CTRL
{
if (pressed)
_modifier_keys |= 0x01 | 0x10;
else
_modifier_keys &= ~(0x01 | 0x10);
}
else if (dc_keycode != 0)
{
if (pressed)
{
if (_kb_used < ARRAY_SIZE(kb_key))
{
bool found = false;
for (int i = 0; !found && i < _kb_used; i++)
{
if (kb_key[i] == dc_keycode)
found = true;
}
if (!found)
kb_key[_kb_used++] = dc_keycode;
}
}
else
{
for (int i = 0; i < _kb_used; i++)
{
if (kb_key[i] == dc_keycode)
{
_kb_used--;
for (int j = i; j < ARRAY_SIZE(kb_key) - 1; j++)
kb_key[j] = kb_key[j + 1];
kb_key[ARRAY_SIZE(kb_key) - 1] = 0;
break;
}
}
}
kb_shift = modifier_keys | _modifier_keys;
}
}

209
core/input/mapping.cpp Normal file
View File

@ -0,0 +1,209 @@
/*
Copyright 2019 flyinghead
This file is part of reicast.
reicast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
reicast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#include "mapping.h"
#include "cfg/ini.h"
static struct
{
DreamcastKey id;
string section;
string option;
}
button_list[] =
{
{ DC_BTN_A, "dreamcast", "btn_a" },
{ DC_BTN_B, "dreamcast", "btn_b" },
{ DC_BTN_C, "dreamcast", "btn_c" },
{ DC_BTN_D, "dreamcast", "btn_d" },
{ DC_BTN_X, "dreamcast", "btn_x" },
{ DC_BTN_Y, "dreamcast", "btn_y" },
{ DC_BTN_Z, "dreamcast", "btn_z" },
{ DC_BTN_START, "dreamcast", "btn_start" },
{ DC_DPAD_LEFT, "dreamcast", "btn_dpad1_left" },
{ DC_DPAD_RIGHT, "dreamcast", "btn_dpad1_right" },
{ DC_DPAD_UP, "dreamcast", "btn_dpad1_up" },
{ DC_DPAD_DOWN, "dreamcast", "btn_dpad1_down" },
{ DC_DPAD2_LEFT, "dreamcast", "btn_dpad2_left" },
{ DC_DPAD2_RIGHT, "dreamcast", "btn_dpad2_right" },
{ DC_DPAD2_UP, "dreamcast", "btn_dpad2_up" },
{ DC_DPAD2_DOWN, "dreamcast", "btn_dpad2_down" },
{ EMU_BTN_ESCAPE, "emulator", "btn_escape" },
{ EMU_BTN_MENU, "emulator", "btn_menu" },
{ EMU_BTN_TRIGGER_LEFT, "compat", "btn_trigger_left" },
{ EMU_BTN_TRIGGER_RIGHT, "compat", "btn_trigger_right" }
};
static struct
{
DreamcastKey id;
string section;
string option;
string section_inverted;
string option_inverted;
}
axis_list[] =
{
{ DC_AXIS_X, "dreamcast", "axis_x", "compat", "axis_x_inverted" },
{ DC_AXIS_Y, "dreamcast", "axis_y", "compat", "axis_y_inverted" },
{ DC_AXIS_LT, "dreamcast", "axis_trigger_left", "compat", "axis_trigger_left_inverted" },
{ DC_AXIS_RT, "dreamcast", "axis_trigger_right", "compat", "axis_trigger_right_inverted" },
{ EMU_AXIS_DPAD1_X, "compat", "axis_dpad1_x", "compat", "axis_dpad1_x_inverted" },
{ EMU_AXIS_DPAD1_Y, "compat", "axis_dpad1_y", "compat", "axis_dpad1_y_inverted" },
{ EMU_AXIS_DPAD2_X, "compat", "axis_dpad2_x", "compat", "axis_dpad2_x_inverted" },
{ EMU_AXIS_DPAD2_Y, "compat", "axis_dpad2_y", "compat", "axis_dpad2_y_inverted" }
};
std::map<std::string, InputMapping *> InputMapping::loaded_mappings;
void InputMapping::set_button(DreamcastKey id, u32 code)
{
if (id != EMU_BTN_NONE)
{
while (true)
{
u32 code = get_button_code(id);
if (code == -1)
break;
buttons[code] = EMU_BTN_NONE;
}
buttons[code] = id;
dirty = true;
}
}
void InputMapping::set_axis(DreamcastKey id, u32 code, bool is_inverted)
{
if (id != EMU_AXIS_NONE)
{
while (true)
{
u32 code = get_axis_code(id);
if (code == -1)
break;
axes[code] = EMU_AXIS_NONE;
}
axes[code] = id;
axes_inverted[code] = is_inverted;
dirty = true;
}
}
void InputMapping::load(FILE* fp)
{
ConfigFile mf;
mf.parse(fp);
this->name = mf.get("emulator", "mapping_name", "<Unknown>");
for (int i = 0; i < ARRAY_SIZE(button_list); i++)
{
int button_code = mf.get_int(button_list[i].section, button_list[i].option, -1);
if (button_code >= 0)
{
this->set_button(button_list[i].id, button_code);
}
}
for (int 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)
{
this->set_axis(axis_list[i].id, axis_code, mf.get_bool(axis_list[i].section_inverted, axis_list[i].option_inverted, false));
}
}
dirty = false;
}
u32 InputMapping::get_button_code(DreamcastKey key)
{
for (auto it : buttons)
{
if (it.second == key)
return it.first;
}
return -1;
}
u32 InputMapping::get_axis_code(DreamcastKey key)
{
for (auto it : axes)
{
if (it.second == key)
return it.first;
}
return -1;
}
InputMapping *InputMapping::LoadMapping(const char *name)
{
auto it = loaded_mappings.find(name);
if (it != loaded_mappings.end())
return it->second;
std::string path = get_readonly_data_path((std::string("/mappings/") + name).c_str());
FILE *fp = fopen(path.c_str(), "r");
if (fp == NULL)
return NULL;
InputMapping *mapping = new InputMapping();
mapping->load(fp);
fclose(fp);
loaded_mappings[name] = mapping;
return mapping;
}
bool InputMapping::save(const char *name)
{
if (!is_dirty())
return true;
std::string path = get_writable_config_path((std::string("/mappings/") + name).c_str());
FILE *fp = fopen(path.c_str(), "w");
if (fp == NULL)
return false;
ConfigFile mf;
mf.set("emulator", "mapping_name", this->name);
for (int i = 0; i < ARRAY_SIZE(button_list); i++)
{
for (auto it : buttons)
{
if (it.second == button_list[i].id)
mf.set_int(button_list[i].section, button_list[i].option, (int)it.first);
}
}
for (int i = 0; i < ARRAY_SIZE(axis_list); i++)
{
for (auto it : axes)
{
if (it.second == axis_list[i].id)
{
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]);
}
}
}
mf.save(fp);
dirty = false;
fclose(fp);
return true;
}

76
core/input/mapping.h Normal file
View File

@ -0,0 +1,76 @@
/*
Copyright 2019 flyinghead
This file is part of reicast.
reicast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
reicast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <map>
#include <stdio.h>
#include "types.h"
#include "gamepad.h"
class InputMapping
{
public:
std::string name;
DreamcastKey get_button_id(u32 code)
{
auto it = buttons.find(code);
if (it != buttons.end())
return it->second;
else
return EMU_BTN_NONE;
}
void set_button(DreamcastKey id, u32 code);
u32 get_button_code(DreamcastKey key);
DreamcastKey get_axis_id(u32 code)
{
auto it = axes.find(code);
if (it != axes.end())
return it->second;
else
return EMU_AXIS_NONE;
}
bool get_axis_inverted(u32 code)
{
auto it = axes_inverted.find(code);
if (it != axes_inverted.end())
return it->second;
else
return false;
}
u32 get_axis_code(DreamcastKey key);
void set_axis(DreamcastKey id, u32 code, bool inverted);
void load(FILE* fp);
bool save(const char *name);
bool is_dirty() { return dirty; }
static InputMapping *LoadMapping(const char *name);
protected:
bool dirty;
private:
std::map<u32, DreamcastKey> buttons;
std::map<u32, DreamcastKey> axes;
std::map<u32, bool> axes_inverted;
static std::map<std::string, InputMapping *> loaded_mappings;
};

View File

@ -4,10 +4,10 @@
#include "linux-dist/evdev.h"
#include "linux-dist/main.h"
#include "hw/maple/maple_devs.h"
#include "hw/maple/maple_cfg.h"
#include "cfg/cfg.h"
#include "cfg/ini.h"
#include "rend/gui.h"
#include "input/gamepad.h"
#include <vector>
#include <map>
#include <dlfcn.h>
@ -504,9 +504,6 @@
}
}
}
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
mcfg_CreateController(port, GetMapleDeviceType(evdev_controllers[port].mapping->Maple_Device1, port), GetMapleDeviceType(evdev_controllers[port].mapping->Maple_Device2, port));
#endif
}
}
}

View File

@ -124,7 +124,7 @@ void os_SetupInput()
#endif
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
mcfg_CreateDevicesFromConfig();
mcfg_CreateDevices();
#endif
}

View File

@ -8,28 +8,3 @@ extern s8 joyx[4], joyy[4];
extern void* x11_win;
extern void* x11_disp;
enum DreamcastController
{
DC_BTN_C = 1,
DC_BTN_B = 1<<1,
DC_BTN_A = 1<<2,
DC_BTN_START = 1<<3,
DC_DPAD_UP = 1<<4,
DC_DPAD_DOWN = 1<<5,
DC_DPAD_LEFT = 1<<6,
DC_DPAD_RIGHT = 1<<7,
DC_BTN_Z = 1<<8,
DC_BTN_Y = 1<<9,
DC_BTN_X = 1<<10,
DC_BTN_D = 1<<11,
DC_DPAD2_UP = 1<<12,
DC_DPAD2_DOWN = 1<<13,
DC_DPAD2_LEFT = 1<<14,
DC_DPAD2_RIGHT = 1<<15,
DC_AXIS_LT = 0X10000,
DC_AXIS_RT = 0X10001,
DC_AXIS_X = 0X20000,
DC_AXIS_Y = 0X20001,
};

View File

@ -14,6 +14,7 @@
#include "linux-dist/x11.h"
#include "linux-dist/main.h"
#include "rend/gui.h"
#include "input/gamepad.h"
#if FEAT_HAS_NIXPROF
#include "profiler/profiler.h"

View File

@ -255,7 +255,7 @@ void os_DoEvents() {
void os_SetupInput() {
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
mcfg_CreateDevicesFromConfig();
mcfg_CreateDevices();
#endif
}

View File

@ -554,6 +554,16 @@ void LoadSettings()
settings.input.DCMouse = cfgLoadInt("input", "DCMouse", 0);
settings.input.MouseSensitivity = cfgLoadInt("input", "MouseSensitivity", 100);
settings.input.JammaSetup = cfgLoadInt("input", "JammaSetup", 0);
for (int i = 0; i < MAPLE_PORTS; i++)
{
char device_name[32];
sprintf(device_name, "device%d", i + 1);
settings.input.maple_devices[i] = (MapleDeviceType)cfgLoadInt("input", device_name, i == 0 ? MDT_SegaController : MDT_None);
sprintf(device_name, "device%d.1", i + 1);
settings.input.maple_expansion_devices[i][0] = (MapleDeviceType)cfgLoadInt("input", device_name, i == 0 ? MDT_SegaVMU : MDT_None);
sprintf(device_name, "device%d.2", i + 1);
settings.input.maple_expansion_devices[i][1] = (MapleDeviceType)cfgLoadInt("input", device_name, i == 0 ? MDT_SegaVMU : MDT_None);
}
#else
settings.rend.RenderToTextureUpscale = max(1, settings.rend.RenderToTextureUpscale);
settings.rend.TextureUpscale = max(1, settings.rend.TextureUpscale);
@ -663,6 +673,17 @@ void SaveSettings()
cfgSaveInt("input", "DCKeyboard", settings.input.DCKeyboard);
cfgSaveInt("input", "DCMouse", settings.input.DCMouse);
cfgSaveInt("input", "MouseSensitivity", settings.input.MouseSensitivity);
for (int i = 0; i < MAPLE_PORTS; i++)
{
char device_name[32];
sprintf(device_name, "device%d", i + 1);
cfgSaveInt("input", device_name, (s32)settings.input.maple_devices[i]);
sprintf(device_name, "device%d.1", i + 1);
cfgSaveInt("input", device_name, (s32)settings.input.maple_expansion_devices[i][0]);
sprintf(device_name, "device%d.2", i + 1);
cfgSaveInt("input", device_name, (s32)settings.input.maple_expansion_devices[i][1]);
}
}
#endif

View File

@ -25,7 +25,8 @@
#include "imgui/imgui_impl_opengl3.h"
#include "imgui/roboto_medium.h"
#include "gles/gles.h"
#include "linux-dist/main.h" // FIXME for kcode[] and DC_BTN_x
#include "input/gamepad_device.h"
#include "linux-dist/main.h" // FIXME for kcode[]
extern bool dc_pause_emu();
extern void dc_resume_emu(bool continue_running);
@ -45,7 +46,7 @@ extern bool renderer_changed;
int screen_dpi = 96;
static bool inited = false;
static float scaling = 1.f;
static float scaling = 1;
static enum { Closed, Commands, Settings, ClosedNoResume } gui_state;
static bool settings_opening;
static bool touch_up;
@ -61,6 +62,8 @@ void gui_init()
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.IniFilename = NULL;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
@ -89,10 +92,10 @@ void gui_init()
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
ImGui::GetStyle().TabRounding = 0.f;
ImGui::GetStyle().TabRounding = 0;
ImGui::GetStyle().ItemSpacing = ImVec2(8, 8); // from 8,4
ImGui::GetStyle().ItemInnerSpacing = ImVec2(4, 6); // from 4,4
//ImGui::GetStyle().WindowRounding = 0.f;
//ImGui::GetStyle().WindowRounding = 0;
#ifdef _ANDROID
ImGui::GetStyle().GrabMinSize = 20.0f; // from 10
ImGui::GetStyle().ScrollbarSize = 24.0f; // from 16
@ -317,6 +320,128 @@ static void gui_display_commands()
settings_opening = false;
}
const char *maple_device_types[] = { "None", "Sega Controller", "Light Gun", "Keyboard", "Mouse" };
const char *maple_expansion_device_types[] = { "None", "Sega VMU", "Purupuru", "Microphone" };
static const char *maple_device_name(MapleDeviceType type)
{
switch (type)
{
case MDT_SegaController:
return maple_device_types[1];
case MDT_LightGun:
return maple_device_types[2];
case MDT_Keyboard:
return maple_device_types[3];
case MDT_Mouse:
return maple_device_types[4];
case MDT_None:
default:
return maple_device_types[0];
}
}
static MapleDeviceType maple_device_type_from_index(int idx)
{
switch (idx)
{
case 1:
return MDT_SegaController;
case 2:
return MDT_LightGun;
case 3:
return MDT_Keyboard;
case 4:
return MDT_Mouse;
case 0:
default:
return MDT_None;
}
}
static const char *maple_expansion_device_name(MapleDeviceType type)
{
switch (type)
{
case MDT_SegaVMU:
return maple_expansion_device_types[1];
case MDT_PurupuruPack:
return maple_expansion_device_types[2];
case MDT_Microphone:
return maple_expansion_device_types[3];
case MDT_None:
default:
return maple_expansion_device_types[0];
}
}
const char *maple_ports[] = { "None", "A", "B", "C", "D" };
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_TRIGGER_LEFT, EMU_BTN_TRIGGER_RIGHT,
DC_BTN_C, DC_BTN_D, DC_BTN_Z, DC_DPAD2_UP, DC_DPAD2_DOWN, DC_DPAD2_LEFT, DC_DPAD2_RIGHT };
const char *button_names[] = { "Start", "A", "B", "X", "Y", "DPad Up", "DPad Down", "DPad Left", "DPad Right",
"Menu", "Exit", "Left Trigger", "Right Trigger",
"C", "D", "Z", "Right Dpad Up", "Right DPad Down", "Right DPad Left", "Right DPad Right" };
const DreamcastKey axis_keys[] = { DC_AXIS_X, DC_AXIS_Y, DC_AXIS_LT, DC_AXIS_RT, EMU_AXIS_DPAD1_X, EMU_AXIS_DPAD1_Y, EMU_AXIS_DPAD2_X, EMU_AXIS_DPAD2_Y };
const char *axis_names[] = { "Stick X", "Stick Y", "Left Trigger", "Right Trigger", "DPad X", "DPad Y", "Right DPad X", "Right DPad Y" };
static MapleDeviceType maple_expansion_device_type_from_index(int idx)
{
switch (idx)
{
case 1:
return MDT_SegaVMU;
case 2:
return MDT_PurupuruPack;
case 3:
return MDT_Microphone;
case 0:
default:
return MDT_None;
}
}
static GamepadDevice *mapped_device;
static u32 mapped_code;
static double map_start_time;
static void input_detected(u32 code)
{
mapped_code = code;
}
static void detect_input_popup(int index, bool analog)
{
ImVec2 padding = ImVec2(20 * scaling, 20 * scaling);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, padding);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, padding);
if (ImGui::BeginPopupModal(analog ? "Map Axis" : "Map Button", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
{
ImGui::Text("Waiting for %s '%s'...", analog ? "axis" : "button", analog ? axis_names[index] : button_names[index]);
double now = os_GetSeconds();
ImGui::Text("Time out in %d s", (int)(5 - (now - map_start_time)));
if (mapped_code != -1)
{
if (analog)
{
u32 previous_mapping = mapped_device->get_input_mapping()->get_axis_code(axis_keys[index]);
bool inverted = false;
if (previous_mapping != -1)
inverted = mapped_device->get_input_mapping()->get_axis_inverted(previous_mapping);
// FIXME Allow inverted to be set
mapped_device->get_input_mapping()->set_axis(axis_keys[index], mapped_code, inverted);
}
else
mapped_device->get_input_mapping()->set_button(button_keys[index], mapped_code);
ImGui::CloseCurrentPopup();
}
else if (now - map_start_time >= 5)
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
ImGui::PopStyleVar(2);
}
static void gui_display_settings()
{
ImGui_Impl_NewFrame();
@ -324,7 +449,6 @@ static void gui_display_settings()
int dynarec_enabled = settings.dynarec.Enable;
u32 renderer = settings.pvr.rend;
int playerCount = cfgLoadInt("players", "nb", 1);
if (!settings_opening)
ImGui_ImplOpenGL3_DrawBackground();
@ -342,12 +466,9 @@ static void gui_display_settings()
{
gui_state = Commands;
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (playerCount != cfgLoadInt("players", "nb", 1))
{
cfgSaveInt("players", "nb", playerCount);
mcfg_DestroyDevices();
mcfg_CreateDevicesFromConfig();
}
// TODO only if changed? sleep time on emu thread?
mcfg_DestroyDevices();
mcfg_CreateDevices();
#endif
SaveSettings();
}
@ -430,15 +551,189 @@ static void gui_display_settings()
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding);
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
ImGui::SliderInt("Players", (int *)&playerCount, 1, 4);
ImGui::Checkbox("Emulate keyboard", &settings.input.DCKeyboard);
ImGui::SameLine();
ShowHelpMarker("Emulate a Dreamcast keyboard");
ImGui::Checkbox("Emulate mouse", &settings.input.DCMouse);
ImGui::SameLine();
ShowHelpMarker("Emulate a Dreamcast mouse");
if (ImGui::CollapsingHeader("Dreamcast Devices", ImGuiTreeNodeFlags_DefaultOpen))
{
for (int bus = 0; bus < MAPLE_PORTS; bus++)
{
ImGui::Text("Device %c", bus + 'A');
ImGui::SameLine();
char device_name[32];
sprintf(device_name, "##device%d", bus);
float w = ImGui::CalcItemWidth() / 3;
ImGui::PushItemWidth(w);
if (ImGui::BeginCombo(device_name, maple_device_name((MapleDeviceType)settings.input.maple_devices[bus]), ImGuiComboFlags_None))
{
for (int i = 0; i < IM_ARRAYSIZE(maple_device_types); i++)
{
bool is_selected = settings.input.maple_devices[bus] == maple_device_type_from_index(i);
if (ImGui::Selectable(maple_device_types[i], &is_selected))
settings.input.maple_devices[bus] = maple_device_type_from_index(i);
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
int port_count = settings.input.maple_devices[bus] == MDT_SegaController ? 2 : settings.input.maple_devices[bus] == MDT_LightGun ? 1 : 0;
for (int port = 0; port < port_count; port++)
{
ImGui::SameLine();
sprintf(device_name, "##device%d.%d", bus, port + 1);
ImGui::PushID(device_name);
if (ImGui::BeginCombo(device_name, maple_expansion_device_name((MapleDeviceType)settings.input.maple_expansion_devices[bus][port]), ImGuiComboFlags_None))
{
for (int i = 0; i < IM_ARRAYSIZE(maple_expansion_device_types); i++)
{
bool is_selected = settings.input.maple_expansion_devices[bus][port] == maple_expansion_device_type_from_index(i);
if (ImGui::Selectable(maple_expansion_device_types[i], &is_selected))
settings.input.maple_expansion_devices[bus][port] = maple_expansion_device_type_from_index(i);
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
ImGui::PopID();
}
ImGui::PopItemWidth();
}
ImGui::Spacing();
}
#endif
if (ImGui::CollapsingHeader("Physical Devices", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Columns(4, "renderers", false);
ImGui::Text("System");
ImGui::SetColumnWidth(-1, ImGui::CalcTextSize("System").x + ImGui::GetStyle().FramePadding.x * 2.0f + ImGui::GetStyle().ItemSpacing.x);
ImGui::NextColumn();
ImGui::Text("Name");
ImGui::NextColumn();
ImGui::Text("Port");
ImGui::SetColumnWidth(-1, ImGui::CalcTextSize("None").x * 1.6f + ImGui::GetStyle().FramePadding.x * 2.0f + ImGui::GetFrameHeight()
+ ImGui::GetStyle().ItemInnerSpacing.x + ImGui::GetStyle().ItemSpacing.x);
ImGui::NextColumn();
ImGui::NextColumn();
for (int i = 0; i < GamepadDevice::GetGamepadCount(); i++)
{
GamepadDevice *gamepad = GamepadDevice::GetGamepad(i);
if (gamepad == NULL)
continue;
ImGui::Text("%s", gamepad->api_name());
ImGui::NextColumn();
ImGui::Text("%s", gamepad->name());
ImGui::NextColumn();
char port_name[32];
sprintf(port_name, "##mapleport%d", i);
ImGui::PushID(port_name);
if (ImGui::BeginCombo(port_name, maple_ports[gamepad->maple_port() + 1]))
{
for (int j = -1; j < MAPLE_PORTS; j++)
{
bool is_selected = gamepad->maple_port() == j;
if (ImGui::Selectable(maple_ports[j + 1], &is_selected))
gamepad->set_maple_port(j);
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
ImGui::NextColumn();
if (ImGui::Button("Map"))
ImGui::OpenPopup("Controller Mapping");
if (ImGui::BeginPopupModal("Controller Mapping", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
{
const float width = 350 * scaling;
const float height = 450 * scaling;
const float col0_width = ImGui::CalcTextSize("Right DPad Downxxx").x + ImGui::GetStyle().FramePadding.x * 2.0f + ImGui::GetStyle().ItemSpacing.x;
const float col1_width = width
- ImGui::GetStyle().GrabMinSize
- (col0_width + ImGui::GetStyle().ItemSpacing.x)
- (ImGui::CalcTextSize("Map").x + ImGui::GetStyle().FramePadding.x * 2.0f + ImGui::GetStyle().ItemSpacing.x);
if (ImGui::Button("Done", ImVec2(100 * scaling, 30 * scaling)))
{
ImGui::CloseCurrentPopup();
gamepad->save_mapping();
}
ImGui::SetItemDefaultFocus();
char key_id[32];
ImGui::BeginGroup();
ImGui::Text(" Buttons ");
ImGui::BeginChildFrame(ImGui::GetID("buttons"), ImVec2(width, height), ImGuiWindowFlags_None);
ImGui::Columns(3, "bindings", false);
ImGui::SetColumnWidth(0, col0_width);
ImGui::SetColumnWidth(1, col1_width);
for (int j = 0; j < ARRAY_SIZE(button_keys); j++)
{
sprintf(key_id, "key_id%d", j);
ImGui::PushID(key_id);
ImGui::Text("%s", button_names[j]);
ImGui::NextColumn();
u32 code = gamepad->get_input_mapping()->get_button_code(button_keys[j]);
if (code != -1)
ImGui::Text("%d", code);
ImGui::NextColumn();
if (ImGui::Button("Map"))
{
map_start_time = os_GetSeconds();
ImGui::OpenPopup("Map Button");
mapped_device = gamepad;
mapped_code = -1;
gamepad->detect_btn_input(&input_detected);
}
detect_input_popup(j, false);
ImGui::NextColumn();
ImGui::PopID();
}
ImGui::EndChildFrame();
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Text(" Analog Axes ");
ImGui::BeginChildFrame(ImGui::GetID("analog"), ImVec2(width, height), ImGuiWindowFlags_None);
ImGui::Columns(3, "bindings", false);
ImGui::SetColumnWidth(0, col0_width);
ImGui::SetColumnWidth(1, col1_width);
for (int j = 0; j < ARRAY_SIZE(axis_keys); j++)
{
sprintf(key_id, "axis_id%d", j);
ImGui::PushID(key_id);
ImGui::Text("%s", axis_names[j]);
ImGui::NextColumn();
u32 code = gamepad->get_input_mapping()->get_axis_code(axis_keys[j]);
if (code != -1)
ImGui::Text("%d", code);
ImGui::NextColumn();
if (ImGui::Button("Map"))
{
map_start_time = os_GetSeconds();
ImGui::OpenPopup("Map Axis");
mapped_device = gamepad;
mapped_code = -1;
gamepad->detect_axis_input(&input_detected);
}
detect_input_popup(j, true);
ImGui::NextColumn();
ImGui::PopID();
}
ImGui::EndChildFrame();
ImGui::EndGroup();
ImGui::EndPopup();
}
ImGui::NextColumn();
ImGui::PopID();
}
}
ImGui::Columns(1, NULL, false);
ImGui::Spacing();
ImGui::SliderInt("Mouse sensitivity", (int *)&settings.input.MouseSensitivity, 1, 500);
ImGui::PopStyleVar();
ImGui::EndTabItem();
}

View File

@ -1,3 +1,4 @@
#if defined(USE_SDL)
#include <map>
#include "types.h"
@ -9,6 +10,8 @@
#include "khronos/GL3/gl3w.h"
#endif
#endif
#include "sdl_gamepad.h"
#include "sdl_keyboard.h"
static SDL_Window* window = NULL;
static SDL_GLContext glcontext;
@ -20,11 +23,13 @@ static SDL_GLContext glcontext;
#endif
#define WINDOW_HEIGHT 480
static SDL_Joystick* JoySDL = 0;
static SDLGamepadDevice* sdl_gamepads[4] = { NULL };
static SDL_JoystickID joystick_ids[ARRAY_SIZE(sdl_gamepads)] = { 0 };
static SDLMouseGamepadDevice* sdl_mouse_gamepad = NULL;
static SDLKbGamepadDevice* sdl_kb_gamepad = NULL;
static SDLKeyboardDevice* sdl_keyboard = NULL;
extern bool FrameSkipping;
extern void dc_stop();
extern bool KillTex;
#ifdef TARGET_PANDORA
extern char OSD_Info[128];
@ -33,169 +38,11 @@ extern bool KillTex;
extern int OSD_Counter;
#endif
#define SDL_MAP_SIZE 32
const u32 sdl_map_btn_usb[SDL_MAP_SIZE] =
{ DC_BTN_Y, DC_BTN_B, DC_BTN_A, DC_BTN_X, 0, 0, 0, 0, 0, DC_BTN_START };
const u32 sdl_map_axis_usb[SDL_MAP_SIZE] =
{ DC_AXIS_X, DC_AXIS_Y, 0, 0, 0, 0, 0, 0, 0, 0 };
const u32 sdl_map_btn_xbox360[SDL_MAP_SIZE] =
{ DC_BTN_A, DC_BTN_B, DC_BTN_X, DC_BTN_Y, 0, 0, 0, DC_BTN_START, 0, 0 };
const u32 sdl_map_axis_xbox360[SDL_MAP_SIZE] =
{ DC_AXIS_X, DC_AXIS_Y, DC_AXIS_LT, 0, 0, DC_AXIS_RT, DC_DPAD_LEFT, DC_DPAD_UP, 0, 0 };
const u32* sdl_map_btn = sdl_map_btn_usb;
const u32* sdl_map_axis = sdl_map_axis_usb;
#ifdef TARGET_PANDORA
u32 JSensitivity[256]; // To have less sensitive value on nubs
#endif
static std::map<int, u8> kb_map;
static u32 kb_used = 0;
extern u8 kb_key[6]; // normal keys pressed
extern u8 kb_shift; // shift keys pressed (bitmask)
extern u32 mo_buttons;
extern s32 mo_x_abs;
extern s32 mo_y_abs;
static void init_kb_map()
{
//04-1D Letter keys A-Z (in alphabetic order)
kb_map[SDLK_a] = 0x04;
kb_map[SDLK_b] = 0x05;
kb_map[SDLK_c] = 0x06;
kb_map[SDLK_d] = 0x07;
kb_map[SDLK_e] = 0x08;
kb_map[SDLK_f] = 0x09;
kb_map[SDLK_g] = 0x0A;
kb_map[SDLK_h] = 0x0B;
kb_map[SDLK_i] = 0x0C;
kb_map[SDLK_j] = 0x0D;
kb_map[SDLK_k] = 0x0E;
kb_map[SDLK_l] = 0x0F;
kb_map[SDLK_m] = 0x10;
kb_map[SDLK_n] = 0x11;
kb_map[SDLK_o] = 0x12;
kb_map[SDLK_p] = 0x13;
kb_map[SDLK_q] = 0x14;
kb_map[SDLK_r] = 0x15;
kb_map[SDLK_s] = 0x16;
kb_map[SDLK_t] = 0x17;
kb_map[SDLK_u] = 0x18;
kb_map[SDLK_v] = 0x19;
kb_map[SDLK_w] = 0x1A;
kb_map[SDLK_x] = 0x1B;
kb_map[SDLK_y] = 0x1C;
kb_map[SDLK_z] = 0x1D;
//1E-27 Number keys 1-0
kb_map[SDLK_1] = 0x1E;
kb_map[SDLK_2] = 0x1F;
kb_map[SDLK_3] = 0x20;
kb_map[SDLK_4] = 0x21;
kb_map[SDLK_5] = 0x22;
kb_map[SDLK_6] = 0x23;
kb_map[SDLK_7] = 0x24;
kb_map[SDLK_8] = 0x25;
kb_map[SDLK_9] = 0x26;
kb_map[SDLK_0] = 0x27;
kb_map[SDLK_RETURN] = 0x28;
kb_map[SDLK_ESCAPE] = 0x29;
kb_map[SDLK_BACKSPACE] = 0x2A;
kb_map[SDLK_TAB] = 0x2B;
kb_map[SDLK_SPACE] = 0x2C;
kb_map[SDLK_MINUS] = 0x2D; // -
kb_map[SDLK_EQUALS] = 0x2E; // =
kb_map[SDLK_LEFTBRACKET] = 0x2F; // [
kb_map[SDLK_RIGHTBRACKET] = 0x30; // ]
kb_map[SDLK_BACKSLASH] = 0x31; // \ (US) unsure of keycode
//32-34 "]", ";" and ":" (the 3 keys right of L)
kb_map[SDLK_ASTERISK] = 0x32; // ~ (non-US) *,µ in FR layout
kb_map[SDLK_SEMICOLON] = 0x33; // ;
kb_map[SDLK_QUOTE] = 0x34; // '
//35 hankaku/zenkaku / kanji (top left)
kb_map[SDLK_BACKQUOTE] = 0x35; // `~ (US)
//36-38 ",", "." and "/" (the 3 keys right of M)
kb_map[SDLK_COMMA] = 0x36;
kb_map[SDLK_PERIOD] = 0x37;
kb_map[SDLK_SLASH] = 0x38;
// CAPSLOCK
kb_map[SDLK_CAPSLOCK] = 0x39;
//3A-45 Function keys F1-F12
for (int i = 0;i < 10; i++)
kb_map[SDLK_F1 + i] = 0x3A + i;
kb_map[SDLK_F11] = 0x44;
kb_map[SDLK_F12] = 0x45;
//46-4E Control keys above cursor keys
kb_map[SDLK_PRINTSCREEN] = 0x46; // Print Screen
kb_map[SDLK_SCROLLLOCK] = 0x47; // Scroll Lock
kb_map[SDLK_PAUSE] = 0x48; // Pause
kb_map[SDLK_INSERT] = 0x49;
kb_map[SDLK_HOME] = 0x4A;
kb_map[SDLK_PAGEUP] = 0x4B;
kb_map[SDLK_DELETE] = 0x4C;
kb_map[SDLK_END] = 0x4D;
kb_map[SDLK_PAGEDOWN] = 0x4E;
//4F-52 Cursor keys
kb_map[SDLK_RIGHT] = 0x4F;
kb_map[SDLK_LEFT] = 0x50;
kb_map[SDLK_DOWN] = 0x51;
kb_map[SDLK_UP] = 0x52;
//53 Num Lock (Numeric keypad)
kb_map[SDLK_NUMLOCKCLEAR] = 0x53;
//54 "/" (Numeric keypad)
kb_map[SDLK_KP_DIVIDE] = 0x54;
//55 "*" (Numeric keypad)
kb_map[SDLK_KP_MULTIPLY] = 0x55;
//56 "-" (Numeric keypad)
kb_map[SDLK_KP_MINUS] = 0x56;
//57 "+" (Numeric keypad)
kb_map[SDLK_KP_PLUS] = 0x57;
//58 Enter (Numeric keypad)
kb_map[SDLK_KP_ENTER] = 0x58;
//59-62 Number keys 1-0 (Numeric keypad)
kb_map[SDLK_KP_1] = 0x59;
kb_map[SDLK_KP_2] = 0x5A;
kb_map[SDLK_KP_3] = 0x5B;
kb_map[SDLK_KP_4] = 0x5C;
kb_map[SDLK_KP_5] = 0x5D;
kb_map[SDLK_KP_6] = 0x5E;
kb_map[SDLK_KP_7] = 0x5F;
kb_map[SDLK_KP_8] = 0x60;
kb_map[SDLK_KP_9] = 0x61;
kb_map[SDLK_KP_0] = 0x62;
//63 "." (Numeric keypad)
kb_map[SDLK_KP_PERIOD] = 0x63;
//64 #| (non-US)
//kb_map[94] = 0x64;
//65 S3 key
//66-A4 Not used
//A5-DF Reserved
//E0 Left Control
//E1 Left Shift
//E2 Left Alt
//E3 Left S1
//E4 Right Control
//E5 Right Shift
//E6 Right Alt
//E7 Right S3
//E8-FF Reserved
}
extern int screen_width, screen_height;
void input_sdl_init()
{
@ -209,60 +56,24 @@ void input_sdl_init()
// Open joystick device
int numjoys = SDL_NumJoysticks();
printf("Number of Joysticks found = %i\n", numjoys);
if (numjoys > 0)
for (int i = 0; i < numjoys && i < ARRAY_SIZE(sdl_gamepads); i++)
{
JoySDL = SDL_JoystickOpen(0);
}
SDL_Joystick *pJoystick = SDL_JoystickOpen(i);
printf("Joystick opened\n");
if (JoySDL)
{
int AxisCount,ButtonCount;
const char* Name;
AxisCount = 0;
ButtonCount = 0;
//Name[0] = '\0';
AxisCount = SDL_JoystickNumAxes(JoySDL);
ButtonCount = SDL_JoystickNumButtons(JoySDL);
Name = SDL_JoystickName(JoySDL);
printf("SDK: Found '%s' joystick with %d axes and %d buttons\n", Name, AxisCount, ButtonCount);
if (Name != NULL && strcmp(Name,"Microsoft X-Box 360 pad")==0)
if (pJoystick == NULL)
{
sdl_map_btn = sdl_map_btn_xbox360;
sdl_map_axis = sdl_map_axis_xbox360;
printf("Using Xbox 360 map\n");
printf("Cannot open joystick %d\n", i + 1);
continue;
}
}
else
{
printf("SDK: No Joystick Found\n");
}
#ifdef TARGET_PANDORA
float v;
int j;
for (int i=0; i<128; i++)
{
v = ((float)i)/127.0f;
v = (v+v*v)/2.0f;
j = (int)(v*127.0f);
if (j > 127)
{
j = 127;
}
JSensitivity[128-i] = -j;
JSensitivity[128+i] = j;
}
#endif
joystick_ids[i] = SDL_JoystickInstanceID(pJoystick);
sdl_gamepads[i] = new SDLGamepadDevice(i, pJoystick);
}
SDL_SetRelativeMouseMode(SDL_FALSE);
init_kb_map();
sdl_keyboard = new SDLKeyboardDevice(0); // FIXME ports!
sdl_kb_gamepad = new SDLKbGamepadDevice(0);
sdl_mouse_gamepad = new SDLMouseGamepadDevice(0);
}
static void set_mouse_position(int x, int y)
@ -281,7 +92,6 @@ void input_sdl_handle(u32 port)
{
#define SET_FLAG(field, mask, expr) field =((expr) ? (field & ~mask) : (field | mask))
SDL_Event event;
int k, value;
while (SDL_PollEvent(&event))
{
switch (event.type)
@ -291,204 +101,32 @@ void input_sdl_handle(u32 port)
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
k = event.key.keysym.sym;
value = (event.type == SDL_KEYDOWN) ? 1 : 0;
switch (k) {
case SDLK_SPACE:
SET_FLAG(kcode[port], DC_BTN_C, value);
break;
case SDLK_UP:
SET_FLAG(kcode[port], DC_DPAD_UP, value);
break;
case SDLK_DOWN:
SET_FLAG(kcode[port], DC_DPAD_DOWN, value);
break;
case SDLK_LEFT:
SET_FLAG(kcode[port], DC_DPAD_LEFT, value);
break;
case SDLK_RIGHT:
SET_FLAG(kcode[port], DC_DPAD_RIGHT, value);
break;
case SDLK_d:
SET_FLAG(kcode[port], DC_BTN_Y, value);
break;
case SDLK_x:
SET_FLAG(kcode[port], DC_BTN_A, value);
break;
case SDLK_c:
SET_FLAG(kcode[port], DC_BTN_B, value);
break;
case SDLK_s:
SET_FLAG(kcode[port], DC_BTN_X, value);
break;
case SDLK_MENU:
case SDLK_TAB:
gui_open_settings();
break;
case SDLK_f:
lt[port] = (value ? 255 : 0);
break;
case SDLK_v:
rt[port] = (value ? 255 : 0);;
break;
case SDLK_RETURN:
SET_FLAG(kcode[port], DC_BTN_START, value);
break;
#if defined(TARGET_PANDORA)
case SDLK_s:
if (value)
{
settings.aica.NoSound = !settings.aica.NoSound;
snprintf(OSD_Info, 128, "Sound %s\n", (settings.aica.NoSound) ? "Off" : "On");
OSD_Delay=300;
}
break;
case SDLK_f:
if (value)
{
FrameSkipping = !FrameSkipping;
snprintf(OSD_Info, 128, "FrameSkipping %s\n", (FrameSkipping) ? "On" : "Off");
OSD_Delay = 300;
}
break;
case SDLK_c:
if (value)
{
OSD_Counter = 1 - OSD_Counter;
}
break;
#endif
}
sdl_kb_gamepad->gamepad_btn_input(event.key.keysym.sym, event.type == SDL_KEYDOWN);
{
auto it = kb_map.find(k);
if (it != kb_map.end())
{
u8 dc_keycode = it->second;
if (event.type == SDL_KEYDOWN)
{
if (kb_used < ARRAY_SIZE(kb_key))
{
bool found = false;
for (int i = 0; !found && i < kb_used; i++)
{
if (kb_key[i] == dc_keycode)
found = true;
}
if (!found)
kb_key[kb_used++] = dc_keycode;
}
}
else
{
for (int i = 0; i < kb_used; i++)
{
if (kb_key[i] == dc_keycode)
{
kb_used--;
for (int j = i; j < ARRAY_SIZE(kb_key) - 1; j++)
kb_key[j] = kb_key[j + 1];
kb_key[ARRAY_SIZE(kb_key) - 1] = 0;
break;
}
}
}
if (event.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))
SET_FLAG(kb_shift, (0x02 | 0x20), event.type == SDL_KEYUP);
if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL))
SET_FLAG(kb_shift, (0x01 | 0x10), event.type == SDL_KEYUP);
}
int modifier_keys = 0;
if (event.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))
SET_FLAG(modifier_keys, (0x02 | 0x20), event.type == SDL_KEYUP);
if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL))
SET_FLAG(modifier_keys, (0x01 | 0x10), event.type == SDL_KEYUP);
sdl_keyboard->keyboard_input(event.key.keysym.sym, event.type == SDL_KEYDOWN, modifier_keys);
}
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
value = (event.type == SDL_JOYBUTTONDOWN) ? 1 : 0;
k = event.jbutton.button;
{
u32 mt = sdl_map_btn[k] >> 16;
u32 mo = sdl_map_btn[k] & 0xFFFF;
// printf("BUTTON %d,%d\n",JE.number,JE.value);
if (mt == 0)
for (int i = 0; i < ARRAY_SIZE(sdl_gamepads); i++)
if (joystick_ids[i] == event.jbutton.which)
{
// printf("Mapped to %d\n",mo);
if (value)
kcode[port] &= ~mo;
else
kcode[port] |= mo;
sdl_gamepads[i]->gamepad_btn_input(event.jbutton.button, event.type == SDL_JOYBUTTONDOWN);
break;
}
else if (mt == 1)
{
// printf("Mapped to %d %d\n",mo,JE.value?255:0);
if (mo == 0)
{
lt[port] = value ? 255 : 0;
}
else if (mo == 1)
{
rt[port] = value ? 255 : 0;
}
}
}
break;
case SDL_JOYAXISMOTION:
k = event.jaxis.axis;
value = event.jaxis.value;
{
u32 mt = sdl_map_axis[k] >> 16;
u32 mo = sdl_map_axis[k] & 0xFFFF;
//printf("AXIS %d,%d\n",JE.number,JE.value);
s8 v=(s8)(value/256); //-127 ... + 127 range
#ifdef TARGET_PANDORA
v = JSensitivity[128+v];
#endif
if (mt == 0)
for (int i = 0; i < ARRAY_SIZE(sdl_gamepads); i++)
if (joystick_ids[i] == event.jaxis.which)
{
kcode[port] |= mo;
kcode[port] |= mo*2;
if (v < -64)
{
kcode[port] &= ~mo;
}
else if (v > 64)
{
kcode[port] &= ~(mo*2);
}
// printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2));
sdl_gamepads[i]->gamepad_axis_input(event.jaxis.axis, event.jaxis.value);
break;
}
else if (mt == 1)
{
if (v >= 0) v++; //up to 255
// printf("AXIS %d,%d Mapped to %d %d %d\n",JE.number,JE.value,mo,v,v+127);
if (mo == 0)
{
lt[port] = v + 127;
}
else if (mo == 1)
{
rt[port] = v + 127;
}
}
else if (mt == 2)
{
// printf("AXIS %d,%d Mapped to %d %d [%d]",JE.number,JE.value,mo,v);
if (mo == 0)
{
joyx[port] = v;
}
else if (mo==1)
{
joyy[port] = v;
}
}
}
break;
case SDL_MOUSEMOTION:
@ -513,6 +151,7 @@ void input_sdl_handle(u32 port)
SET_FLAG(mo_buttons, 1 << 3, event.button.state == SDL_PRESSED);
break;
}
sdl_mouse_gamepad->gamepad_btn_input(event.button.button, event.button.state == SDL_PRESSED);
break;
}
}
@ -581,11 +220,15 @@ void sdl_window_create()
}
SDL_GL_MakeCurrent(window, NULL);
SDL_GL_GetDrawableSize(window, &screen_width, &screen_height);
float ddpi, hdpi, vdpi;
if (!SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(window), &ddpi, &hdpi, &vdpi))
screen_dpi = (int)roundf(max(hdpi, vdpi));
printf("Created SDL Window (%ix%i) and GL Context successfully\n", window_width, window_height);
}
extern int screen_width, screen_height;
bool gl_init(void* wind, void* disp)
{
SDL_GL_MakeCurrent(window, glcontext);
@ -601,14 +244,7 @@ void gl_swap()
SDL_GL_SwapWindow(window);
/* Check if drawable has been resized */
int new_width, new_height;
SDL_GL_GetDrawableSize(window, &new_width, &new_height);
if (new_width != screen_width || new_height != screen_height)
{
screen_width = new_width;
screen_height = new_height;
}
SDL_GL_GetDrawableSize(window, &screen_width, &screen_height);
}
void gl_term()

View File

@ -1,5 +1,6 @@
#pragma once
#include <SDL2/SDL.h>
#include "types.h"
extern void input_sdl_init();
extern void input_sdl_handle(u32 port);

146
core/sdl/sdl_gamepad.h Normal file
View File

@ -0,0 +1,146 @@
#include "../input/gamepad_device.h"
#include "sdl.h"
class DefaultInputMapping : public InputMapping
{
public:
DefaultInputMapping()
{
name = "Default";
set_button(DC_BTN_Y, 0);
set_button(DC_BTN_B, 1);
set_button(DC_BTN_A, 2);
set_button(DC_BTN_X, 3);
set_button(DC_BTN_START, 9);
set_axis(DC_AXIS_X, 0, false);
set_axis(DC_AXIS_Y, 1, false);
dirty = false;
}
};
class Xbox360InputMapping : public InputMapping
{
public:
Xbox360InputMapping()
{
name = "Xbox 360";
set_button(DC_BTN_A, 0);
set_button(DC_BTN_B, 1);
set_button(DC_BTN_X, 2);
set_button(DC_BTN_Y, 3);
set_button(DC_BTN_START, 7);
set_axis(DC_AXIS_X, 0, false);
set_axis(DC_AXIS_Y, 1, false);
set_axis(DC_AXIS_LT, 2, false);
set_axis(DC_AXIS_RT, 5, false);
set_axis(DC_DPAD_LEFT, 6, false);
set_axis(DC_DPAD_UP, 7, false);
dirty = false;
}
};
class SDLGamepadDevice : public GamepadDevice
{
public:
SDLGamepadDevice(int maple_port, SDL_Joystick* sdl_joystick) : GamepadDevice(maple_port), sdl_joystick(sdl_joystick)
{
_name = SDL_JoystickName(sdl_joystick);
if (!find_mapping())
{
if (_name == "Microsoft X-Box 360 pad")
{
input_mapper = new Xbox360InputMapping();
printf("Using Xbox 360 mapping\n");
}
else
{
input_mapper = new DefaultInputMapping();
printf("Using default mapping\n");
}
save_mapping();
}
}
virtual const char* api_name() override { return "SDL"; }
virtual const char* name() override { return _name.c_str(); }
virtual ~SDLGamepadDevice() override
{
SDL_JoystickClose(sdl_joystick);
}
protected:
virtual void load_axis_min_max(u32 axis) override
{
axis_min_values[axis] = -32768;
axis_ranges[axis] = 65535;
}
private:
std::string _name;
SDL_Joystick* sdl_joystick;
};
class KbInputMapping : public InputMapping
{
public:
KbInputMapping()
{
name = "SDL Keyboard";
set_button(DC_BTN_A, SDLK_x);
set_button(DC_BTN_B, SDLK_c);
set_button(DC_BTN_X, SDLK_s);
set_button(DC_BTN_Y, SDLK_d);
set_button(DC_DPAD_UP, SDLK_UP);
set_button(DC_DPAD_DOWN, SDLK_DOWN);
set_button(DC_DPAD_LEFT, SDLK_LEFT);
set_button(DC_DPAD_RIGHT, SDLK_RIGHT);
set_button(DC_BTN_START, SDLK_RETURN);
set_button(EMU_BTN_TRIGGER_LEFT, SDLK_f);
set_button(EMU_BTN_TRIGGER_RIGHT, SDLK_v);
set_button(EMU_BTN_MENU, SDLK_TAB);
dirty = false;
}
};
class SDLKbGamepadDevice : public GamepadDevice
{
public:
SDLKbGamepadDevice(int maple_port) : GamepadDevice(maple_port)
{
if (!find_mapping())
input_mapper = new KbInputMapping();
}
virtual const char* api_name() override { return "SDL"; }
virtual const char* name() override { return "Keyboard"; }
virtual ~SDLKbGamepadDevice() {}
};
class MouseInputMapping : public InputMapping
{
public:
MouseInputMapping()
{
name = "SDL Mouse";
set_button(DC_BTN_A, SDL_BUTTON_LEFT);
set_button(DC_BTN_B, SDL_BUTTON_RIGHT);
set_button(DC_BTN_START, SDL_BUTTON_MIDDLE);
dirty = false;
}
};
class SDLMouseGamepadDevice : public GamepadDevice
{
public:
SDLMouseGamepadDevice(int maple_port) : GamepadDevice(maple_port)
{
if (!find_mapping())
input_mapper = new MouseInputMapping();
}
virtual const char* api_name() override { return "SDL"; }
virtual const char* name() override { return "Mouse"; }
virtual ~SDLMouseGamepadDevice() {}
};

153
core/sdl/sdl_keyboard.h Normal file
View File

@ -0,0 +1,153 @@
#pragma once
#include "input/keyboard_device.h"
#include "sdl.h"
class SDLKeyboardDevice : public KeyboardDevice<SDL_Keycode>
{
public:
SDLKeyboardDevice(int maple_port) : KeyboardDevice(maple_port)
{
//04-1D Letter keys A-Z (in alphabetic order)
kb_map[SDLK_a] = 0x04;
kb_map[SDLK_b] = 0x05;
kb_map[SDLK_c] = 0x06;
kb_map[SDLK_d] = 0x07;
kb_map[SDLK_e] = 0x08;
kb_map[SDLK_f] = 0x09;
kb_map[SDLK_g] = 0x0A;
kb_map[SDLK_h] = 0x0B;
kb_map[SDLK_i] = 0x0C;
kb_map[SDLK_j] = 0x0D;
kb_map[SDLK_k] = 0x0E;
kb_map[SDLK_l] = 0x0F;
kb_map[SDLK_m] = 0x10;
kb_map[SDLK_n] = 0x11;
kb_map[SDLK_o] = 0x12;
kb_map[SDLK_p] = 0x13;
kb_map[SDLK_q] = 0x14;
kb_map[SDLK_r] = 0x15;
kb_map[SDLK_s] = 0x16;
kb_map[SDLK_t] = 0x17;
kb_map[SDLK_u] = 0x18;
kb_map[SDLK_v] = 0x19;
kb_map[SDLK_w] = 0x1A;
kb_map[SDLK_x] = 0x1B;
kb_map[SDLK_y] = 0x1C;
kb_map[SDLK_z] = 0x1D;
//1E-27 Number keys 1-0
kb_map[SDLK_1] = 0x1E;
kb_map[SDLK_2] = 0x1F;
kb_map[SDLK_3] = 0x20;
kb_map[SDLK_4] = 0x21;
kb_map[SDLK_5] = 0x22;
kb_map[SDLK_6] = 0x23;
kb_map[SDLK_7] = 0x24;
kb_map[SDLK_8] = 0x25;
kb_map[SDLK_9] = 0x26;
kb_map[SDLK_0] = 0x27;
kb_map[SDLK_RETURN] = 0x28;
kb_map[SDLK_ESCAPE] = 0x29;
kb_map[SDLK_BACKSPACE] = 0x2A;
kb_map[SDLK_TAB] = 0x2B;
kb_map[SDLK_SPACE] = 0x2C;
kb_map[SDLK_MINUS] = 0x2D; // -
kb_map[SDLK_EQUALS] = 0x2E; // =
kb_map[SDLK_LEFTBRACKET] = 0x2F; // [
kb_map[SDLK_RIGHTBRACKET] = 0x30; // ]
kb_map[SDLK_BACKSLASH] = 0x31; // \ (US) unsure of keycode
//32-34 "]", ";" and ":" (the 3 keys right of L)
kb_map[SDLK_ASTERISK] = 0x32; // ~ (non-US) *,µ in FR layout
kb_map[SDLK_SEMICOLON] = 0x33; // ;
kb_map[SDLK_QUOTE] = 0x34; // '
//35 hankaku/zenkaku / kanji (top left)
kb_map[SDLK_BACKQUOTE] = 0x35; // `~ (US)
//36-38 ",", "." and "/" (the 3 keys right of M)
kb_map[SDLK_COMMA] = 0x36;
kb_map[SDLK_PERIOD] = 0x37;
kb_map[SDLK_SLASH] = 0x38;
// CAPSLOCK
kb_map[SDLK_CAPSLOCK] = 0x39;
//3A-45 Function keys F1-F12
for (int i = 0;i < 10; i++)
kb_map[SDLK_F1 + i] = 0x3A + i;
kb_map[SDLK_F11] = 0x44;
kb_map[SDLK_F12] = 0x45;
//46-4E Control keys above cursor keys
kb_map[SDLK_PRINTSCREEN] = 0x46; // Print Screen
kb_map[SDLK_SCROLLLOCK] = 0x47; // Scroll Lock
kb_map[SDLK_PAUSE] = 0x48; // Pause
kb_map[SDLK_INSERT] = 0x49;
kb_map[SDLK_HOME] = 0x4A;
kb_map[SDLK_PAGEUP] = 0x4B;
kb_map[SDLK_DELETE] = 0x4C;
kb_map[SDLK_END] = 0x4D;
kb_map[SDLK_PAGEDOWN] = 0x4E;
//4F-52 Cursor keys
kb_map[SDLK_RIGHT] = 0x4F;
kb_map[SDLK_LEFT] = 0x50;
kb_map[SDLK_DOWN] = 0x51;
kb_map[SDLK_UP] = 0x52;
//53 Num Lock (Numeric keypad)
kb_map[SDLK_NUMLOCKCLEAR] = 0x53;
//54 "/" (Numeric keypad)
kb_map[SDLK_KP_DIVIDE] = 0x54;
//55 "*" (Numeric keypad)
kb_map[SDLK_KP_MULTIPLY] = 0x55;
//56 "-" (Numeric keypad)
kb_map[SDLK_KP_MINUS] = 0x56;
//57 "+" (Numeric keypad)
kb_map[SDLK_KP_PLUS] = 0x57;
//58 Enter (Numeric keypad)
kb_map[SDLK_KP_ENTER] = 0x58;
//59-62 Number keys 1-0 (Numeric keypad)
kb_map[SDLK_KP_1] = 0x59;
kb_map[SDLK_KP_2] = 0x5A;
kb_map[SDLK_KP_3] = 0x5B;
kb_map[SDLK_KP_4] = 0x5C;
kb_map[SDLK_KP_5] = 0x5D;
kb_map[SDLK_KP_6] = 0x5E;
kb_map[SDLK_KP_7] = 0x5F;
kb_map[SDLK_KP_8] = 0x60;
kb_map[SDLK_KP_9] = 0x61;
kb_map[SDLK_KP_0] = 0x62;
//63 "." (Numeric keypad)
kb_map[SDLK_KP_PERIOD] = 0x63;
//64 #| (non-US)
//kb_map[94] = 0x64;
//65 S3 key
//66-A4 Not used
//A5-DF Reserved
//E0 Left Control
//E1 Left Shift
//E2 Left Alt
//E3 Left S1
//E4 Right Control
//E5 Right Shift
//E6 Right Alt
//E7 Right S3
//E8-FF Reserved
}
virtual ~SDLKeyboardDevice() {}
virtual const char* name() override { return "SDL Keyboard"; }
protected:
virtual u8 convert_keycode(SDL_Keycode keycode) override
{
return kb_map[keycode];
}
private:
std::map<SDL_Keycode, u8> kb_map;
};

View File

@ -846,6 +846,8 @@ struct settings_t
u32 MouseSensitivity;
u32 JammaSetup; // 0: standard, 1: 4-players, 2: rotary encoders, 3: Sega Marine Fishing,
// 4: dual I/O boards (4P), 5: Namco JYU board (Ninja Assault)
int maple_devices[4];
int maple_expansion_devices[4][2];
} input;
};

View File

@ -120,7 +120,7 @@ void os_SetupInput()
{
init_kb_map();
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
mcfg_CreateDevicesFromConfig();
mcfg_CreateDevices();
#endif
}

View File

@ -105,7 +105,6 @@ int dc_init();
void dc_run();
void dc_pause();
void dc_term();
void mcfg_Create(MapleDeviceType type,u32 bus,u32 port);
bool VramLockedWrite(u8* address);
@ -214,16 +213,23 @@ void os_SetupInput()
{
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
// Create first controller
mcfg_CreateController(0, MDT_SegaVMU, GetMapleDeviceType(controller_periphs[0][1]));
settings.input.maple_devices[0] = MDT_SegaController;
settings.input.maple_expansion_devices[0][0] = MDT_SegaVMU;
settings.input.maple_expansion_devices[0][1] = GetMapleDeviceType(controller_periphs[0][1]);
// Add additonal controllers
for (int i = 0; i < 3; i++)
// Add additional controllers
for (int i = 1; i < 4; i++)
{
if (add_controllers[i])
mcfg_CreateController(i + 1,
GetMapleDeviceType(controller_periphs[i + 1][0]),
GetMapleDeviceType(controller_periphs[i + 1][1]));
if (add_controllers[i - 1])
{
settings.input.maple_devices[i] = MDT_SegaController;
settings.input.maple_expansion_devices[i][0] = GetMapleDeviceType(controller_periphs[i][0]);
settings.input.maple_expansion_devices[i][1] = GetMapleDeviceType(controller_periphs[i][1]);
}
else
settings.input.maple_devices[i] = MDT_None;
}
mcfg_CreateDevices();
#endif
}
@ -450,6 +456,7 @@ JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_send(JNIEnv *env,jobj
else if (cmd==2)
{
}
return 0;
}
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env, jobject obj, jint id, jbyteArray d)
@ -654,4 +661,4 @@ void SaveSettings()
if (detach_thread)
g_jvm->DetachCurrentThread();
}
}

View File

@ -105,7 +105,7 @@ void os_CreateWindow() {
void os_SetupInput() {
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
mcfg_CreateDevicesFromConfig();
mcfg_CreateDevices();
#endif
}

View File

@ -78,7 +78,7 @@ void os_CreateWindow() {
void os_SetupInput() {
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
mcfg_CreateDevicesFromConfig();
mcfg_CreateDevices();
#endif
init_kb_map();
}