Add support for macros

This commit is contained in:
dokutan 2019-12-08 01:52:41 +01:00
parent ca95cdf881
commit 6dd9083806
11 changed files with 238 additions and 4 deletions

View file

@ -20,7 +20,7 @@ sudo make uninstall
``
## Usage
The settings are stored in a file and applied all at once. See example.ini and keymap.md
The settings are stored in a file and applied all at once (except macros, see below). See example.ini and keymap.md
- Apply the example configuration:
``
@ -34,6 +34,26 @@ mouse_m908 -p 3
``
mouse_m908 -h
``
- Send macro example.macro to slot 1:
``
mouse_m908 -m example.macro -n 1
``
### Macros
There is space for 15 macros on the mouse, these are shared over all profiles. Each macro can hold up to 34 actions. To set a macro to a specific button:
1. Create a file containing the macro actions
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⟩
- up ⟨key⟩
example.macro for an example, keymap.md section Keyboard keys/Keys for a list of recognized Keys.
## TODO
Button remapping is not (yet) fully supported: macros ~~and keyboard keys~~ aren't implemented.
~~Button remapping is not (yet) fully supported: macros and keyboard keys aren't implemented.~~ Macros are currently missing some features:
- [ ] delay between keys
- [ ] mousebuttons

View file

@ -46,7 +46,7 @@ scroll_up=scroll_up
scroll_down=scroll_down
button_1=backward
button_2=forward
button_3=none
button_3=macro1
button_4=dpi-cycle
button_5=report_rate+
button_6=report_rate-

4
example.macro Normal file
View file

@ -0,0 +1,4 @@
down Ctrl_l
down a
up a
up Ctrl_l

View file

@ -51,6 +51,13 @@ mouse_m908::mouse_m908(){
}
}
_report_rates.fill( r_125Hz );
int count = 0;
for( auto &i : _macro_data ){
std::copy(std::begin(_data_macros_2), std::end(_data_macros_2), std::begin(i));
i[2] = _data_macros_codes[count][0];
i[3] = _data_macros_codes[count][1];
count++;
}
//name → keycode
_keycodes = {
@ -67,6 +74,21 @@ mouse_m908::mouse_m908(){
{ "right", { 0x82, 0x00, 0x00 } },
{ "middle", { 0x83, 0x00, 0x00 } },
{ "profile_switch", { 0x8d, 0x00, 0x00 } },
{ "macro1", { 0x91, 0x00, 0x01 } },
{ "macro2", { 0x91, 0x01, 0x01 } },
{ "macro3", { 0x91, 0x02, 0x01 } },
{ "macro4", { 0x91, 0x03, 0x01 } },
{ "macro5", { 0x91, 0x04, 0x01 } },
{ "macro6", { 0x91, 0x05, 0x01 } },
{ "macro7", { 0x91, 0x06, 0x01 } },
{ "macro8", { 0x91, 0x07, 0x01 } },
{ "macro9", { 0x91, 0x08, 0x01 } },
{ "macro10", { 0x91, 0x09, 0x01 } },
{ "macro11", { 0x91, 0x0a, 0x01 } },
{ "macro12", { 0x91, 0x0b, 0x01 } },
{ "macro13", { 0x91, 0x0c, 0x01 } },
{ "macro14", { 0x91, 0x0d, 0x01 } },
{ "macro15", { 0x91, 0x0e, 0x01 } },
{ "none", { 0x00, 0x00, 0x00 } } };
//modifier name → value

View file

@ -194,3 +194,45 @@ uint8_t mouse_m908::_data_settings_3[][16] = {
{0x02, 0xf1, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x02, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
uint8_t mouse_m908::_data_macros_1[16] =
{0x02, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t mouse_m908::_data_macros_2[256] = {
0x04, 0xf3, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint8_t mouse_m908::_data_macros_3[16] =
{0x02, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t mouse_m908::_data_macros_codes[15][2] = {
{0x78, 0x04},
{0x40, 0x05},
{0x08, 0x06},
{0xd0, 0x06},
{0x98, 0x07},
{0x60, 0x08},
{0x28, 0x09},
{0xf0, 0x09},
{0xb8, 0x0a},
{0x80, 0x0b},
{0x48, 0x0c},
{0x10, 0x0d},
{0xd8, 0x0d},
{0xa0, 0x0e},
{0x68, 0x0f} };

View file

@ -27,6 +27,8 @@
#include <algorithm>
#include <exception>
#include <regex>
#include <fstream>
#include <utility>
class mouse_m908{
@ -72,6 +74,7 @@ class mouse_m908{
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::string mapping );
int set_report_rate( m908_profile profile, m908_report_rate report_rate );
int set_macro( int macro_number, std::string file );
//getter functions
m908_profile get_profile();
@ -87,6 +90,7 @@ class mouse_m908{
//writer functions (apply settings to mouse)
int write_profile();
int write_settings();
int write_macro( int macro_number );
//helper functions
int open_mouse();
@ -113,6 +117,7 @@ class mouse_m908{
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<m908_report_rate, 5> _report_rates;
std::array<std::array<uint8_t, 256>, 15> _macro_data;
//setting min and max values
uint8_t _scrollspeed_min, _scrollspeed_max;
@ -131,6 +136,10 @@ class mouse_m908{
static uint8_t _data_settings_1[][16];
static uint8_t _data_settings_2[64];
static uint8_t _data_settings_3[][16];
static uint8_t _data_macros_1[16];
static uint8_t _data_macros_2[256];
static uint8_t _data_macros_3[16];
static uint8_t _data_macros_codes[15][2];
};
#include "data.cpp"

View file

@ -24,4 +24,6 @@ void print_help(){
std::cout << "-h --help\n\tDisplays this message.\n";
std::cout << "-c --config\n\tLoads and applies settings from specified file.\n";
std::cout << "-p --profile\n\tSets currently active profile (1-5).\n";
std::cout << "-m --macro\n\tSeSelects macro file for sending.\n";
std::cout << "-p --profile\n\tSelects macro slot for sending (1-15).\n";
}

View file

@ -136,3 +136,52 @@ int mouse_m908::set_report_rate( m908_profile profile, m908_report_rate report_r
_report_rates[profile] = report_rate;
return 0;
}
int mouse_m908::set_macro( int macro_number, std::string file ){
//check if macro_number is valid
if( macro_number < 1 || macro_number > 15 ){
return 1;
}
//open file
std::ifstream config_in( file );
if( !config_in.is_open() ){
return 1;
}
//process file
std::string value1 = "";
std::string value2 = "";
std::size_t position = 0;
int data_offset = 8;
for( std::string line; std::getline(config_in, line); ){
//process individual line
if( line.length() != 0 ){
position = 0;
position = line.find("\t", position);
value1 = line.substr(0, position);
value2 = line.substr(position+1);
if( value1 == "down" && _keyboard_key_values.find(value2) != _keyboard_key_values.end() ){
_macro_data[macro_number-1][data_offset] = 0x84;
_macro_data[macro_number-1][data_offset+1] = _keyboard_key_values[value2];
data_offset += 3;
} else if( value1 == "up" && _keyboard_key_values.find(value2) != _keyboard_key_values.end() ){
_macro_data[macro_number-1][data_offset] = 0x04;
_macro_data[macro_number-1][data_offset+1] = _keyboard_key_values[value2];
data_offset += 3;
}
if(data_offset > 212){
return 0;
}
}
}
return 0;
}

View file

@ -173,3 +173,34 @@ int mouse_m908::write_settings(){
return 0;
}
int mouse_m908::write_macro( int macro_number ){
//check if macro_number is valid
if( macro_number < 1 || macro_number > 15 ){
return 1;
}
//prepare data 1
uint8_t buffer1[16];
std::copy(std::begin(_data_macros_1), std::end(_data_macros_1), std::begin(buffer1));
//prepare data 2
uint8_t buffer2[265];
std::copy(std::begin(_macro_data[macro_number-1]), std::end(_macro_data[macro_number-1]), std::begin(buffer2));
//prepare data 3
uint8_t buffer3[16];
std::copy(std::begin(_data_macros_3), std::end(_data_macros_3), std::begin(buffer3));
//send data 1
libusb_control_transfer( _handle, 0x21, 0x09, 0x0302, 0x0002, buffer1, 16, 1000 );
//send data 2
libusb_control_transfer( _handle, 0x21, 0x09, 0x0302, 0x0002, buffer2, 256, 1000 );
//send data 3
libusb_control_transfer( _handle, 0x21, 0x09, 0x0302, 0x0002, buffer3, 16, 1000 );
return 0;
}

View file

@ -17,6 +17,23 @@ middle
profile_switch
none
## Macros (see README.md)
macro1
macro2
macro3
macro4
macro5
macro6
macro7
macro8
macro9
macro10
macro11
macro12
macro13
macro14
macro15
## Keyboard keys
### Modifers
ctrl_l+

View file

@ -39,15 +39,19 @@ int main( int argc, char **argv ){
{"help", no_argument, 0, 'h'},
{"config", required_argument, 0, 'c'},
{"profile", required_argument, 0, 'p'},
{"macro", required_argument, 0, 'm'},
{"number", required_argument, 0, 'n'},
{0, 0, 0, 0}
};
bool flag_config = false, flag_profile = false;
bool flag_macro = false, flag_number = false;
std::string string_config, string_profile;
std::string string_macro, string_number;
//parse command line options
int c, option_index = 0;
while( (c = getopt_long( argc, argv, "hc:p:",
while( (c = getopt_long( argc, argv, "hc:p:m:n:",
long_options, &option_index ) ) != -1 ){
switch( c ){
@ -63,6 +67,14 @@ int main( int argc, char **argv ){
flag_profile = true;
string_profile = optarg;
break;
case 'm':
flag_macro = true;
string_macro = optarg;
break;
case 'n':
flag_number = true;
string_number = optarg;
break;
case '?':
break;
default:
@ -406,5 +418,31 @@ int main( int argc, char **argv ){
}
if( flag_macro && flag_number ){
int r;
int number = (int)stoi(string_number);
r = m.set_macro( number, string_macro );
if( r != 0 ){
std::cout << "Couldn't load macro\n";
return 1;
}
r = m.open_mouse();
if( r != 0 ){
std::cout << "Couldn't open mouse\n";
return 1;
}
m.write_macro(number);
m.close_mouse();
} else if( flag_macro || flag_number ){
std::cout << "Misssing option\n";
}
return 0;
}