From 792dccfe9707c4ea7f400c286f2a7eeb6ee75337 Mon Sep 17 00:00:00 2001 From: dokutan <54861821+dokutan@users.noreply.github.com> Date: Fri, 13 Dec 2019 03:02:46 +0100 Subject: [PATCH] Add fire button and investigate macro repetition --- README.md | 10 ++++----- example.ini | 6 ++--- include/constructor.cpp | 2 ++ include/data.cpp | 3 +++ include/getters.cpp | 10 +++++++++ include/mouse_m908.h | 9 ++++++-- include/print_help.cpp | 1 + include/setters.cpp | 49 ++++++++++++++++++++++++++++++++++++++++- include/writers.cpp | 21 ++++++++++++++++++ keymap.md | 12 ++++++++++ mouse_m908.cpp | 18 +++++++++++++++ 11 files changed, 129 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9167224..807ed11 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # mouse_m908 Control the Redragon M908 Impact gaming mouse from Linux +## Status +All settings from the official software are implemented, except repeating macros, which seems to be broken in the official software and is therefore currently disabled in this program. +As a result there will be no changes to this program, unless I overlooked some features or find a bug. + ## Installing - Install the dependencies: - libusb @@ -46,7 +50,6 @@ There is space for 15 macros on the mouse, these are shared over all profiles. E 2. Add macro⟨N⟩ to the button mapping configuration to set a button to the ⟨N⟩th macro 3. Apply the configuration: mouse_m908 -c ⟨config.ini⟩ 4. Apply the specific macro: mouse_m908 -m ⟨macrofile⟩ -n ⟨N⟩ - #### Macro file Each line contains an action and a parameter separated by a tab. Supported actions are: - down ⟨key⟩ @@ -58,8 +61,3 @@ example.macro for an example, keymap.md section Keyboard keys/Keys for a list of - mouse_right - mouse_middle -## TODO -~~Button remapping is not (yet) fully supported: macros and keyboard keys aren't implemented.~~ Macros are currently missing some features: -- [x] delay between keys -- [x] mousebuttons -- [ ] repeat diff --git a/example.ini b/example.ini index a6f0433..eded4a5 100644 --- a/example.ini +++ b/example.ini @@ -39,7 +39,7 @@ report_rate=500 button_left=left button_right=right button_middle=middle -button_fire=left +button_fire=fire:mouse_left:5:1 button_dpi_up=dpi+ button_dpi_down=dpi- scroll_up=scroll_up @@ -51,8 +51,8 @@ button_4=dpi-cycle button_5=report_rate+ button_6=report_rate- button_7=profile_switch -button_8=a -button_9=b +button_8=fire:a:5:1 +button_9=a button_10=super_l+shift_l+2 button_11=ctrl_l+a button_12=super_l+3 diff --git a/include/constructor.cpp b/include/constructor.cpp index d414e22..bd690d7 100644 --- a/include/constructor.cpp +++ b/include/constructor.cpp @@ -48,6 +48,7 @@ mouse_m908::mouse_m908(){ _keymap_data[i][j][0] = _data_settings_3[35+(20*i)+j][8]; _keymap_data[i][j][1] = _data_settings_3[35+(20*i)+j][9]; _keymap_data[i][j][2] = _data_settings_3[35+(20*i)+j][10]; + _keymap_data[i][j][3] = _data_settings_3[35+(20*i)+j][11]; } } _report_rates.fill( r_125Hz ); @@ -58,6 +59,7 @@ mouse_m908::mouse_m908(){ i[3] = _data_macros_codes[count][1]; count++; } + _macro_repeat.fill( 0x01 ); //name → keycode _keycodes = { diff --git a/include/data.cpp b/include/data.cpp index 30d11eb..ab49541 100644 --- a/include/data.cpp +++ b/include/data.cpp @@ -236,3 +236,6 @@ uint8_t mouse_m908::_data_macros_codes[15][2] = { {0xd8, 0x0d}, {0xa0, 0x0e}, {0x68, 0x0f} }; + +uint8_t mouse_m908::_data_macros_repeat[16] = + {0x02, 0xf3, 0xa2, 0x00, 0x04, 0x00, 0x00, 0x00, 0x91, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/include/getters.cpp b/include/getters.cpp index 40dd8b2..810051c 100644 --- a/include/getters.cpp +++ b/include/getters.cpp @@ -51,3 +51,13 @@ uint8_t mouse_m908::get_dpi( m908_profile profile, int level ){ mouse_m908::m908_report_rate mouse_m908::get_report_rate( m908_profile profile ){ return _report_rates[profile]; } + +uint8_t mouse_m908::get_macro_repeat( int macro_number ){ + + //check if macro_number is valid + if( macro_number < 1 || macro_number > 15 ){ + return 1; + } + + return _macro_repeat[macro_number]; +} diff --git a/include/mouse_m908.h b/include/mouse_m908.h index 1a18b0c..b8df94c 100644 --- a/include/mouse_m908.h +++ b/include/mouse_m908.h @@ -71,10 +71,11 @@ class mouse_m908{ int set_speed( m908_profile profile, uint8_t speed ); int set_dpi_enable( m908_profile profile, int level, bool enabled ); int set_dpi( m908_profile profile, int level, uint8_t dpi ); - int set_key_mapping( m908_profile profile, int key, std::array<uint8_t, 3> mapping ); + int set_key_mapping( m908_profile profile, int key, std::array<uint8_t, 4> mapping ); int set_key_mapping( m908_profile profile, int key, std::string mapping ); int set_report_rate( m908_profile profile, m908_report_rate report_rate ); int set_macro( int macro_number, std::string file ); + int set_macro_repeat( int macro_number, uint8_t repeat ); //getter functions m908_profile get_profile(); @@ -86,11 +87,13 @@ class mouse_m908{ bool get_dpi_enable( m908_profile profile, int level ); uint8_t get_dpi( m908_profile profile, int level ); m908_report_rate get_report_rate( m908_profile profile ); + uint8_t get_macro_repeat( int macro_number ); //writer functions (apply settings to mouse) int write_profile(); int write_settings(); int write_macro( int macro_number ); + int write_macro_repeat( int macro_number ); //helper functions int open_mouse(); @@ -115,9 +118,10 @@ class mouse_m908{ std::array<uint8_t, 5> _speed_levels; std::array<std::array<bool, 5>, 5> _dpi_enabled; std::array<std::array<uint8_t, 5>, 5> _dpi_levels; - std::array<std::array<std::array<uint8_t, 3>, 20>, 5> _keymap_data; + std::array<std::array<std::array<uint8_t, 4>, 20>, 5> _keymap_data; std::array<m908_report_rate, 5> _report_rates; std::array<std::array<uint8_t, 256>, 15> _macro_data; + std::array<uint8_t, 15> _macro_repeat; //setting min and max values uint8_t _scrollspeed_min, _scrollspeed_max; @@ -140,6 +144,7 @@ class mouse_m908{ static uint8_t _data_macros_2[256]; static uint8_t _data_macros_3[16]; static uint8_t _data_macros_codes[15][2]; + static uint8_t _data_macros_repeat[16]; }; #include "data.cpp" diff --git a/include/print_help.cpp b/include/print_help.cpp index 1114b6a..d85ab87 100644 --- a/include/print_help.cpp +++ b/include/print_help.cpp @@ -26,4 +26,5 @@ void print_help(){ std::cout << "-p --profile\n\tSets currently active profile (1-5).\n"; std::cout << "-m --macro\n\tSelects macro file for sending.\n"; std::cout << "-n --number\n\tSelects macro slot for sending (1-15).\n"; + //std::cout << "-r --repeat\n\tSets number of times the macro will be repeated (1-255).\n"; } diff --git a/include/setters.cpp b/include/setters.cpp index 6ffafe9..f155816 100644 --- a/include/setters.cpp +++ b/include/setters.cpp @@ -89,10 +89,11 @@ int mouse_m908::set_dpi( m908_profile profile, int level, uint8_t dpi ){ return 0; } -int mouse_m908::set_key_mapping( m908_profile profile, int key, std::array<uint8_t, 3> mapping ){ +int mouse_m908::set_key_mapping( m908_profile profile, int key, std::array<uint8_t, 4> mapping ){ _keymap_data[profile][key][0] = mapping[0]; _keymap_data[profile][key][1] = mapping[1]; _keymap_data[profile][key][2] = mapping[2]; + _keymap_data[profile][key][3] = mapping[3]; return 0; } @@ -103,6 +104,40 @@ int mouse_m908::set_key_mapping( m908_profile profile, int key, std::string mapp _keymap_data[profile][key][0] = _keycodes[mapping][0]; _keymap_data[profile][key][1] = _keycodes[mapping][1]; _keymap_data[profile][key][2] = _keycodes[mapping][2]; + _keymap_data[profile][key][3] = 0x00; + } else if( mapping.find("fire") == 0 ){ + // fire button (multiple keypresses) + + std::stringstream mapping_stream(mapping); + std::string value1 = "", value2 = "", value3 = ""; + uint8_t keycode, repeats = 1, delay = 0; + + std::getline( mapping_stream, value1, ':' ); + std::getline( mapping_stream, value1, ':' ); + std::getline( mapping_stream, value2, ':' ); + std::getline( mapping_stream, value3, ':' ); + + if( value1 == "mouse_left" ){ + keycode = 0x81; + } else if( value1 == "mouse_right" ){ + keycode = 0x82; + } else if( value1 == "mouse_middle" ){ + keycode = 0x84; + } else if( _keyboard_key_values.find(value1) != _keyboard_key_values.end() ){ + keycode = _keyboard_key_values[value1]; + } else{ + return 1; + } + + repeats = (uint8_t)stoi(value2); + delay = (uint8_t)stoi(value3); + + // store values + _keymap_data[profile][key][0] = 0x99; + _keymap_data[profile][key][1] = keycode; + _keymap_data[profile][key][2] = repeats; + _keymap_data[profile][key][3] = delay; + } else{ // string is not a key in _keycodes: keyboard key? @@ -123,6 +158,7 @@ int mouse_m908::set_key_mapping( m908_profile profile, int key, std::string mapp _keymap_data[profile][key][0] = first_value; _keymap_data[profile][key][1] = modifier_value; _keymap_data[profile][key][2] = _keyboard_key_values[std::regex_replace( mapping, modifier_regex, "" )]; + _keymap_data[profile][key][3] = 0x00; //std::cout << std::regex_replace( mapping, modifier_regex, "" ) << "\n"; } catch( std::exception& f ){ return 1; @@ -230,3 +266,14 @@ int mouse_m908::set_macro( int macro_number, std::string file ){ return 0; } + +int mouse_m908::set_macro_repeat( int macro_number, uint8_t repeat ){ + + //check if macro_number is valid + if( macro_number < 1 || macro_number > 15 ){ + return 1; + } + + _macro_repeat[macro_number] = repeat; + return 0; +} diff --git a/include/writers.cpp b/include/writers.cpp index c64138b..89d83d6 100644 --- a/include/writers.cpp +++ b/include/writers.cpp @@ -127,6 +127,8 @@ int mouse_m908::write_settings(){ buffer3[35+(20*i)+j][8] = _keymap_data[i][j][0]; buffer3[35+(20*i)+j][9] = _keymap_data[i][j][1]; buffer3[35+(20*i)+j][10] = _keymap_data[i][j][2]; + buffer3[35+(20*i)+j][11] = _keymap_data[i][j][3]; + //std::cout << (int)_keymap_data[i][j][0] << " " << (int)_keymap_data[i][j][1] << " " << (int)_keymap_data[i][j][2] << " " << (int)_keymap_data[i][j][3] << "\n"; } } //usb report rate @@ -204,3 +206,22 @@ int mouse_m908::write_macro( int macro_number ){ return 0; } + +int mouse_m908::write_macro_repeat( int macro_number ){ + + //check if macro_number is valid + if( macro_number < 1 || macro_number > 15 ){ + return 1; + } + + //prepare data + uint8_t buffer[16]; + std::copy(std::begin(_data_macros_repeat), std::end(_data_macros_repeat), std::begin(buffer)); + + buffer[10] = _macro_repeat[macro_number]; + + //send data + libusb_control_transfer( _handle, 0x21, 0x09, 0x0302, 0x0002, buffer, 16, 1000 ); + + return 0; +} diff --git a/keymap.md b/keymap.md index a6bb3eb..1609718 100644 --- a/keymap.md +++ b/keymap.md @@ -1,6 +1,18 @@ # keymap.md This documents all options for button mapping. +## Fire button (simulates multiple nutton presses) +fire:⟨button⟩:⟨repeats⟩:⟨delay⟩ + +⟨button⟩ can be: +- mouse_left +- mouse_right +- mouse_middle +- a keyboard key + +⟨repeats⟩ can be 1-255 +⟨delay⟩ can be 1-255 + ## Mousebuttons and special functions forward backward diff --git a/mouse_m908.cpp b/mouse_m908.cpp index 293d95a..92f354a 100644 --- a/mouse_m908.cpp +++ b/mouse_m908.cpp @@ -41,16 +41,20 @@ int main( int argc, char **argv ){ {"profile", required_argument, 0, 'p'}, {"macro", required_argument, 0, 'm'}, {"number", required_argument, 0, 'n'}, + //{"repeat", required_argument, 0, 'r'}, {0, 0, 0, 0} }; bool flag_config = false, flag_profile = false; bool flag_macro = false, flag_number = false; + //bool flag_repeat; std::string string_config, string_profile; std::string string_macro, string_number; + //std::string string_repeat; //parse command line options int c, option_index = 0; + //while( (c = getopt_long( argc, argv, "hc:p:m:n:r:", while( (c = getopt_long( argc, argv, "hc:p:m:n:", long_options, &option_index ) ) != -1 ){ @@ -75,6 +79,10 @@ int main( int argc, char **argv ){ flag_number = true; string_number = optarg; break; + //case 'r': + // flag_repeat = true; + // string_repeat = optarg; + // break; case '?': break; default: @@ -438,6 +446,16 @@ int main( int argc, char **argv ){ m.write_macro(number); + /*if( flag_repeat ){ + int repeat = (int)stoi(string_repeat); + r = m.set_macro_repeat( number, repeat ); + if( r != 0 ){ + std::cout << "Invalid repeats\n"; + return 1; + } + m.write_macro_repeat( number ); + }*/ + m.close_mouse(); } else if( flag_macro || flag_number ){