Add support for macros
This commit is contained in:
parent
ca95cdf881
commit
6dd9083806
11 changed files with 238 additions and 4 deletions
24
README.md
24
README.md
|
@ -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
|
||||
|
|
|
@ -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
4
example.macro
Normal file
|
@ -0,0 +1,4 @@
|
|||
down Ctrl_l
|
||||
down a
|
||||
up a
|
||||
up Ctrl_l
|
|
@ -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
|
||||
|
|
|
@ -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} };
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
17
keymap.md
17
keymap.md
|
@ -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+
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue