diff --git a/src/arg_parser.hpp b/src/arg_parser.hpp index b96c06b..0e4fbd4 100644 --- a/src/arg_parser.hpp +++ b/src/arg_parser.hpp @@ -20,6 +20,7 @@ #define HEADER_ARG_PARSER_HPP #include <string> +#include <iostream> #include <vector> class ArgParser diff --git a/src/command_line_options.cpp b/src/command_line_options.cpp index 2b83047..05fc9c4 100644 --- a/src/command_line_options.cpp +++ b/src/command_line_options.cpp @@ -16,6 +16,8 @@ ** along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "command_line_options.hpp" + #include <stdio.h> #include <iostream> #include <stdexcept> @@ -26,7 +28,8 @@ #include "arg_parser.hpp" #include "helper.hpp" #include "uinput_deviceid.hpp" -#include "command_line_options.hpp" +#include "options.hpp" +#include "ini_schema.hpp" #define RAISE_EXCEPTION(x) do { \ std::ostringstream kiJk8f08d4oMX; \ @@ -34,7 +37,7 @@ throw std::runtime_error(kiJk8f08d4oMX.str()); \ } while(0) -CommandLineOptions* command_line_options = 0; +Options* g__options = 0; enum { OPTION_HELP, @@ -88,42 +91,9 @@ enum { OPTION_HELP_DEVICES }; -CommandLineOptions::CommandLineOptions() : - mode(RUN_DEFAULT), - verbose(false), - silent (false), - quiet (false), - rumble (false), - led (-1), - rumble_l(-1), - rumble_r(-1), - rumble_gain(255), - controller_id(0), - wireless_id(0), - instant_exit(false), - no_uinput(false), - detach_kernel_driver(), - gamepad_type(GAMEPAD_UNKNOWN), - vendor_id(-1), - product_id(-1), - uinput_config(), - deadzone(0), - deadzone_trigger(0), - button_map(), - axis_map(), - autofire_map(), - relative_axis_map(), - calibration_map(), - axis_sensitivity_map(), - square_axis(false), - four_way_restrictor(false), - dpad_rotation(0), - evdev_device(), +CommandLineParser::CommandLineParser() : argp() { - busid[0] = '\0'; - devid[0] = '\0'; - argp .add_usage("[OPTION]...") .add_text("Xbox360 USB Gamepad Userspace Driver") @@ -264,23 +234,23 @@ void set_evdev_keymap(std::map<int, XboxButton>& keymap, const std::string& str) } void -CommandLineOptions::parse_args(int argc, char** argv) +CommandLineParser::parse_args(int argc, char** argv, Options* options) { ArgParser::ParsedOptions parsed = argp.parse_args(argc, argv); for(ArgParser::ParsedOptions::const_iterator i = parsed.begin(); i != parsed.end(); ++i) { - CommandLineOptions& opts = *this; + Options& opts = *options; const ArgParser::ParsedOption& opt = *i; switch (i->key) { case OPTION_HELP: - opts.mode = PRINT_HELP; + opts.mode = Options::PRINT_HELP; break; case OPTION_VERSION: - opts.mode = PRINT_VERSION; + opts.mode = Options::PRINT_VERSION; break; case OPTION_VERBOSE: @@ -297,7 +267,7 @@ CommandLineOptions::parse_args(int argc, char** argv) case OPTION_DAEMON: opts.silent = true; - opts.mode = RUN_DAEMON; + opts.mode = Options::RUN_DAEMON; break; case OPTION_TEST_RUMBLE: @@ -457,7 +427,7 @@ CommandLineOptions::parse_args(int argc, char** argv) case OPTION_LED: if (opt.argument == "help") { - opts.mode = PRINT_LED_HELP; + opts.mode = Options::PRINT_LED_HELP; } else { @@ -519,14 +489,14 @@ CommandLineOptions::parse_args(int argc, char** argv) break; case OPTION_DPAD_ROTATION: - { - int degree = boost::lexical_cast<int>(opt.argument); - degree /= 45; - degree %= 8; - if (degree < 0) degree += 8; - opts.dpad_rotation = degree; - } - break; + { + int degree = boost::lexical_cast<int>(opt.argument); + degree /= 45; + degree %= 8; + if (degree < 0) degree += 8; + opts.dpad_rotation = degree; + } + break; case OPTION_SQUARE_AXIS: opts.square_axis = true; @@ -544,46 +514,56 @@ CommandLineOptions::parse_args(int argc, char** argv) break; case OPTION_HELP_LED: - opts.mode = PRINT_LED_HELP; + opts.mode = Options::PRINT_LED_HELP; break; case OPTION_DEVICE_BY_ID: - { - unsigned int tmp_product_id; - unsigned int tmp_vendor_id; - if (sscanf(opt.argument.c_str(), "%x:%x", &tmp_vendor_id, &tmp_product_id) == 2) { - opts.vendor_id = tmp_vendor_id; - opts.product_id = tmp_product_id; + unsigned int tmp_product_id; + unsigned int tmp_vendor_id; + if (sscanf(opt.argument.c_str(), "%x:%x", &tmp_vendor_id, &tmp_product_id) == 2) + { + opts.vendor_id = tmp_vendor_id; + opts.product_id = tmp_product_id; + } + else + { + RAISE_EXCEPTION(opt.option << " expected an argument in form PRODUCT:VENDOR (i.e. 046d:c626)"); + } + break; } - else - { - RAISE_EXCEPTION(opt.option << " expected an argument in form PRODUCT:VENDOR (i.e. 046d:c626)"); - } - break; - } case OPTION_DEVICE_BY_PATH: - if (sscanf(opt.argument.c_str(), "%3s:%3s", opts.busid, opts.devid) != 2) - { - RAISE_EXCEPTION(opt.option << " expected an argument in form BUS:DEV (i.e. 006:003)"); + { + char busid[4] = { '\0' }; + char devid[4] = { '\0' }; + + if (sscanf(opt.argument.c_str(), "%3s:%3s", busid, devid) != 2) + { + RAISE_EXCEPTION(opt.option << " expected an argument in form BUS:DEV (i.e. 006:003)"); + } + else + { + opts.busid = busid; + opts.devid = devid; + } } break; case OPTION_LIST_SUPPORTED_DEVICES: - opts.mode = RUN_LIST_SUPPORTED_DEVICES; + opts.mode = Options::RUN_LIST_SUPPORTED_DEVICES; break; case OPTION_LIST_SUPPORTED_DEVICES_XPAD: - opts.mode = RUN_LIST_SUPPORTED_DEVICES_XPAD; + opts.mode = Options::RUN_LIST_SUPPORTED_DEVICES_XPAD; break; case OPTION_LIST_CONTROLLER: - opts.mode = RUN_LIST_CONTROLLER; + opts.mode = Options::RUN_LIST_CONTROLLER; break; case OPTION_HELP_DEVICES: - opts.mode = PRINT_HELP_DEVICES; + opts.mode = Options::PRINT_HELP_DEVICES; break; case ArgParser::REST_ARG: @@ -598,13 +578,13 @@ CommandLineOptions::parse_args(int argc, char** argv) } void -CommandLineOptions::print_help() const +CommandLineParser::print_help() const { argp.print_help(std::cout); } void -CommandLineOptions::print_led_help() const +CommandLineParser::print_led_help() const { std::cout << "Possible values for '--led VALUE' are:\n\n" @@ -628,7 +608,7 @@ CommandLineOptions::print_led_help() const } void -CommandLineOptions::print_version() const +CommandLineParser::print_version() const { std::cout << "xboxdrv " PACKAGE_VERSION " - http://pingus.seul.org/~grumbel/xboxdrv/\n" @@ -638,4 +618,55 @@ CommandLineOptions::print_version() const << "This is free software, and you are welcome to redistribute it under certain conditions; see the file COPYING for details.\n"; } +void +CommandLineParser::create_ini_schema() +{ + // INISchema ini; + + // ini.section("general") + // ("verbose", &verbose) + // ("silent", &silent) + // ("quiet", &quiet) + // ("rumble", &rumble) + // ("led", &led) + // ("rumble_l", &rumble_l) + // ("rumble_r", &rumble_r) + // ("rumble_gain", &rumble_gain) + // ("controller-id", &controller_id) + // ("wireless-id", &wireless_id) + // ("instant-exit", &instant_exit) + // ("no-uinput", &no_uinput) + // ("detach-kernel-driver", &detach_kernel_driver); + + // char busid[4]; + // char devid[4]; + // int deadzone; + // int deadzone_trigger; + + // int vendor_id; + // int product_id; + + // bool square_axis; + // bool four_way_restrictor; + // int dpad_rotation; + // std::string evdev_device; + + // uInputCfg uinput_config; + //ini.section("ui-buttonmap", ui_buttonmap_cb); + //ini.section("ui-axismap", ui_buttonmap_cb); + + // std::vector<ButtonMapping> button_map; + //ini.section("buttonmap", buttonmap_cb); + + // std::vector<AxisMapping> axis_map; + //ini.section("axismap", axismap_cb); + + // std::vector<AutoFireMapping> autofire_map; + // std::vector<RelativeAxisMapping> relative_axis_map; + // std::vector<CalibrationMapping> calibration_map; + // std::vector<AxisSensitivityMapping> axis_sensitivity_map; + // std::map<int, XboxAxis> evdev_absmap; + // std::map<int, XboxButton> evdev_keymap; +} + /* EOF */ diff --git a/src/command_line_options.hpp b/src/command_line_options.hpp index b64a81a..945ab32 100644 --- a/src/command_line_options.hpp +++ b/src/command_line_options.hpp @@ -29,70 +29,23 @@ class Xboxdrv; -class CommandLineOptions +class CommandLineParser { public: - enum { RUN_DEFAULT, - RUN_DAEMON, - RUN_LIST_CONTROLLER, - RUN_LIST_SUPPORTED_DEVICES, - RUN_LIST_SUPPORTED_DEVICES_XPAD, - PRINT_VERSION, - PRINT_HELP, - PRINT_HELP_DEVICES, - PRINT_LED_HELP - } mode; - - bool verbose; - bool silent; - bool quiet; - bool rumble; - int led; - int rumble_l; - int rumble_r; - int rumble_gain; - int controller_id; - int wireless_id; - bool instant_exit; - bool no_uinput; - bool detach_kernel_driver; - - GamepadType gamepad_type; - - char busid[4]; - char devid[4]; - - int vendor_id; - int product_id; - - uInputCfg uinput_config; - int deadzone; - int deadzone_trigger; - std::vector<ButtonMapping> button_map; - std::vector<AxisMapping> axis_map; - std::vector<AutoFireMapping> autofire_map; - std::vector<RelativeAxisMapping> relative_axis_map; - std::vector<CalibrationMapping> calibration_map; - std::vector<AxisSensitivityMapping> axis_sensitivity_map; - bool square_axis; - bool four_way_restrictor; - int dpad_rotation; - std::string evdev_device; - std::map<int, XboxAxis> evdev_absmap; - std::map<int, XboxButton> evdev_keymap; - ArgParser argp; public: - CommandLineOptions(); - void parse_args(int argc, char** argv); + CommandLineParser(); + + void parse_args(int argc, char** argv, Options* options); void print_help() const; void print_led_help() const; void print_version() const; + void create_ini_schema(); }; -extern CommandLineOptions* command_line_options; +extern Options* g_options; #endif diff --git a/src/force_feedback_handler.cpp b/src/force_feedback_handler.cpp index 4024654..78b651f 100644 --- a/src/force_feedback_handler.cpp +++ b/src/force_feedback_handler.cpp @@ -19,7 +19,7 @@ #include <stdlib.h> #include <iostream> #include <assert.h> -#include "command_line_options.hpp" +#include "options.hpp" #include "force_feedback_handler.hpp" std::ostream& operator<<(std::ostream& out, const struct ff_envelope& envelope) @@ -294,7 +294,7 @@ ForceFeedbackHandler::get_max_effects() void ForceFeedbackHandler::upload(const struct ff_effect& effect) { - if (command_line_options->verbose) + if (g_options->verbose) std::cout << "FF_UPLOAD(" << "effect_id:" << effect.id << ", effect_type:" << effect.type @@ -325,7 +325,7 @@ ForceFeedbackHandler::upload(const struct ff_effect& effect) void ForceFeedbackHandler::erase(int id) { - if (command_line_options->verbose) + if (g_options->verbose) std::cout << "FF_ERASE(effect_id:" << id << ")" << std::endl; std::map<int, ForceFeedbackEffect>::iterator i = effects.find(id); @@ -338,7 +338,7 @@ ForceFeedbackHandler::erase(int id) void ForceFeedbackHandler::play(int id) { - if (command_line_options->verbose) + if (g_options->verbose) std::cout << "FFPlay(effect_id:" << id << ")" << std::endl; std::map<int, ForceFeedbackEffect>::iterator i = effects.find(id); @@ -351,7 +351,7 @@ ForceFeedbackHandler::play(int id) void ForceFeedbackHandler::stop(int id) { - if (command_line_options->verbose) + if (g_options->verbose) std::cout << "FFStop(effect_id:" << id << ")" << std::endl; std::map<int, ForceFeedbackEffect>::iterator i = effects.find(id); diff --git a/src/ini_builder.hpp b/src/ini_builder.hpp new file mode 100644 index 0000000..48e8407 --- /dev/null +++ b/src/ini_builder.hpp @@ -0,0 +1,32 @@ +/* +** 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_INI_BUILDER_HPP +#define HEADER_XBOXDRV_INI_BUILDER_HPP + +class INIBuilder +{ +public: + virtual ~INIBuilder() {} + virtual void send_section(const std::string& section) =0; + virtual void send_pair(const std::string& name, const std::string& value) =0; +}; + +#endif + +/* EOF */ diff --git a/src/ini_parser.cpp b/src/ini_parser.cpp new file mode 100644 index 0000000..bcf0a2e --- /dev/null +++ b/src/ini_parser.cpp @@ -0,0 +1,268 @@ +/* +** 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 "ini_parser.hpp" + +#include <stdlib.h> +#include <iostream> +#include <ctype.h> +#include <stdexcept> + +#include "ini_builder.hpp" + +INIParser::INIParser(std::istream& in, INIBuilder& builder, const std::string& context) : + m_in(in), + m_builder(builder), + m_context(context), + m_line(1), + m_column(0), + m_current_char(-1) +{} + +void +INIParser::run() +{ + // read the first char + next(); + + while(peek() != -1) + { + if (accept('[')) + { + m_builder.send_section(get_section()); + expect(']'); + whitespace(); + if (accept('#')) + eat_rest_of_line(); + newline(); + } + else if (accept(' ') || accept('\t') || accept('\n')) + { + // eat whitespace + } + else if (accept('#')) + { + eat_rest_of_line(); + newline(); + } + else // assume name=value pair + { + std::string n; + std::string v; + + n = get_ident(); + whitespace(); + expect('='); + whitespace(); + if (accept('#')) + { // "foobar = # comment here, value empty" + eat_rest_of_line(); + newline(); + } + else + { + if (accept('"')) + { + v = get_string(); + expect('"'); + } + else + { + v = get_value(); + } + + whitespace(); + if (accept('#')) + eat_rest_of_line(); + newline(); + } + m_builder.send_pair(n, v); + } + } +} + +void +INIParser::error(const std::string& message) +{ + std::ostringstream str; + str << m_context << ":" << m_line << ":" << m_column << ": error: " << message; + throw std::runtime_error(str.str()); +} + +int +INIParser::peek() +{ + return m_current_char; +} + +void +INIParser::next() +{ + if (m_in.eof()) + { + error("unexpected end of file"); + } + else + { + m_current_char = m_in.get(); + if (m_current_char == '\n') + { + m_line += 1; + m_column = 0; + } + } +} + +bool +INIParser::accept(char c) +{ + if (peek() != c) + { + return false; + } + else + { + next(); + return true; + } +} + +void +INIParser::expect(char c) +{ + if (peek() != c) + { + std::ostringstream str; + str << "expected '" << c << "', got "; + if (peek() == -1) + str << "EOF"; + else + str << "'" << static_cast<char>(peek()) << "'"; + error(str.str()); + } + else + { + next(); + } +} + +std::string +INIParser::get_value() +{ + std::ostringstream str; + while(peek() != ' ' && peek() != '\t' && peek() != '\n') + { + str << (char)peek(); + next(); + } + return str.str(); +} + +std::string +INIParser::get_ident() +{ + std::ostringstream str; + while(peek() != '=' && peek() != ' ' && peek() != '\t') + { + str << (char)peek(); + next(); + } + return str.str(); +} + +std::string +INIParser::get_string() +{ + std::ostringstream str; + while(peek() != '"') + { + if (peek() == '\\') + { + next(); + switch(peek()) + { + case '\\': str << '\\'; break; + case '0': str << '\0'; break; + case 'a': str << '\a'; break; + case 'b': str << '\b'; break; + case 't': str << '\t'; break; + case 'r': str << '\r'; break; + case 'n': str << '\n'; break; + default: str << '\\' << (char)peek(); break; + } + } + else + { + str << (char)peek(); + } + next(); + } + return str.str(); +} + +void +INIParser::newline() +{ + if (peek() != '\n') + { + error("expected newline"); + } + else + { + next(); + } +} + +void +INIParser::eat_rest_of_line() +{ + while(peek() != '\n') + { + next(); + } +} + +std::string +INIParser::get_section() +{ + std::ostringstream str; + while(peek() != ']') + { + str << (char)peek(); + next(); + } + return str.str(); +} + + +void +INIParser::whitespace() +{ + while(peek() == ' ' || peek() == '\t') + { + next(); + } +} + +int +INIParser::getchar() +{ + return m_in.get(); +} + +/* EOF */ diff --git a/src/ini_parser.hpp b/src/ini_parser.hpp new file mode 100644 index 0000000..d58b7c5 --- /dev/null +++ b/src/ini_parser.hpp @@ -0,0 +1,65 @@ +/* +** 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_INI_PARSER_HPP +#define HEADER_XBOXDRV_INI_PARSER_HPP + +#include <map> +#include <string> +#include <sstream> + +class INIBuilder; + +class INIParser +{ +private: + std::istream& m_in; + INIBuilder& m_builder; + std::string m_context; + int m_line; + int m_column; + int m_current_char; + +public: + INIParser(std::istream& in, INIBuilder& builder, const std::string& context); + + void run(); + +private: + void error(const std::string& message); + int peek(); + void next(); + bool accept(char c); + void expect(char c); + std::string get_string(); + std::string get_value(); + std::string get_ident(); + void newline(); + void eat_rest_of_line(); + std::string get_section(); + void whitespace(); + int getchar(); + +private: + INIParser(const INIParser&); + INIParser& operator=(const INIParser&); +}; + +#endif + +/* EOF */ diff --git a/src/ini_schema.cpp b/src/ini_schema.cpp new file mode 100644 index 0000000..95325fe --- /dev/null +++ b/src/ini_schema.cpp @@ -0,0 +1,208 @@ +/* +** 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 "ini_schema.hpp" + +class INIPairSchema +{ +public: + virtual ~INIPairSchema() {} +}; + +class INIPairSchemaBool : public INIPairSchema +{ +private: + bool* m_data; + +public: + INIPairSchemaBool(bool* data) : m_data(data) {} + void call(const std::string& value) + { + if (value == "yes" || value == "true" || value == "1") + { + *m_data = true; + } + else if (value == "no" || value == "false" || value == "0") + { + *m_data = false; + } + else + { + throw std::runtime_error("unable to convert '" + value + "' to bool"); + } + } +}; + +class INIPairSchemaInt : public INIPairSchema +{ +private: + int* m_data; + +public: + INIPairSchemaInt(int* data) : m_data(data) {} + void call(const std::string& value) + { + *m_data = atoi(value.c_str()); + } +}; + +class INIPairSchemaFloat : public INIPairSchema +{ +private: + float* m_data; + +public: + INIPairSchemaFloat(float* data) : m_data(data) {} + void call(const std::string& value) + { + *m_data = atoi(value.c_str()); + } +}; + +class INIPairSchemaString : public INIPairSchema +{ +private: + std::string* m_data; + +public: + INIPairSchemaString(std::string* data) : m_data(data) {} + void call(const std::string& value) + { + *m_data = value; + } +}; + +class INIPairSchemaCallback : public INIPairSchema +{ +private: + boost::function<void (const std::string&)> m_callback; + +public: + INIPairSchemaCallback(boost::function<void (const std::string&)> callback) : m_callback(callback) {} + void call(const std::string& value) + { + if (m_callback) + m_callback(value); + } +}; + +INISchemaSection::INISchemaSection() +{ +} + +INISchemaSection::~INISchemaSection() +{ + for(Schema::iterator i = m_schema.begin(); i != m_schema.end(); ++i) + { + delete i->second; + } +} + +INISchemaSection& +INISchemaSection::add(const std::string& name, INIPairSchema* schema) +{ + Schema::iterator i = m_schema.find(name); + + if (i != m_schema.end()) + { + delete i->second; + } + + m_schema.insert(std::pair<std::string, INIPairSchema*>(name, schema)); + + return *this; +} + +INISchemaSection& +INISchemaSection::operator()(const std::string& name, bool* value) +{ + add(name, new INIPairSchemaBool(value)); + return *this; +} + +INISchemaSection& +INISchemaSection::operator()(const std::string& name, int* value) +{ + add(name, new INIPairSchemaInt(value)); + return *this; +} + +INISchemaSection& +INISchemaSection::operator()(const std::string& name, float* value) +{ + add(name, new INIPairSchemaFloat(value)); + return *this; +} + +INISchemaSection& +INISchemaSection::operator()(const std::string& name, std::string* value) +{ + add(name, new INIPairSchemaString(value)); + return *this; +} + +INISchemaSection& +INISchemaSection::operator()(const std::string& name, boost::function<void (const std::string&)> callback) +{ + add(name, new INIPairSchemaCallback(callback)); + return *this; +} + +INISchema::INISchema() : + m_sections() +{ +} + +INISchema::~INISchema() +{ + for(Sections::iterator i = m_sections.begin(); i != m_sections.end(); ++i) + { + delete i->second; + } +} + +INISchemaSection& +INISchema::section(const std::string& name, + boost::function<void (const std::string&, const std::string&)> callback) +{ + Sections::iterator i = m_sections.find(name); + if (i != m_sections.end()) + { + delete i->second; + } + + INISchemaSection* section = new INISchemaSection(); + m_sections.insert(std::pair<std::string, INISchemaSection*>(name, section)); + return *section; +} + +INISchemaSection* +INISchema::get_section(const std::string& name) +{ + Sections::iterator i = m_sections.find(name); + if (i != m_sections.end()) + { + return i->second; + } + else + { + return 0; + } +} + +/* EOF */ diff --git a/src/ini_schema.hpp b/src/ini_schema.hpp new file mode 100644 index 0000000..3ebe8e9 --- /dev/null +++ b/src/ini_schema.hpp @@ -0,0 +1,75 @@ +/* +** 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_INI_SCHEMA_HPP +#define HEADER_XBOXDRV_INI_SCHEMA_HPP + +#include <map> +#include <string> +#include <boost/function.hpp> + +class INIPairSchema; + +class INISchemaSection +{ +private: + typedef std::map<std::string, INIPairSchema*> Schema; + Schema m_schema; + +public: + INISchemaSection(); + ~INISchemaSection(); + + INISchemaSection& operator()(const std::string& name, bool* value); + INISchemaSection& operator()(const std::string& name, int* value); + INISchemaSection& operator()(const std::string& name, float* value); + INISchemaSection& operator()(const std::string& name, std::string* value); + INISchemaSection& operator()(const std::string& name, boost::function<void (const std::string&)> callback); + +private: + INISchemaSection& add(const std::string& name, INIPairSchema* schema); + +private: + INISchemaSection(const INISchemaSection&); + INISchemaSection& operator=(const INISchemaSection&); +}; + +class INISchema +{ +private: + typedef std::map<std::string, INISchemaSection*> Sections; + Sections m_sections; + +public: + INISchema(); + ~INISchema(); + + INISchemaSection& section(const std::string& name, + boost::function<void (const std::string&, const std::string&)> callback + = boost::function<void (const std::string&, const std::string&)>()); + + INISchemaSection* get_section(const std::string& name); + +private: + INISchema(const INISchema&); + INISchema& operator=(const INISchema&); +}; + +#endif + +/* EOF */ diff --git a/src/modifier.cpp b/src/modifier.cpp index e6b8e47..013235c 100644 --- a/src/modifier.cpp +++ b/src/modifier.cpp @@ -22,7 +22,7 @@ #include <stdexcept> #include <math.h> -#include "command_line_options.hpp" +#include "options.hpp" #include "helper.hpp" #include "modifier.hpp" @@ -310,7 +310,7 @@ void apply_square_axis(XboxGenericMsg& msg) } } -void apply_deadzone(XboxGenericMsg& msg, const CommandLineOptions& opts) +void apply_deadzone(XboxGenericMsg& msg, const Options& opts) { switch (msg.type) { @@ -350,7 +350,7 @@ void apply_deadzone(XboxGenericMsg& msg, const CommandLineOptions& opts) } } -void apply_axis_sensitivity(XboxGenericMsg& msg, const CommandLineOptions& opts) +void apply_axis_sensitivity(XboxGenericMsg& msg, const Options& opts) { for(std::vector<AxisSensitivityMapping>::const_iterator i = opts.axis_sensitivity_map.begin(); i != opts.axis_sensitivity_map.end(); ++i) @@ -371,7 +371,7 @@ void apply_axis_sensitivity(XboxGenericMsg& msg, const CommandLineOptions& opts) } } -void apply_four_way_restrictor(XboxGenericMsg& msg, const CommandLineOptions& opts) +void apply_four_way_restrictor(XboxGenericMsg& msg, const Options& opts) { // left Stick if (abs(get_axis(msg, XBOX_AXIS_X1)) > abs(get_axis(msg, XBOX_AXIS_Y1))) @@ -402,7 +402,7 @@ void apply_four_way_restrictor(XboxGenericMsg& msg, const CommandLineOptions& op } } -void apply_dpad_rotator(XboxGenericMsg& msg, const CommandLineOptions& opts) +void apply_dpad_rotator(XboxGenericMsg& msg, const Options& opts) { int up = get_button(msg, XBOX_DPAD_UP); int down = get_button(msg, XBOX_DPAD_DOWN); diff --git a/src/modifier.hpp b/src/modifier.hpp index b22ea8f..282185e 100644 --- a/src/modifier.hpp +++ b/src/modifier.hpp @@ -24,7 +24,7 @@ #include <vector> #include "xboxmsg.hpp" -class CommandLineOptions; +class Options; struct ButtonMapping { static ButtonMapping from_string(const std::string& str); @@ -161,11 +161,11 @@ public: void apply_button_map(XboxGenericMsg& msg, const std::vector<ButtonMapping>& lst); void apply_axis_map(XboxGenericMsg& msg, const std::vector<AxisMapping>& lst); void apply_calibration_map(XboxGenericMsg& msg, const std::vector<CalibrationMapping>& lst); -void apply_deadzone(XboxGenericMsg& msg, const CommandLineOptions& opts); +void apply_deadzone(XboxGenericMsg& msg, const Options& opts); void apply_square_axis(XboxGenericMsg& msg); -void apply_axis_sensitivity(XboxGenericMsg& msg, const CommandLineOptions& opts); -void apply_four_way_restrictor(XboxGenericMsg& msg, const CommandLineOptions& opts); -void apply_dpad_rotator(XboxGenericMsg& msg, const CommandLineOptions& opts); +void apply_axis_sensitivity(XboxGenericMsg& msg, const Options& opts); +void apply_four_way_restrictor(XboxGenericMsg& msg, const Options& opts); +void apply_dpad_rotator(XboxGenericMsg& msg, const Options& opts); #endif diff --git a/src/options.cpp b/src/options.cpp new file mode 100644 index 0000000..72895ee --- /dev/null +++ b/src/options.cpp @@ -0,0 +1,57 @@ +/* +** 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 "options.hpp" + +Options* g_options; + +Options::Options() : + mode(RUN_DEFAULT), + verbose(false), + silent (false), + quiet (false), + rumble (false), + led (-1), + rumble_l(-1), + rumble_r(-1), + rumble_gain(255), + controller_id(0), + wireless_id(0), + instant_exit(false), + no_uinput(false), + detach_kernel_driver(), + gamepad_type(GAMEPAD_UNKNOWN), + vendor_id(-1), + product_id(-1), + uinput_config(), + deadzone(0), + deadzone_trigger(0), + button_map(), + axis_map(), + autofire_map(), + relative_axis_map(), + calibration_map(), + axis_sensitivity_map(), + square_axis(false), + four_way_restrictor(false), + dpad_rotation(0), + evdev_device() +{ +} + +/* EOF */ diff --git a/src/options.hpp b/src/options.hpp new file mode 100644 index 0000000..53847d1 --- /dev/null +++ b/src/options.hpp @@ -0,0 +1,89 @@ +/* +** 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_OPTIONS_HPP +#define HEADER_XBOXDRV_OPTIONS_HPP + +#include <string> +#include <map> +#include <vector> + +#include "xpad_device.hpp" +#include "uinput_cfg.hpp" +#include "modifier.hpp" + +class Options +{ +public: + enum { RUN_DEFAULT, + RUN_DAEMON, + RUN_LIST_CONTROLLER, + RUN_LIST_SUPPORTED_DEVICES, + RUN_LIST_SUPPORTED_DEVICES_XPAD, + PRINT_VERSION, + PRINT_HELP, + PRINT_HELP_DEVICES, + PRINT_LED_HELP + } mode; + + bool verbose; + bool silent; + bool quiet; + bool rumble; + int led; + int rumble_l; + int rumble_r; + int rumble_gain; + int controller_id; + int wireless_id; + bool instant_exit; + bool no_uinput; + bool detach_kernel_driver; + + GamepadType gamepad_type; + + std::string busid; + std::string devid; + + int vendor_id; + int product_id; + + uInputCfg uinput_config; + int deadzone; + int deadzone_trigger; + std::vector<ButtonMapping> button_map; + std::vector<AxisMapping> axis_map; + std::vector<AutoFireMapping> autofire_map; + std::vector<RelativeAxisMapping> relative_axis_map; + std::vector<CalibrationMapping> calibration_map; + std::vector<AxisSensitivityMapping> axis_sensitivity_map; + bool square_axis; + bool four_way_restrictor; + int dpad_rotation; + std::string evdev_device; + std::map<int, XboxAxis> evdev_absmap; + std::map<int, XboxButton> evdev_keymap; + + Options(); +}; + +extern Options* g_options; + +#endif + +/* EOF */ diff --git a/src/xbox360_controller.cpp b/src/xbox360_controller.cpp index 1aef03c..f9d8a13 100644 --- a/src/xbox360_controller.cpp +++ b/src/xbox360_controller.cpp @@ -24,7 +24,7 @@ #include <iostream> #include <boost/format.hpp> -#include "command_line_options.hpp" +#include "options.hpp" #include "helper.hpp" #include "usb_helper.hpp" #include "usb_read_thread.hpp" @@ -228,7 +228,7 @@ Xbox360Controller::read(XboxGenericMsg& msg, bool verbose, int timeout) } else if (ret == 3 && data[0] == 0x08 && data[1] == 0x03) { - if (!command_line_options->quiet) + if (!g_options->quiet) { if (data[2] == 0x00) std::cout << "Headset: none"; diff --git a/src/xboxdrv.cpp b/src/xboxdrv.cpp index 8a729f4..c29bee6 100644 --- a/src/xboxdrv.cpp +++ b/src/xboxdrv.cpp @@ -44,6 +44,7 @@ #include "helper.hpp" #include "evdev_helper.hpp" #include "command_line_options.hpp" +#include "options.hpp" #include "xbox_generic_controller.hpp" #include "xboxdrv.hpp" @@ -56,13 +57,13 @@ void on_sigint(int) { if (global_exit_xboxdrv) { - if (!command_line_options->quiet) + if (!g_options->quiet) std::cout << "Ctrl-c pressed twice, exiting hard" << std::endl; exit(EXIT_SUCCESS); } else { - if (!command_line_options->quiet) + if (!g_options->quiet) std::cout << "Shutdown initiated, press Ctrl-c again if nothing is happening" << std::endl; global_exit_xboxdrv = true; @@ -73,7 +74,7 @@ void on_sigint(int) void on_sigterm(int) { - if (!command_line_options->quiet) + if (!g_options->quiet) std::cout << "Shutdown initiated by SIGTERM" << std::endl; if (global_controller) @@ -149,17 +150,17 @@ Xboxdrv::run_list_controller() } bool -Xboxdrv::find_controller_by_path(const char* busid, const char* devid,struct usb_device** xbox_device) const +Xboxdrv::find_controller_by_path(const std::string& busid, const std::string& devid,struct usb_device** xbox_device) const { struct usb_bus* busses = usb_get_busses(); for (struct usb_bus* bus = busses; bus; bus = bus->next) { - if (strcmp(bus->dirname, busid) == 0) + if (bus->dirname == busid) { for (struct usb_device* dev = bus->devices; dev; dev = dev->next) { - if (strcmp(dev->filename, devid) == 0) + if (dev->filename == devid) { *xbox_device = dev; return true; @@ -272,7 +273,7 @@ Xboxdrv::find_xbox360_controller(int id, struct usb_device** xbox_device, XPadDe } void -Xboxdrv::apply_modifier(XboxGenericMsg& msg, int msec_delta, const CommandLineOptions& opts) const +Xboxdrv::apply_modifier(XboxGenericMsg& msg, int msec_delta, const Options& opts) const { apply_calibration_map(msg, opts.calibration_map); @@ -293,7 +294,7 @@ Xboxdrv::apply_modifier(XboxGenericMsg& msg, int msec_delta, const CommandLineOp } void -Xboxdrv::controller_loop(GamepadType type, uInput* uinput, XboxGenericController* controller, const CommandLineOptions& opts) +Xboxdrv::controller_loop(GamepadType type, uInput* uinput, XboxGenericController* controller, const Options& opts) { int timeout = 0; // 0 == no timeout XboxGenericMsg oldmsg; // last data send to uinput @@ -392,7 +393,7 @@ Xboxdrv::controller_loop(GamepadType type, uInput* uinput, XboxGenericController void Xboxdrv::find_controller(struct usb_device*& dev, XPadDevice& dev_type, - const CommandLineOptions& opts) const + const Options& opts) const { if (opts.busid[0] != '\0' && opts.devid[0] != '\0') { @@ -453,11 +454,16 @@ Xboxdrv::find_controller(struct usb_device*& dev, } void -Xboxdrv::run_main(const CommandLineOptions& opts) +Xboxdrv::run_main(const Options& opts) { if (!opts.quiet) { - opts.print_version(); + std::cout + << "xboxdrv " PACKAGE_VERSION " - http://pingus.seul.org/~grumbel/xboxdrv/\n" + << "Copyright © 2008-2010 Ingo Ruhnke <grumbel@gmx.de>\n" + << "Licensed under GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n" + << "This program comes with ABSOLUTELY NO WARRANTY.\n" + << "This is free software, and you are welcome to redistribute it under certain conditions; see the file COPYING for details.\n"; std::cout << std::endl; } @@ -601,7 +607,7 @@ Xboxdrv::run_main(const CommandLineOptions& opts) void Xboxdrv::print_info(struct usb_device* dev, const XPadDevice& dev_type, - const CommandLineOptions& opts) const + const Options& opts) const { std::cout << "USB Device: " << dev->bus->dirname << ":" << dev->filename << std::endl; std::cout << "Controller: " << boost::format("\"%s\" (idVendor: 0x%04x, idProduct: 0x%04x)") @@ -748,7 +754,7 @@ Xboxdrv::run_help_devices() } void -Xboxdrv::run_daemon(const CommandLineOptions& opts) +Xboxdrv::run_daemon(const Options& opts) { pid_t pid = fork(); @@ -773,45 +779,47 @@ Xboxdrv::main(int argc, char** argv) signal(SIGINT, on_sigint); signal(SIGTERM, on_sigterm); - CommandLineOptions opts; - opts.parse_args(argc, argv); - command_line_options = &opts; + Options opts; + g_options = &opts; + + CommandLineParser cmd_parser; + cmd_parser.parse_args(argc, argv, &opts); switch(opts.mode) { - case CommandLineOptions::PRINT_HELP_DEVICES: + case Options::PRINT_HELP_DEVICES: run_help_devices(); break; - case CommandLineOptions::RUN_LIST_SUPPORTED_DEVICES: + case Options::RUN_LIST_SUPPORTED_DEVICES: run_list_supported_devices(); break; - case CommandLineOptions::RUN_LIST_SUPPORTED_DEVICES_XPAD: + case Options::RUN_LIST_SUPPORTED_DEVICES_XPAD: run_list_supported_devices_xpad(); break; - case CommandLineOptions::PRINT_VERSION: - opts.print_version(); + case Options::PRINT_VERSION: + cmd_parser.print_version(); break; - case CommandLineOptions::PRINT_HELP: - opts.print_help(); + case Options::PRINT_HELP: + cmd_parser.print_help(); break; - case CommandLineOptions::PRINT_LED_HELP: - opts.print_led_help(); + case Options::PRINT_LED_HELP: + cmd_parser.print_led_help(); break; - case CommandLineOptions::RUN_DEFAULT: + case Options::RUN_DEFAULT: run_main(opts); break; - case CommandLineOptions::RUN_DAEMON: + case Options::RUN_DAEMON: run_daemon(opts); break; - case CommandLineOptions::RUN_LIST_CONTROLLER: + case Options::RUN_LIST_CONTROLLER: run_list_controller(); break; } diff --git a/src/xboxdrv.hpp b/src/xboxdrv.hpp index 1376700..1e9dbb4 100644 --- a/src/xboxdrv.hpp +++ b/src/xboxdrv.hpp @@ -22,15 +22,16 @@ #include "xboxmsg.hpp" struct XPadDevice; -class CommandLineOptions; +class Options; +class Options; class uInput; class XboxGenericController; class Xboxdrv { private: - void run_main(const CommandLineOptions& opts); - void run_daemon(const CommandLineOptions& opts); + void run_main(const Options& opts); + void run_daemon(const Options& opts); void run_list_supported_devices(); void run_list_supported_devices_xpad(); void run_help_devices(); @@ -38,16 +39,16 @@ private: void print_info(struct usb_device* dev, const XPadDevice& dev_type, - const CommandLineOptions& opts) const; + const Options& opts) const; void controller_loop(GamepadType type, uInput* uinput, XboxGenericController* controller, - const CommandLineOptions& opts); - void apply_modifier(XboxGenericMsg& msg, int msec_delta, const CommandLineOptions& opts) const; + const Options& opts); + void apply_modifier(XboxGenericMsg& msg, int msec_delta, const Options& opts) const; - bool find_controller_by_path(const char* busid, const char* devid,struct usb_device** xbox_device) const; + bool find_controller_by_path(const std::string& busid, const std::string& devid,struct usb_device** xbox_device) const; void find_controller(struct usb_device*& dev, XPadDevice& dev_type, - const CommandLineOptions& opts) const; + const Options& opts) const; int find_jsdev_number() const; int find_evdev_number() const; bool find_controller_by_id(int id, int vendor_id, int product_id, struct usb_device** xbox_device) const; diff --git a/src/xboxmsg.cpp b/src/xboxmsg.cpp index 02bc76b..d4840d8 100644 --- a/src/xboxmsg.cpp +++ b/src/xboxmsg.cpp @@ -22,7 +22,7 @@ #include <algorithm> #include "helper.hpp" -#include "command_line_options.hpp" +#include "options.hpp" #include "xboxmsg.hpp" std::string gamepadtype_to_string(const GamepadType& type) @@ -152,7 +152,7 @@ std::ostream& operator<<(std::ostream& out, const Xbox360GuitarMsg& msg) % int(msg.blue) % int(msg.orange); - if (command_line_options->verbose) + if (g_options->verbose) { out << boost::format("| dummy: %d %d %d %d %02hhx %02hhx %04hx %04hx %02x %02x") % int(msg.thumb_l) @@ -205,7 +205,7 @@ std::ostream& operator<<(std::ostream& out, const Xbox360Msg& msg) out << boost::format(" LT:%3d RT:%3d") % int(msg.lt) % int(msg.rt); - if (command_line_options->verbose) + if (g_options->verbose) out << " Dummy: " << msg.dummy1 << " " << msg.dummy2 << " " << msg.dummy3; return out; @@ -245,7 +245,7 @@ std::ostream& operator<<(std::ostream& out, const XboxMsg& msg) % int(msg.lt) % int(msg.rt); - if (command_line_options->verbose) + if (g_options->verbose) out << " Dummy: " << msg.dummy; return out;