Add Joystick type detection and Xbox controller support
* Add joystick type detection (with joystick_type setting to override it) * Fix multiple joysticks from interfering with each other by only reading from one (add joystick_id setting) * Add support for Xbox controllers
This commit is contained in:
parent
351cc2e79a
commit
bce0d458d8
|
@ -107,6 +107,12 @@ continuous_forward (Continuous forward) bool false
|
||||||
# Enable Joysticks
|
# Enable Joysticks
|
||||||
enable_joysticks (Enable Joysticks) bool false
|
enable_joysticks (Enable Joysticks) bool false
|
||||||
|
|
||||||
|
# The identifier of the joystick to use
|
||||||
|
joystick_id (Joystick ID) int 0
|
||||||
|
|
||||||
|
# The type of joystick
|
||||||
|
joystick_type (Joystick Type) enum auto auto,generic,xbox
|
||||||
|
|
||||||
# The time in seconds it takes between repeated events
|
# The time in seconds it takes between repeated events
|
||||||
# when holding down a joystick button combination.
|
# when holding down a joystick button combination.
|
||||||
repeat_joystick_button_time (Joystick button repetition interval) float 0.17
|
repeat_joystick_button_time (Joystick button repetition interval) float 0.17
|
||||||
|
|
|
@ -87,6 +87,14 @@
|
||||||
# type: bool
|
# type: bool
|
||||||
# enable_joysticks = false
|
# enable_joysticks = false
|
||||||
|
|
||||||
|
# The identifier of the joystick to use
|
||||||
|
# type: int
|
||||||
|
# joystick_id = 0
|
||||||
|
|
||||||
|
# The type of joystick
|
||||||
|
# type: enum values: auto,generic,xbox
|
||||||
|
# joystick_type = auto
|
||||||
|
|
||||||
# The time in seconds it takes between repeated events
|
# The time in seconds it takes between repeated events
|
||||||
# when holding down a joystick button combination.
|
# when holding down a joystick button combination.
|
||||||
# type: float
|
# type: float
|
||||||
|
@ -1786,4 +1794,3 @@ server_side_occlusion_culling = true
|
||||||
# Print the engine's profiling data in regular intervals (in seconds). 0 = disable. Useful for developers.
|
# Print the engine's profiling data in regular intervals (in seconds). 0 = disable. Useful for developers.
|
||||||
# type: int
|
# type: int
|
||||||
# profiler_print_interval = 0
|
# profiler_print_interval = 0
|
||||||
|
|
||||||
|
|
|
@ -127,10 +127,7 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
|
||||||
|
|
||||||
device->setResizable(true);
|
device->setResizable(true);
|
||||||
|
|
||||||
if (random_input)
|
init_input();
|
||||||
input = new RandomInputHandler();
|
|
||||||
else
|
|
||||||
input = new RealInputHandler(device, receiver);
|
|
||||||
|
|
||||||
smgr = device->getSceneManager();
|
smgr = device->getSceneManager();
|
||||||
smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
|
smgr->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
|
||||||
|
@ -337,6 +334,33 @@ bool ClientLauncher::init_engine()
|
||||||
return device != NULL;
|
return device != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientLauncher::init_input()
|
||||||
|
{
|
||||||
|
if (random_input)
|
||||||
|
input = new RandomInputHandler();
|
||||||
|
else
|
||||||
|
input = new RealInputHandler(device, receiver);
|
||||||
|
|
||||||
|
if (g_settings->getBool("enable_joysticks")) {
|
||||||
|
irr::core::array<irr::SJoystickInfo> infos;
|
||||||
|
std::vector<irr::SJoystickInfo> joystick_infos;
|
||||||
|
|
||||||
|
// Make sure this is called maximum once per
|
||||||
|
// irrlicht device, otherwise it will give you
|
||||||
|
// multiple events for the same joystick.
|
||||||
|
if (device->activateJoysticks(infos)) {
|
||||||
|
infostream << "Joystick support enabled" << std::endl;
|
||||||
|
joystick_infos.reserve(infos.size());
|
||||||
|
for (u32 i = 0; i < infos.size(); i++) {
|
||||||
|
joystick_infos.push_back(infos[i]);
|
||||||
|
}
|
||||||
|
input->joystick.onJoystickConnect(joystick_infos);
|
||||||
|
} else {
|
||||||
|
errorstream << "Could not activate joystick support." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ClientLauncher::launch_game(std::string &error_message,
|
bool ClientLauncher::launch_game(std::string &error_message,
|
||||||
bool reconnect_requested, GameParams &game_params,
|
bool reconnect_requested, GameParams &game_params,
|
||||||
const Settings &cmd_args)
|
const Settings &cmd_args)
|
||||||
|
@ -566,25 +590,8 @@ bool ClientLauncher::create_engine_device()
|
||||||
|
|
||||||
device = createDeviceEx(params);
|
device = createDeviceEx(params);
|
||||||
|
|
||||||
if (device) {
|
if (device)
|
||||||
if (g_settings->getBool("enable_joysticks")) {
|
|
||||||
irr::core::array<irr::SJoystickInfo> infos;
|
|
||||||
std::vector<irr::SJoystickInfo> joystick_infos;
|
|
||||||
// Make sure this is called maximum once per
|
|
||||||
// irrlicht device, otherwise it will give you
|
|
||||||
// multiple events for the same joystick.
|
|
||||||
if (device->activateJoysticks(infos)) {
|
|
||||||
infostream << "Joystick support enabled" << std::endl;
|
|
||||||
joystick_infos.reserve(infos.size());
|
|
||||||
for (u32 i = 0; i < infos.size(); i++) {
|
|
||||||
joystick_infos.push_back(infos[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errorstream << "Could not activate joystick support." << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
porting::initIrrlicht(device);
|
porting::initIrrlicht(device);
|
||||||
}
|
|
||||||
|
|
||||||
return device != NULL;
|
return device != NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void init_args(GameParams &game_params, const Settings &cmd_args);
|
void init_args(GameParams &game_params, const Settings &cmd_args);
|
||||||
bool init_engine();
|
bool init_engine();
|
||||||
|
void init_input();
|
||||||
|
|
||||||
bool launch_game(std::string &error_message, bool reconnect_requested,
|
bool launch_game(std::string &error_message, bool reconnect_requested,
|
||||||
GameParams &game_params, const Settings &cmd_args);
|
GameParams &game_params, const Settings &cmd_args);
|
||||||
|
|
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "keys.h"
|
#include "keys.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "gettime.h"
|
#include "gettime.h"
|
||||||
|
#include "../util/string.h"
|
||||||
|
|
||||||
bool JoystickButtonCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
|
bool JoystickButtonCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
|
||||||
{
|
{
|
||||||
|
@ -42,7 +43,7 @@ bool JoystickAxisCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
|
||||||
#define JLO_B_PB(A, B, C) jlo.button_keys.push_back(JoystickButtonCmb(A, B, C))
|
#define JLO_B_PB(A, B, C) jlo.button_keys.push_back(JoystickButtonCmb(A, B, C))
|
||||||
#define JLO_A_PB(A, B, C, D) jlo.axis_keys.push_back(JoystickAxisCmb(A, B, C, D))
|
#define JLO_A_PB(A, B, C, D) jlo.axis_keys.push_back(JoystickAxisCmb(A, B, C, D))
|
||||||
|
|
||||||
static JoystickLayout create_default_layout()
|
JoystickLayout create_default_layout()
|
||||||
{
|
{
|
||||||
JoystickLayout jlo;
|
JoystickLayout jlo;
|
||||||
|
|
||||||
|
@ -103,11 +104,59 @@ static JoystickLayout create_default_layout()
|
||||||
return jlo;
|
return jlo;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const JoystickLayout default_layout = create_default_layout();
|
JoystickLayout create_xbox_layout()
|
||||||
|
{
|
||||||
|
JoystickLayout jlo;
|
||||||
|
|
||||||
|
jlo.axes_dead_border = 7000;
|
||||||
|
|
||||||
|
const JoystickAxisLayout axes[JA_COUNT] = {
|
||||||
|
{0, 1}, // JA_SIDEWARD_MOVE
|
||||||
|
{1, 1}, // JA_FORWARD_MOVE
|
||||||
|
{2, 1}, // JA_FRUSTUM_HORIZONTAL
|
||||||
|
{3, 1}, // JA_FRUSTUM_VERTICAL
|
||||||
|
};
|
||||||
|
memcpy(jlo.axes, axes, sizeof(jlo.axes));
|
||||||
|
|
||||||
|
// The back button means "ESC".
|
||||||
|
JLO_B_PB(KeyType::ESC, 1 << 8, 1 << 8); // back
|
||||||
|
JLO_B_PB(KeyType::ESC, 1 << 9, 1 << 9); // start
|
||||||
|
|
||||||
|
// 4 Buttons
|
||||||
|
JLO_B_PB(KeyType::JUMP, 1 << 0, 1 << 0); // A/green
|
||||||
|
JLO_B_PB(KeyType::ESC, 1 << 1, 1 << 1); // B/red
|
||||||
|
JLO_B_PB(KeyType::SPECIAL1, 1 << 2, 1 << 2); // X/blue
|
||||||
|
JLO_B_PB(KeyType::INVENTORY, 1 << 3, 1 << 3); // Y/yellow
|
||||||
|
|
||||||
|
// Analog Sticks
|
||||||
|
JLO_B_PB(KeyType::SPECIAL1, 1 << 11, 1 << 11); // left
|
||||||
|
JLO_B_PB(KeyType::SNEAK, 1 << 12, 1 << 12); // right
|
||||||
|
|
||||||
|
// Triggers
|
||||||
|
JLO_B_PB(KeyType::MOUSE_L, 1 << 6, 1 << 6); // lt
|
||||||
|
JLO_B_PB(KeyType::MOUSE_R, 1 << 7, 1 << 7); // rt
|
||||||
|
JLO_B_PB(KeyType::SCROLL_UP, 1 << 4, 1 << 4); // lb
|
||||||
|
JLO_B_PB(KeyType::SCROLL_DOWN, 1 << 5, 1 << 5); // rb
|
||||||
|
|
||||||
|
// D-PAD
|
||||||
|
JLO_B_PB(KeyType::ZOOM, 1 << 15, 1 << 15); // up
|
||||||
|
JLO_B_PB(KeyType::DROP, 1 << 13, 1 << 13); // left
|
||||||
|
JLO_B_PB(KeyType::SCREENSHOT, 1 << 14, 1 << 14); // right
|
||||||
|
JLO_B_PB(KeyType::FREEMOVE, 1 << 16, 1 << 16); // down
|
||||||
|
|
||||||
|
// Movement buttons, important for vessels
|
||||||
|
JLO_A_PB(KeyType::FORWARD, 1, 1, 1024);
|
||||||
|
JLO_A_PB(KeyType::BACKWARD, 1, -1, 1024);
|
||||||
|
JLO_A_PB(KeyType::LEFT, 0, 1, 1024);
|
||||||
|
JLO_A_PB(KeyType::RIGHT, 0, -1, 1024);
|
||||||
|
|
||||||
|
return jlo;
|
||||||
|
}
|
||||||
|
|
||||||
JoystickController::JoystickController()
|
JoystickController::JoystickController()
|
||||||
{
|
{
|
||||||
m_layout = &default_layout;
|
m_joystick_id = 0;
|
||||||
|
|
||||||
doubling_dtime = g_settings->getFloat("repeat_joystick_button_time");
|
doubling_dtime = g_settings->getFloat("repeat_joystick_button_time");
|
||||||
|
|
||||||
for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
|
for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
|
||||||
|
@ -116,23 +165,54 @@ JoystickController::JoystickController()
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JoystickController::onJoystickConnect(const std::vector<irr::SJoystickInfo> &joystick_infos)
|
||||||
|
{
|
||||||
|
s32 id = g_settings->getS32("joystick_id");
|
||||||
|
std::string layout = g_settings->get("joystick_type");
|
||||||
|
|
||||||
|
if (id < 0 || id >= joystick_infos.size()) {
|
||||||
|
// TODO: auto detection
|
||||||
|
id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id >= 0 && id < joystick_infos.size()) {
|
||||||
|
if (layout.empty() || layout == "auto")
|
||||||
|
setLayoutFromControllerName(joystick_infos[id].Name.c_str());
|
||||||
|
else
|
||||||
|
setLayoutFromControllerName(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_joystick_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JoystickController::setLayoutFromControllerName(std::string name) {
|
||||||
|
if (lowercase(name).find("xbox") >= 0) {
|
||||||
|
m_layout = create_xbox_layout();
|
||||||
|
} else {
|
||||||
|
m_layout = create_default_layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
|
bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
|
||||||
{
|
{
|
||||||
|
if (ev.Joystick != m_joystick_id)
|
||||||
|
return false;
|
||||||
|
|
||||||
m_internal_time = getTimeMs() / 1000.f;
|
m_internal_time = getTimeMs() / 1000.f;
|
||||||
|
|
||||||
std::bitset<KeyType::INTERNAL_ENUM_COUNT> keys_pressed;
|
std::bitset<KeyType::INTERNAL_ENUM_COUNT> keys_pressed;
|
||||||
|
|
||||||
// First generate a list of keys pressed
|
// First generate a list of keys pressed
|
||||||
|
|
||||||
for (size_t i = 0; i < m_layout->button_keys.size(); i++) {
|
for (size_t i = 0; i < m_layout.button_keys.size(); i++) {
|
||||||
if (m_layout->button_keys[i].isTriggered(ev)) {
|
if (m_layout.button_keys[i].isTriggered(ev)) {
|
||||||
keys_pressed.set(m_layout->button_keys[i].key);
|
keys_pressed.set(m_layout.button_keys[i].key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < m_layout->axis_keys.size(); i++) {
|
for (size_t i = 0; i < m_layout.axis_keys.size(); i++) {
|
||||||
if (m_layout->axis_keys[i].isTriggered(ev)) {
|
if (m_layout.axis_keys[i].isTriggered(ev)) {
|
||||||
keys_pressed.set(m_layout->axis_keys[i].key);
|
keys_pressed.set(m_layout.axis_keys[i].key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +233,7 @@ bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < JA_COUNT; i++) {
|
for (size_t i = 0; i < JA_COUNT; i++) {
|
||||||
const JoystickAxisLayout &ax_la = m_layout->axes[i];
|
const JoystickAxisLayout &ax_la = m_layout.axes[i];
|
||||||
m_axes_vals[i] = ax_la.invert * ev.Axis[ax_la.axis_id];
|
m_axes_vals[i] = ax_la.invert * ev.Axis[ax_la.axis_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,8 +252,8 @@ void JoystickController::clear()
|
||||||
s16 JoystickController::getAxisWithoutDead(JoystickAxis axis)
|
s16 JoystickController::getAxisWithoutDead(JoystickAxis axis)
|
||||||
{
|
{
|
||||||
s16 v = m_axes_vals[axis];
|
s16 v = m_axes_vals[axis];
|
||||||
if (((v > 0) && (v < m_layout->axes_dead_border)) ||
|
if (((v > 0) && (v < m_layout.axes_dead_border)) ||
|
||||||
((v < 0) && (v > -m_layout->axes_dead_border)))
|
((v < 0) && (v > -m_layout.axes_dead_border)))
|
||||||
return 0;
|
return 0;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,9 @@ class JoystickController {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JoystickController();
|
JoystickController();
|
||||||
|
|
||||||
|
void onJoystickConnect(const std::vector<irr::SJoystickInfo> &joystick_infos);
|
||||||
|
|
||||||
bool handleEvent(const irr::SEvent::SJoystickEvent &ev);
|
bool handleEvent(const irr::SEvent::SJoystickEvent &ev);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
@ -146,10 +149,14 @@ public:
|
||||||
f32 doubling_dtime;
|
f32 doubling_dtime;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const JoystickLayout *m_layout;
|
void setLayoutFromControllerName(std::string name);
|
||||||
|
|
||||||
|
JoystickLayout m_layout;
|
||||||
|
|
||||||
s16 m_axes_vals[JA_COUNT];
|
s16 m_axes_vals[JA_COUNT];
|
||||||
|
|
||||||
|
u8 m_joystick_id;
|
||||||
|
|
||||||
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_pressed_keys;
|
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_pressed_keys;
|
||||||
|
|
||||||
f32 m_internal_time;
|
f32 m_internal_time;
|
||||||
|
|
|
@ -203,6 +203,8 @@ void set_default_settings(Settings *settings)
|
||||||
settings->setDefault("always_fly_fast", "true");
|
settings->setDefault("always_fly_fast", "true");
|
||||||
settings->setDefault("continuous_forward", "false");
|
settings->setDefault("continuous_forward", "false");
|
||||||
settings->setDefault("enable_joysticks", "false");
|
settings->setDefault("enable_joysticks", "false");
|
||||||
|
settings->setDefault("joystick_id", "0");
|
||||||
|
settings->setDefault("joystick_type", "");
|
||||||
settings->setDefault("repeat_joystick_button_time", "0.17");
|
settings->setDefault("repeat_joystick_button_time", "0.17");
|
||||||
settings->setDefault("joystick_frustum_sensitivity", "170");
|
settings->setDefault("joystick_frustum_sensitivity", "170");
|
||||||
|
|
||||||
|
|
|
@ -171,4 +171,3 @@ void the_game(bool *kill,
|
||||||
bool simple_singleplayer_mode);
|
bool simple_singleplayer_mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue