Add fire button and investigate macro repetition

This commit is contained in:
dokutan 2019-12-13 03:02:46 +01:00
parent 7f7c15e00a
commit 792dccfe97
11 changed files with 129 additions and 12 deletions

View file

@ -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

View file

@ -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

View file

@ -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 = {

View file

@ -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};

View file

@ -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];
}

View file

@ -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"

View file

@ -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";
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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 ){