diff --git a/SConstruct b/SConstruct index ce25c82..055a441 100644 --- a/SConstruct +++ b/SConstruct @@ -53,6 +53,7 @@ env.Program('xboxdrv', ['src/xboxdrv.cpp', 'src/button_event.cpp', 'src/axis_event.cpp', 'src/arg_parser.cpp', + 'src/button_map.cpp', 'src/pretty_printer.cpp', 'src/helper.cpp', 'src/modifier.cpp', diff --git a/src/button_map.cpp b/src/button_map.cpp new file mode 100644 index 0000000..39aaa6e --- /dev/null +++ b/src/button_map.cpp @@ -0,0 +1,62 @@ +/* +** Xbox360 USB Gamepad Userspace Driver +** Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de> +** +** This program 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 3 of the License, or +** (at your option) any later version. +** +** This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "button_map.hpp" + +ButtonMap::ButtonMap() +{ + clear(); +} + +void +ButtonMap::bind(int code, const ButtonEvent& event) +{ + btn_map[XBOX_BTN_UNKNOWN][code] = event; +} + +void +ButtonMap::bind(int shift_code, int code, const ButtonEvent& event) +{ + btn_map[shift_code][code] = event; +} + +ButtonEvent +ButtonMap::lookup(int code) const +{ + return btn_map[XBOX_BTN_UNKNOWN][code]; +} + +ButtonEvent +ButtonMap::lookup_shift(int shift_code, int code) const +{ + return btn_map[shift_code][code]; +} + +void +ButtonMap::clear() +{ + for(int shift_code = 0; shift_code < XBOX_BTN_MAX; ++shift_code) + { + for(int code = 0; code < XBOX_BTN_MAX; ++code) + { + btn_map[shift_code][code] = ButtonEvent::invalid(); + } + } +} + +/* EOF */ diff --git a/src/button_map.hpp b/src/button_map.hpp new file mode 100644 index 0000000..70240a8 --- /dev/null +++ b/src/button_map.hpp @@ -0,0 +1,126 @@ +/* +** Xbox360 USB Gamepad Userspace Driver +** Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de> +** +** This program 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 3 of the License, or +** (at your option) any later version. +** +** This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef HEADER_XBOXDRV_BUTTON_MAP_HPP +#define HEADER_XBOXDRV_BUTTON_MAP_HPP + +#include <assert.h> +#include <iostream> + +#include "button_event.hpp" +#include "xboxmsg.hpp" + +class ButtonMap +{ +private: + ButtonEvent btn_map[XBOX_BTN_MAX][XBOX_BTN_MAX]; + +public: + ButtonMap(); + + void bind(int code, const ButtonEvent& event); + void bind(int shift_code, int code, const ButtonEvent& event); + + ButtonEvent lookup(int code) const; + ButtonEvent lookup_shift(int shift_code, int code) const; + + void clear(); + + template<class Pred> + bool contains(const Pred& pred) + { + for(int shift_code = 0; shift_code < XBOX_BTN_MAX; ++shift_code) + { + for(int code = 0; code < XBOX_BTN_MAX; ++code) + { + if (pred(btn_map[shift_code][code])) + { + return true; + } + } + } + return false; + } + + struct iterator + { + friend class ButtonMap; + private: + ButtonMap& btn_map; + int j; + int i; + + iterator(ButtonMap& btn_map_) : + btn_map(btn_map_), + j(0), + i(0) + {} + + iterator(ButtonMap& btn_map_, int j_, int i_) : + btn_map(btn_map_), + j(j_), + i(i_) + {} + + public: + void operator++() + { + assert(j < XBOX_BTN_MAX); + + i += 1; + if (i == XBOX_BTN_MAX) + { + i = 0; + j += 1; + } + } + + const ButtonEvent& operator*() const + { + return btn_map.btn_map[j][i]; + } + + const ButtonEvent& operator->() const + { + return btn_map.btn_map[j][i]; + } + + ButtonEvent& operator*() + { + return btn_map.btn_map[j][i]; + } + + ButtonEvent& operator->() + { + return btn_map.btn_map[j][i]; + } + + bool operator!=(const iterator& rhs) const + { + assert(&btn_map == &rhs.btn_map); + return (j != rhs.j || i != rhs.i); + } + }; + + iterator begin() { return iterator(*this); } + iterator end() { return iterator(*this, XBOX_BTN_MAX, 0); } +}; + +#endif + +/* EOF */ diff --git a/src/command_line_options.cpp b/src/command_line_options.cpp index adca14e..5996c31 100644 --- a/src/command_line_options.cpp +++ b/src/command_line_options.cpp @@ -180,7 +180,7 @@ CommandLineOptions::CommandLineOptions() : .add_text("Report bugs to Ingo Ruhnke <grumbel@gmx.de>"); } -void set_ui_button_map(ButtonEvent* ui_button_map, const std::string& str) +void set_ui_button_map(ButtonMap& ui_button_map, const std::string& str) { std::string::size_type i = str.find_first_of('='); if (i == std::string::npos) @@ -196,7 +196,7 @@ void set_ui_button_map(ButtonEvent* ui_button_map, const std::string& str) if (btn != XBOX_BTN_UNKNOWN) { - ui_button_map[btn] = event; + ui_button_map.bind(btn, event); } else { @@ -367,8 +367,7 @@ CommandLineOptions::parse_args(int argc, char** argv) case OPTION_UI_CLEAR: std::fill_n(opts.uinput_config.axis_map, static_cast<int>(XBOX_AXIS_MAX), AxisEvent::invalid()); - for(int i = 0; i < XBOX_BTN_MAX; ++i) - std::fill_n(opts.uinput_config.btn_map[i], static_cast<int>(XBOX_BTN_MAX), ButtonEvent::invalid()); + opts.uinput_config.btn_map.clear(); break; case OPTION_UI_AXISMAP: @@ -376,7 +375,7 @@ CommandLineOptions::parse_args(int argc, char** argv) break; case OPTION_UI_BUTTONMAP: - arg2apply(opt.argument, boost::bind(&set_ui_button_map, opts.uinput_config.btn_map[XBOX_BTN_UNKNOWN], _1)); + arg2apply(opt.argument, boost::bind(&set_ui_button_map, opts.uinput_config.btn_map, _1)); break; case OPTION_ID: diff --git a/src/uinput.cpp b/src/uinput.cpp index f9947af..e61e45b 100644 --- a/src/uinput.cpp +++ b/src/uinput.cpp @@ -33,19 +33,40 @@ #include "uinput.hpp" #include "uinput_deviceid.hpp" +bool is_keyboard_event(const ButtonEvent& event) +{ + if (event.type == EV_KEY && uInput::is_keyboard_button(event.code)) + { + return true; + } + else + { + return false; + } +} + +bool is_mouse_event(const ButtonEvent& event) +{ + if (event.type == EV_KEY && uInput::is_mouse_button(event.code)) + { + return true; + } + else if (event.type == EV_REL) + { + return true; + } + else + { + return false; + } +} + bool uInput::need_keyboard_device() { - for(int j = 0; j < XBOX_BTN_MAX; ++j) + if (cfg.btn_map.contains(is_keyboard_event)) { - for(int i = 0; i < XBOX_BTN_MAX; ++i) - { - if (cfg.btn_map[j][i].type == EV_KEY && - is_keyboard_button(cfg.btn_map[j][i].code)) - { - return true; - } - } + return true; } for(int i = 0; i < XBOX_AXIS_MAX; ++i) @@ -64,20 +85,9 @@ uInput::need_keyboard_device() bool uInput::need_mouse_device() { - for(int j = 0; j < XBOX_BTN_MAX; ++j) + if (cfg.btn_map.contains(is_mouse_event)) { - for(int i = 0; i < XBOX_BTN_MAX; ++i) - { - if (cfg.btn_map[j][i].type == EV_KEY && - is_mouse_button(cfg.btn_map[j][i].code)) - { - return true; - } - else if (cfg.btn_map[j][i].type == EV_REL) - { - return true; - } - } + return true; } for(int i = 0; i < XBOX_AXIS_MAX; ++i) @@ -131,12 +141,9 @@ uInput::uInput(const XPadDevice& dev, uInputCfg config_) : create_uinput_device(0); } - for(int j = 0; j < XBOX_BTN_MAX; ++j) + for(ButtonMap::iterator i = cfg.btn_map.begin(); i != cfg.btn_map.end(); ++i) { - for(int i = 0; i < XBOX_BTN_MAX; ++i) - { - cfg.btn_map[j][i].device_id = create_uinput_device(cfg.btn_map[j][i]); - } + (*i).device_id = create_uinput_device(*i); } for(int i = 0; i < XBOX_AXIS_MAX; ++i) @@ -657,9 +664,9 @@ uInput::update(int msec_delta) if (i->time >= i->next_time) { - get_mouse_uinput()->send(EV_REL, cfg.btn_map[XBOX_BTN_UNKNOWN][i->button].code, - static_cast<int>(cfg.btn_map[XBOX_BTN_UNKNOWN][i->button].rel.value * button_state[i->button])); - i->next_time += cfg.btn_map[XBOX_BTN_UNKNOWN][i->button].rel.repeat; + get_mouse_uinput()->send(EV_REL, cfg.btn_map.lookup(i->button).code, + static_cast<int>(cfg.btn_map.lookup(i->button).rel.value * button_state[i->button])); + i->next_time += cfg.btn_map.lookup(i->button).rel.repeat; needs_syncronization = true; } } @@ -680,7 +687,7 @@ uInput::send_button(int code, bool value) { button_state[code] = value; - const ButtonEvent& event = cfg.btn_map[XBOX_BTN_UNKNOWN][code]; + const ButtonEvent& event = cfg.btn_map.lookup(code); send_key(event.device_id, event.code, value); } @@ -803,7 +810,7 @@ uInput::add_axis(int code, int min, int max) void uInput::add_button(int code) { - const ButtonEvent& event = cfg.btn_map[XBOX_BTN_UNKNOWN][code]; + const ButtonEvent& event = cfg.btn_map.lookup(code); if (event.type == EV_KEY) { diff --git a/src/uinput.hpp b/src/uinput.hpp index c7930c2..e6f58d6 100644 --- a/src/uinput.hpp +++ b/src/uinput.hpp @@ -102,8 +102,9 @@ private: bool need_keyboard_device(); bool need_joystick_device(); - bool is_mouse_button(int ev_code); - bool is_keyboard_button(int ev_code); +public: + static bool is_mouse_button(int ev_code); + static bool is_keyboard_button(int ev_code); }; #endif diff --git a/src/uinput_cfg.cpp b/src/uinput_cfg.cpp index c8ed687..fa72c13 100644 --- a/src/uinput_cfg.cpp +++ b/src/uinput_cfg.cpp @@ -29,44 +29,41 @@ uInputCfg::uInputCfg() : force_feedback(false), extra_devices(true) { - for(int i = 0; i < XBOX_BTN_MAX; ++i) - std::fill_n(btn_map[i], static_cast<int>(XBOX_BTN_MAX), ButtonEvent::invalid()); + btn_map.clear(); std::fill_n(axis_map, static_cast<int>(XBOX_AXIS_MAX), AxisEvent::invalid()); - ButtonEvent* bmap = btn_map[XBOX_BTN_UNKNOWN]; // FIXME: little hacky to abuse XBOX_BTN_UNKNOWN - // Button Mapping - bmap[XBOX_BTN_START] = ButtonEvent::create(EV_KEY, BTN_START); - bmap[XBOX_BTN_GUIDE] = ButtonEvent::create(EV_KEY, BTN_MODE); - bmap[XBOX_BTN_BACK] = ButtonEvent::create(EV_KEY, BTN_SELECT); + btn_map.bind(XBOX_BTN_START, ButtonEvent::create(EV_KEY, BTN_START)); + btn_map.bind(XBOX_BTN_GUIDE, ButtonEvent::create(EV_KEY, BTN_MODE)); + btn_map.bind(XBOX_BTN_BACK, ButtonEvent::create(EV_KEY, BTN_SELECT)); - bmap[XBOX_BTN_A] = ButtonEvent::create(EV_KEY, BTN_A); - bmap[XBOX_BTN_B] = ButtonEvent::create(EV_KEY, BTN_B); - bmap[XBOX_BTN_X] = ButtonEvent::create(EV_KEY, BTN_X); - bmap[XBOX_BTN_Y] = ButtonEvent::create(EV_KEY, BTN_Y); + btn_map.bind(XBOX_BTN_A, ButtonEvent::create(EV_KEY, BTN_A)); + btn_map.bind(XBOX_BTN_B, ButtonEvent::create(EV_KEY, BTN_B)); + btn_map.bind(XBOX_BTN_X, ButtonEvent::create(EV_KEY, BTN_X)); + btn_map.bind(XBOX_BTN_Y, ButtonEvent::create(EV_KEY, BTN_Y)); - bmap[XBOX_BTN_GREEN] = ButtonEvent::create(EV_KEY, BTN_0); - bmap[XBOX_BTN_RED] = ButtonEvent::create(EV_KEY, BTN_1); - bmap[XBOX_BTN_YELLOW] = ButtonEvent::create(EV_KEY, BTN_2); - bmap[XBOX_BTN_BLUE] = ButtonEvent::create(EV_KEY, BTN_3); - bmap[XBOX_BTN_ORANGE] = ButtonEvent::create(EV_KEY, BTN_4); + btn_map.bind(XBOX_BTN_GREEN, ButtonEvent::create(EV_KEY, BTN_0)); + btn_map.bind(XBOX_BTN_RED, ButtonEvent::create(EV_KEY, BTN_1)); + btn_map.bind(XBOX_BTN_YELLOW, ButtonEvent::create(EV_KEY, BTN_2)); + btn_map.bind(XBOX_BTN_BLUE, ButtonEvent::create(EV_KEY, BTN_3)); + btn_map.bind(XBOX_BTN_ORANGE, ButtonEvent::create(EV_KEY, BTN_4)); - bmap[XBOX_BTN_WHITE] = ButtonEvent::create(EV_KEY, BTN_TL); - bmap[XBOX_BTN_BLACK] = ButtonEvent::create(EV_KEY, BTN_TR); + btn_map.bind(XBOX_BTN_WHITE, ButtonEvent::create(EV_KEY, BTN_TL)); + btn_map.bind(XBOX_BTN_BLACK, ButtonEvent::create(EV_KEY, BTN_TR)); - bmap[XBOX_BTN_LB] = ButtonEvent::create(EV_KEY, BTN_TL); - bmap[XBOX_BTN_RB] = ButtonEvent::create(EV_KEY, BTN_TR); + btn_map.bind(XBOX_BTN_LB, ButtonEvent::create(EV_KEY, BTN_TL)); + btn_map.bind(XBOX_BTN_RB, ButtonEvent::create(EV_KEY, BTN_TR)); - bmap[XBOX_BTN_LT] = ButtonEvent::create(EV_KEY, BTN_TL2); - bmap[XBOX_BTN_RT] = ButtonEvent::create(EV_KEY, BTN_TR2); + btn_map.bind(XBOX_BTN_LT, ButtonEvent::create(EV_KEY, BTN_TL2)); + btn_map.bind(XBOX_BTN_RT, ButtonEvent::create(EV_KEY, BTN_TR2)); - bmap[XBOX_BTN_THUMB_L] = ButtonEvent::create(EV_KEY, BTN_THUMBL); - bmap[XBOX_BTN_THUMB_R] = ButtonEvent::create(EV_KEY, BTN_THUMBR); + btn_map.bind(XBOX_BTN_THUMB_L, ButtonEvent::create(EV_KEY, BTN_THUMBL)); + btn_map.bind(XBOX_BTN_THUMB_R, ButtonEvent::create(EV_KEY, BTN_THUMBR)); - bmap[XBOX_DPAD_UP] = ButtonEvent::create(EV_KEY, BTN_BASE); - bmap[XBOX_DPAD_DOWN] = ButtonEvent::create(EV_KEY, BTN_BASE2); - bmap[XBOX_DPAD_LEFT] = ButtonEvent::create(EV_KEY, BTN_BASE3); - bmap[XBOX_DPAD_RIGHT] = ButtonEvent::create(EV_KEY, BTN_BASE4); + btn_map.bind(XBOX_DPAD_UP, ButtonEvent::create(EV_KEY, BTN_BASE)); + btn_map.bind(XBOX_DPAD_DOWN, ButtonEvent::create(EV_KEY, BTN_BASE2)); + btn_map.bind(XBOX_DPAD_LEFT, ButtonEvent::create(EV_KEY, BTN_BASE3)); + btn_map.bind(XBOX_DPAD_RIGHT, ButtonEvent::create(EV_KEY, BTN_BASE4)); // Axis Mapping axis_map[XBOX_AXIS_X1] = AxisEvent::create(EV_ABS, ABS_X); @@ -87,39 +84,37 @@ uInputCfg::mimic_xpad() extra_devices = false; - ButtonEvent* bmap = btn_map[XBOX_BTN_UNKNOWN]; // FIXME: little hacky to abuse XBOX_BTN_UNKNOWN + btn_map.bind(XBOX_BTN_START, ButtonEvent::create(EV_KEY, BTN_START)); + btn_map.bind(XBOX_BTN_GUIDE, ButtonEvent::create(EV_KEY, BTN_MODE)); + btn_map.bind(XBOX_BTN_BACK, ButtonEvent::create(EV_KEY, BTN_BACK)); - bmap[XBOX_BTN_START] = ButtonEvent::create(EV_KEY, BTN_START); - bmap[XBOX_BTN_GUIDE] = ButtonEvent::create(EV_KEY, BTN_MODE); - bmap[XBOX_BTN_BACK] = ButtonEvent::create(EV_KEY, BTN_BACK); + btn_map.bind(XBOX_BTN_A, ButtonEvent::create(EV_KEY, BTN_A)); + btn_map.bind(XBOX_BTN_B, ButtonEvent::create(EV_KEY, BTN_B)); + btn_map.bind(XBOX_BTN_X, ButtonEvent::create(EV_KEY, BTN_X)); + btn_map.bind(XBOX_BTN_Y, ButtonEvent::create(EV_KEY, BTN_Y)); - bmap[XBOX_BTN_A] = ButtonEvent::create(EV_KEY, BTN_A); - bmap[XBOX_BTN_B] = ButtonEvent::create(EV_KEY, BTN_B); - bmap[XBOX_BTN_X] = ButtonEvent::create(EV_KEY, BTN_X); - bmap[XBOX_BTN_Y] = ButtonEvent::create(EV_KEY, BTN_Y); + btn_map.bind(XBOX_BTN_GREEN, ButtonEvent::create(EV_KEY, BTN_0)); + btn_map.bind(XBOX_BTN_RED, ButtonEvent::create(EV_KEY, BTN_1)); + btn_map.bind(XBOX_BTN_YELLOW, ButtonEvent::create(EV_KEY, BTN_2)); + btn_map.bind(XBOX_BTN_BLUE, ButtonEvent::create(EV_KEY, BTN_3)); + btn_map.bind(XBOX_BTN_ORANGE, ButtonEvent::create(EV_KEY, BTN_4)); - bmap[XBOX_BTN_GREEN] = ButtonEvent::create(EV_KEY, BTN_0); - bmap[XBOX_BTN_RED] = ButtonEvent::create(EV_KEY, BTN_1); - bmap[XBOX_BTN_YELLOW] = ButtonEvent::create(EV_KEY, BTN_2); - bmap[XBOX_BTN_BLUE] = ButtonEvent::create(EV_KEY, BTN_3); - bmap[XBOX_BTN_ORANGE] = ButtonEvent::create(EV_KEY, BTN_4); + btn_map.bind(XBOX_BTN_WHITE, ButtonEvent::create(EV_KEY, BTN_TL)); + btn_map.bind(XBOX_BTN_BLACK, ButtonEvent::create(EV_KEY, BTN_TR)); - bmap[XBOX_BTN_WHITE] = ButtonEvent::create(EV_KEY, BTN_TL); - bmap[XBOX_BTN_BLACK] = ButtonEvent::create(EV_KEY, BTN_TR); - - bmap[XBOX_BTN_LB] = ButtonEvent::create(EV_KEY, BTN_TL); - bmap[XBOX_BTN_RB] = ButtonEvent::create(EV_KEY, BTN_TR); + btn_map.bind(XBOX_BTN_LB, ButtonEvent::create(EV_KEY, BTN_TL)); + btn_map.bind(XBOX_BTN_RB, ButtonEvent::create(EV_KEY, BTN_TR)); - bmap[XBOX_BTN_LT] = ButtonEvent::create(EV_KEY, BTN_TL2); - bmap[XBOX_BTN_RT] = ButtonEvent::create(EV_KEY, BTN_TR2); + btn_map.bind(XBOX_BTN_LT, ButtonEvent::create(EV_KEY, BTN_TL2)); + btn_map.bind(XBOX_BTN_RT, ButtonEvent::create(EV_KEY, BTN_TR2)); - bmap[XBOX_BTN_THUMB_L] = ButtonEvent::create(EV_KEY, BTN_THUMBL); - bmap[XBOX_BTN_THUMB_R] = ButtonEvent::create(EV_KEY, BTN_THUMBR); + btn_map.bind(XBOX_BTN_THUMB_L, ButtonEvent::create(EV_KEY, BTN_THUMBL)); + btn_map.bind(XBOX_BTN_THUMB_R, ButtonEvent::create(EV_KEY, BTN_THUMBR)); - bmap[XBOX_DPAD_UP] = ButtonEvent::create(EV_KEY, BTN_BASE); - bmap[XBOX_DPAD_DOWN] = ButtonEvent::create(EV_KEY, BTN_BASE2); - bmap[XBOX_DPAD_LEFT] = ButtonEvent::create(EV_KEY, BTN_BASE3); - bmap[XBOX_DPAD_RIGHT] = ButtonEvent::create(EV_KEY, BTN_BASE4); + btn_map.bind(XBOX_DPAD_UP, ButtonEvent::create(EV_KEY, BTN_BASE)); + btn_map.bind(XBOX_DPAD_DOWN, ButtonEvent::create(EV_KEY, BTN_BASE2)); + btn_map.bind(XBOX_DPAD_LEFT, ButtonEvent::create(EV_KEY, BTN_BASE3)); + btn_map.bind(XBOX_DPAD_RIGHT, ButtonEvent::create(EV_KEY, BTN_BASE4)); // Axis Mapping axis_map[XBOX_AXIS_X1] = AxisEvent::create(EV_ABS, ABS_X, 16, 128); diff --git a/src/uinput_cfg.hpp b/src/uinput_cfg.hpp index 607e6e7..44c1f97 100644 --- a/src/uinput_cfg.hpp +++ b/src/uinput_cfg.hpp @@ -21,6 +21,7 @@ #include "axis_event.hpp" #include "button_event.hpp" +#include "button_map.hpp" #include "xboxmsg.hpp" class uInputCfg @@ -34,8 +35,8 @@ public: bool force_feedback; bool extra_devices; - ButtonEvent btn_map[XBOX_BTN_MAX][XBOX_BTN_MAX]; - AxisEvent axis_map[XBOX_AXIS_MAX]; + ButtonMap btn_map; + AxisEvent axis_map[XBOX_AXIS_MAX]; uInputCfg();