Add M913 backend

This commit is contained in:
dokutan 2021-02-28 17:15:47 +01:00
parent 60870b773d
commit c4f883bf65
12 changed files with 1174 additions and 3 deletions

17
documentation/M913.md Normal file
View file

@ -0,0 +1,17 @@
# USB protocol of the M913
These notes were taken during the reverse engineering process and may not be entirely accurate.
# changing settings
## sending
Endpoint: 0x00
control transfer
bmRequestType: 0x21
bRequest: 0x09
wValue: 0x0308
wIndex: 0x0001
wLength: 17
## receiving
Endpoint: 0x82
interrupt transfer
data length: 17

View file

@ -47,8 +47,8 @@ std::set< uint16_t > rd_mouse::_c_all_pids = {
0xfc5f, // M998-RGB and M808-RGB (?)
0xfc38, // M607 Griffin
0xfc3f, // (?)
0xfa07, // M913 (has two PIDs for wired/wireless connection)
0xfa08 // M913 (has two PIDs for wired/wireless connection)
0xfa07, // M913 (has two PIDs: wireless connection)
0xfa08 // M913 (has two PIDs: wired connection)
};
//setting min and max values

View file

@ -0,0 +1,60 @@
/*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#include "../rd_mouse.h"
// Constructor, set the default settings
mouse_m913::mouse_m913(){
//default settings
_s_profile = profile_1;
_s_scrollspeeds.fill( 0x01 );
_s_lightmodes.fill( lightmode_static );
_s_colors.fill( {0xff, 0xff, 0xff} );
_s_brightness_levels.fill( 0x03 );
_s_speed_levels.fill( 0x08 );
// dpi
_s_dpi_enabled.fill( {true, true, true, true, true} );
_s_dpi_levels.fill( {{ {0x04, 0x00}, {0x16, 0x00}, {0x2d, 0x00}, {0x43, 0x00}, {0x8c, 0x00} }} );
// button mapping, missing data
/*
for( int i = 0; i < 5; i++ ){
for( int j = 0; j < 8; j++ ){
_s_keymap_data[i][j][0] = _c_data_settings_3[35+(8*i)+j][8];
_s_keymap_data[i][j][1] = _c_data_settings_3[35+(8*i)+j][9];
_s_keymap_data[i][j][2] = _c_data_settings_3[35+(8*i)+j][10];
_s_keymap_data[i][j][3] = _c_data_settings_3[35+(8*i)+j][11];
}
}
*/
_s_report_rates.fill( r_125Hz );
/* missing data
int count = 0;
for( auto &i : _s_macro_data ){
std::copy(std::begin(_c_data_macros_2), std::end(_c_data_macros_2), std::begin(i));
i[2] = _c_data_macros_codes[count][0];
i[3] = _c_data_macros_codes[count][1];
count++;
}
*/
}

54
include/m913/data.cpp Normal file
View file

@ -0,0 +1,54 @@
/*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
/*
* This file contains internal constants and lookup tables
*/
#include "../rd_mouse.h"
const std::string mouse_m913::_c_name = "913";
// usb device vars
const uint16_t mouse_m913::_c_mouse_vid = 0x25a7;
const uint16_t mouse_m913::_c_mouse_pid = 0xfc4d;
// Names of the physical buttons
std::map< int, std::string > mouse_m913::_c_button_names = {
{ 0, "button_left" },
{ 1, "button_right" },
{ 2, "button_middle" },
{ 3, "button_fire" },
//{ 4, "button_dpi_up" }, // not known if remappable
//{ 5, "button_dpi_down" }, // not known if remappable
{ 6, "button_1" },
{ 7, "button_2" },
{ 8, "button_3" },
{ 9, "button_4" },
{ 10, "button_5" },
{ 11, "button_6" },
{ 12, "button_7" },
{ 13, "button_8" },
{ 14, "button_9" },
{ 15, "button_10" },
{ 16, "button_11" },
{ 17, "button_12" },
{ 18, "scroll_up" },
{ 19, "scroll_down" } };
//usb data packets

125
include/m913/getters.cpp Normal file
View file

@ -0,0 +1,125 @@
/*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#include "../rd_mouse.h"
mouse_m913::rd_profile mouse_m913::get_profile(){
return _s_profile;
}
uint8_t mouse_m913::get_scrollspeed( rd_profile profile ){
return _s_scrollspeeds[profile];
}
mouse_m913::rd_lightmode mouse_m913::get_lightmode( rd_profile profile ){
return _s_lightmodes[profile];
}
void mouse_m913::get_color( rd_profile profile, std::array<uint8_t, 3> &color ){
color = _s_colors[profile];
}
uint8_t mouse_m913::get_brightness( rd_profile profile ){
return _s_brightness_levels[profile];
}
uint8_t mouse_m913::get_speed( rd_profile profile ){
return _s_speed_levels[profile];
}
bool mouse_m913::get_dpi_enable( rd_profile profile, int level ){
// check DPI level bounds
if( level < _c_level_min || level > _c_level_max )
return false;
return _s_dpi_enabled[profile][level];
}
int mouse_m913::get_dpi( rd_profile profile, int level, std::array<uint8_t, 2>& dpi ){
// check DPI level bounds
if( level < _c_level_min || level > _c_level_max )
return 1;
dpi[0] = _s_dpi_levels[profile][level][0];
dpi[1] = _s_dpi_levels[profile][level][1];
return 0;
}
mouse_m913::rd_report_rate mouse_m913::get_report_rate( rd_profile profile ){
return _s_report_rates[profile];
}
int mouse_m913::get_key_mapping_raw( mouse_m913::rd_profile profile, int key, std::array<uint8_t, 4>& mapping ){
// valid key ?
if( _c_button_names[key] == "" )
return 1;
mapping[0] = _s_keymap_data[profile][key][0];
mapping[1] = _s_keymap_data[profile][key][1];
mapping[2] = _s_keymap_data[profile][key][2];
mapping[3] = _s_keymap_data[profile][key][3];
return 0;
}
int mouse_m913::get_key_mapping( mouse_m913::rd_profile profile, int key, std::string& mapping ){
// valid key ?
if( _c_button_names[key] == "" )
return 1;
std::array< uint8_t, 4 > bytes = {
_s_keymap_data[profile][key][0],
_s_keymap_data[profile][key][1],
_s_keymap_data[profile][key][2],
_s_keymap_data[profile][key][3]
};
_i_decode_button_mapping( bytes, mapping );
return 0;
}
int mouse_m913::get_macro_raw( int number, std::array<uint8_t, 256>& macro ){
//check if macro_number is valid
if( number < 1 || number > 15 )
return 1;
std::copy( _s_macro_data[number-1].begin(), _s_macro_data[number-1].end(), macro.begin() );
return 0;
}
int mouse_m913::get_macro( int number, std::string& macro ){
std::stringstream output;
// macro undefined?
if( _s_macro_data[number-1][8] == 0 && _s_macro_data[number-1][9] == 0 && _s_macro_data[number-1][10] == 0 )
return 0;
std::vector< uint8_t > macro_bytes;
std::copy( _s_macro_data[number-1].begin(), _s_macro_data[number-1].end(), macro_bytes.begin() );
_i_decode_macro( macro_bytes, output, "", 8 );
macro = output.str();
return 0;
}

300
include/m913/helpers.cpp Normal file
View file

@ -0,0 +1,300 @@
/*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#include "../rd_mouse.h"
//helper functions
//init libusb and open mouse
int mouse_m913::open_mouse(){
//vars
int res = 0;
//libusb init
res = libusb_init( NULL );
if( res < 0 ){
return res;
}
//open device
_i_handle = libusb_open_device_with_vid_pid( NULL, _c_mouse_vid, _c_mouse_pid );
if( !_i_handle ){
return 1;
}
if( _i_detach_kernel_driver ){
//detach kernel driver on interface 0 if active
if( libusb_kernel_driver_active( _i_handle, 0 ) ){
res += libusb_detach_kernel_driver( _i_handle, 0 );
if( res == 0 ){
_i_detached_driver_0 = true;
} else{
return res;
}
}
//detach kernel driver on interface 1 if active
if( libusb_kernel_driver_active( _i_handle, 1 ) ){
res += libusb_detach_kernel_driver( _i_handle, 1 );
if( res == 0 ){
_i_detached_driver_1 = true;
} else{
return res;
}
}
}
//claim interface 0
res += libusb_claim_interface( _i_handle, 0 );
if( res != 0 ){
return res;
}
//claim interface 1
res += libusb_claim_interface( _i_handle, 1 );
if( res != 0 ){
return res;
}
return res;
}
// init libusb and open mouse by bus and device
int mouse_m913::open_mouse_bus_device( uint8_t bus, uint8_t device ){
//vars
int res = 0;
//libusb init
res = libusb_init( NULL );
if( res < 0 ){
return res;
}
//open device (_i_handle)
libusb_device **dev_list; // device list
ssize_t num_devs = libusb_get_device_list(NULL, &dev_list); //get device list
if( num_devs < 0 )
return 1;
for( ssize_t i = 0; i < num_devs; i++ ){
// check if correct bus and device
if( bus == libusb_get_bus_number( dev_list[i] ) &&
device == libusb_get_device_address( dev_list[i] ) ){
// open device
if( libusb_open( dev_list[i], &_i_handle ) != 0 ){
return 1;
} else{
break;
}
}
}
//free device list, unreference devices
libusb_free_device_list( dev_list, 1 );
if( _i_detach_kernel_driver ){
//detach kernel driver on interface 0 if active
if( libusb_kernel_driver_active( _i_handle, 0 ) ){
res += libusb_detach_kernel_driver( _i_handle, 0 );
if( res == 0 ){
_i_detached_driver_0 = true;
} else{
return res;
}
}
//detach kernel driver on interface 1 if active
if( libusb_kernel_driver_active( _i_handle, 1 ) ){
res += libusb_detach_kernel_driver( _i_handle, 1 );
if( res == 0 ){
_i_detached_driver_1 = true;
} else{
return res;
}
}
}
//claim interface 0
res += libusb_claim_interface( _i_handle, 0 );
if( res != 0 ){
return res;
}
//claim interface 1
res += libusb_claim_interface( _i_handle, 1 );
if( res != 0 ){
return res;
}
return res;
}
// close mouse
int mouse_m913::close_mouse(){
// release interfaces 0 and 1
libusb_release_interface( _i_handle, 0 );
libusb_release_interface( _i_handle, 1 );
// attach kernel driver for interface 0
if( _i_detached_driver_0 ){
libusb_attach_kernel_driver( _i_handle, 0 );
}
// attach kernel driver for interface 1
if( _i_detached_driver_1 ){
libusb_attach_kernel_driver( _i_handle, 1 );
}
// exit libusb
libusb_exit( NULL );
return 0;
}
// print current configuration
int mouse_m913::print_settings( std::ostream& output ){
// print configuration
output << "# Configuration created by mouse_m913::print_settings().\n";
output << "# Currently active profile: " << _s_profile << "\n";
for( int i = 1; i < 6; i++ ){
// section header
output << "\n[profile" << i << "]\n";
output << "\n# LED settings\n";
// color
output << "color=";
output << std::setfill('0') << std::setw(2) << std::hex << (int)_s_colors[i-1][0];
output << std::setfill('0') << std::setw(2) << std::hex << (int)_s_colors[i-1][1];
output << std::setfill('0') << std::setw(2) << std::hex << (int)_s_colors[i-1][2];
output << std::setfill(' ') << std::setw(0) << std::dec << "\n";
// brightness
output << "brightness=" << (int)_s_brightness_levels[i-1] << "\n";
// speed
output << "speed=" << (int)_s_speed_levels[i-1] << "\n";
// lightmode
output << "lightmode=";
if( _s_lightmodes[i-1] == lightmode_off )
output << "off\n";
else if( _s_lightmodes[i-1] == lightmode_breathing )
output << "breathing\n";
else if( _s_lightmodes[i-1] == lightmode_rainbow )
output << "rainbow\n";
else if( _s_lightmodes[i-1] == lightmode_static )
output << "static\n";
else if( _s_lightmodes[i-1] == lightmode_wave )
output << "wave\n";
else if( _s_lightmodes[i-1] == lightmode_alternating )
output << "alternating\n";
else if( _s_lightmodes[i-1] == lightmode_reactive )
output << "reactive\n";
else if( _s_lightmodes[i-1] == lightmode_flashing )
output << "flashing\n";
else{
output << "unknown, please report as bug\n";
}
// polling rate (report rate)
output << "\n";
if( _s_report_rates[i-1] == r_125Hz )
output << "report_rate=125\n";
else if( _s_report_rates[i-1] == r_250Hz )
output << "report_rate=250\n";
else if( _s_report_rates[i-1] == r_500Hz )
output << "report_rate=500\n";
else if( _s_report_rates[i-1] == r_1000Hz )
output << "report_rate=1000\n";
else{
output << "# report rate unknown, please report as bug\n";
}
// scrollspeed
output << "scrollspeed=" << std::hex << (int)_s_scrollspeeds[i-1] << std::dec << "\n";
// dpi
output << "\n# DPI settings\n";
for( int j = 1; j < 6; j++ ){
if( _s_dpi_enabled[i-1][j-1] )
output << "dpi" << j << "_enable=1\n";
else
output << "dpi" << j << "_enable=0\n";
// DPI value
std::array<uint8_t, 2> dpi_bytes = {_s_dpi_levels[i-1][j-1][0], _s_dpi_levels[i-1][j-1][1]};
std::string dpi_string = "";
if( _i_decode_dpi( dpi_bytes, dpi_string ) == 0 )
output << "dpi" << j << "=" << dpi_string << "\n";
else
output << "\n";
}
// button mapping
output << "\n# Button mapping\n";
for( int j = 0; j < 8; j++ ){
std::array< uint8_t, 4 > bytes = {
_s_keymap_data[i-1][j][0],
_s_keymap_data[i-1][j][1],
_s_keymap_data[i-1][j][2],
_s_keymap_data[i-1][j][3]
};
std::string mapping;
_i_decode_button_mapping( bytes, mapping );
output << _c_button_names[j] << "=" << mapping << std::endl;
}
}
// macros
output << "\n# Macros\n";
for( int i = 0; i < 15; i++ ){
// is macro not defined ?
if( _s_macro_data[i][8] == 0 && _s_macro_data[i][9] == 0 && _s_macro_data[i][10] == 0 )
continue;
// _i_decode_macros takes a vector as argument, copy array to vector
std::vector< uint8_t > macro_bytes( _s_macro_data[i].begin(), _s_macro_data[i].end() );
// print macro (macro data starts at byte 8)
output << "\n;## macro" << i+1 << "\n";
_i_decode_macro( macro_bytes, output, ";# ", 8 );
}
return 0;
}

279
include/m913/mouse_m913.h Normal file
View file

@ -0,0 +1,279 @@
/*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
//main class
#ifndef MOUSE_M913
#define MOUSE_M913
#include <libusb.h>
#include <map>
#include <array>
#include <string>
#include <algorithm>
#include <exception>
#include <regex>
#include <fstream>
#include <sstream>
#include <utility>
#include <iostream>
#include <iomanip>
/**
* The main class representing the M913 mouse.
* This class has member functions to open, close and apply settings to the mouse.
*
* There are 4 main types of functions:
* - set_*: setters
* - get_*: getters
* - write_*: write the settings to the mouse
* - read_*: read the sttings from the mouse
*
* Therefore the general procedure when changing settings on the mouse is as follows:
* 1. open_mouse() or open_mouse_bus_device()
* 2. set_* (this step only changes the internal state of the class)
* 3. write_* (this step sends the internal state of the class to the mouse)
* 4. close_mouse()
*
* Private member variables are named as follows:
* - \_i\_* for internal variables that determine how the mouse is opened, etc.
* - \_s\_* for variables that describe the settings on the mouse
* - \_c\_* for constants like keycodes, USB data, minimum and maximum values, etc. (these are not neccessarily defined as const)
*/
class mouse_m913 : public rd_mouse{
public:
/// The default constructor. Sets the default settings.
mouse_m913();
//setter functions
/// Set the currently active profile
int set_profile( rd_profile profile );
/** \brief Set the scrollspeed for the specified profile
* \see _c_scrollspeed_min
* \see _c_scrollspeed_max
* \return 0 if successful, 1 if out of bounds
*/
int set_scrollspeed( rd_profile profile, uint8_t speed );
/** \brief Set the led mode for the specified profile
* \see rd_lightmode
* \return 0 if successful
*/
int set_lightmode( rd_profile profile, rd_lightmode lightmode );
/** \brief Set the led color for the specified profile
* \param color color as {r, g, b}
* \return 0 if successful
*/
int set_color( rd_profile profile, std::array<uint8_t, 3> color );
/** \brief Set the led brightness for the specified profile
* \see _c_brightness_min
* \see _c_brightness_max
* \return 0 if successful, 1 if out of bounds
*/
int set_brightness( rd_profile profile, uint8_t brightness );
/** \brief Set the led animation speed for the specified profile
* \see _c_speed_min
* \see _c_speed_max
* \return 0 if successful, 1 if out of bounds
*/
int set_speed( rd_profile profile, uint8_t speed );
/** \brief Enables/Disables a dpi level for the specified profile
* \see _c_level_min
* \see _c_level_max
* \return 0 if successful, 1 if out of bounds
*/
int set_dpi_enable( rd_profile profile, int level, bool enabled );
/** \brief Set the value of a dpi level for the specified profile
* \see _c_dpi_min
* \see _c_dpi_max
* \see _c_level_min
* \see _c_level_max
* \return 0 if successful, 1 if out of bounds or invalid dpi
*/
int set_dpi( rd_profile profile, int level, std::string dpi );
int set_dpi( rd_profile profile, int level, std::array<uint8_t, 2> dpi );
/** \brief Set a mapping for a button for the specified profile
* \param mapping 4 bytes for the usb data packets
* \return 0 if successful
*/
int set_key_mapping( rd_profile profile, int key, std::array<uint8_t, 4> mapping );
/** \brief Set a mapping for a button for the specified profile
* \param mapping button name (see keymap.md)
* \return 0 if successful, 1 if mapping is invalid
*/
int set_key_mapping( rd_profile profile, int key, std::string mapping );
/** \brief Set the USB poll rate for the specified profile
* \see rd_report_rate
* \return 0 if successful
*/
int set_report_rate( rd_profile profile, rd_report_rate report_rate );
/** \brief Load the macro from the specified file into the specified slot
* \param macro_number macro slot (1-15)
* \return 0 if successful
*/
int set_macro( int macro_number, std::string file );
/** \brief Load all macros from the specified .ini file
* \return 0 if successful
*/
int set_all_macros( std::string file );
//getter functions
/// Get currently active profile
rd_profile get_profile();
/// Get scrollspeed of specified profile
uint8_t get_scrollspeed( rd_profile profile );
/// Get led mode of specified profile
rd_lightmode get_lightmode( rd_profile profile );
/// Get led color of specified profile
void get_color( rd_profile profile, std::array<uint8_t, 3> &color );
/// Get led brightness of specified profile
uint8_t get_brightness( rd_profile profile );
/// Get led animation speed of specified profile
uint8_t get_speed( rd_profile profile );
/// Get dpi level enabled/disabled status of specified profile
bool get_dpi_enable( rd_profile profile, int level );
/// Get dpi value of specified level and profile
int get_dpi( rd_profile profile, int level, std::array<uint8_t, 2>& dpi );
/// Get USB poll rate of specified profile
rd_report_rate get_report_rate( rd_profile profile );
/// Get button mapping as a string
int get_key_mapping( rd_profile profile, int key, std::string& mapping );
/// Get button mapping as a 4-byte value
int get_key_mapping_raw( rd_profile profile, int key, std::array<uint8_t, 4>& mapping );
/// Get macro as a string
int get_macro( int number, std::string& macro );
/// Get raw macro bytecode
int get_macro_raw( int number, std::array<uint8_t, 256>& macro );
/// Get USB vendor id
static uint16_t get_vid(){
return _c_mouse_vid;
}
/// Get USB product id
static uint16_t get_pid(){
return _c_mouse_pid;
}
/// Get USB product id
static std::string get_name(){
return _c_name;
}
//writer functions (apply settings to mouse)
/** \brief Write the currently active profile to the mouse
* \return 0 if successful
*/
int write_profile();
/** \brief Write the settings (leds, button mapping, dpi, etc.) to the mouse
* \return 0 if successful
*/
int write_settings();
/** \brief Write a macro to the mouse
* \return 0 if successful
*/
int write_macro( int macro_number );
//helper functions
/** \brief Init libusb and open the mouse by its USB VID and PID
* \return 0 if successful
*/
int open_mouse();
/** \brief Init libusb and open the mouse by the USB bus and device adress
* \return 0 if successful
*/
int open_mouse_bus_device( uint8_t bus, uint8_t device );
/** \brief Close the mouse and libusb
* \return 0 if successful (always at the moment)
*/
int close_mouse();
/// Print the current configuration in .ini format to output
int print_settings( std::ostream& output );
//reader functions (get settings from the mouse)
/// Read the settings and print the raw data to output
int dump_settings( std::ostream& output );
/**
* \brief Read the settings and print the configuration in .ini format to output.
* This does not alter the internal settings of the mouse_m913 class.
*/
int read_and_print_settings( std::ostream& output );
/**
* \brief Read the settings and print the configuration in .ini format to output.
* This updates the internal settings of the mouse_m913 class.
*/
int read_settings();
/// Returns a reference to _c_button_names (physical button names)
std::map< int, std::string >& button_names(){ return _c_button_names; }
private:
/// Names of the physical buttons
static std::map< int, std::string > _c_button_names;
/// The model name
static const std::string _c_name;
//usb device vars
/// USB vendor id, needs to be explicitly set
static const uint16_t _c_mouse_vid;
/// USB product id, needs to be explicitly set
static const uint16_t _c_mouse_pid;
//setting vars
rd_profile _s_profile;
std::array<uint8_t, 5> _s_scrollspeeds;
std::array<rd_lightmode, 5> _s_lightmodes;
std::array<std::array<uint8_t, 3>, 5> _s_colors;
std::array<uint8_t, 5> _s_brightness_levels;
std::array<uint8_t, 5> _s_speed_levels;
std::array<std::array<bool, 5>, 5> _s_dpi_enabled;
std::array<std::array<std::array<uint8_t, 2>, 5>, 5> _s_dpi_levels;
std::array<std::array<std::array<uint8_t, 4>, 8>, 5> _s_keymap_data;
std::array<rd_report_rate, 5> _s_report_rates;
std::array<std::array<uint8_t, 256>, 15> _s_macro_data;
//usb data packets
};
#endif

36
include/m913/readers.cpp Normal file
View file

@ -0,0 +1,36 @@
/*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#include "../rd_mouse.h"
//reader functions (get settings from mouse)
int mouse_m913::dump_settings( std::ostream& output ){
output << "Not implemented, missing data\n";
return 0;
}
int mouse_m913::read_and_print_settings( std::ostream& output ){
output << "Not implemented, missing data\n";
return 0;
}
int mouse_m913::read_settings(){
// missing data
return 0;
}

237
include/m913/setters.cpp Normal file
View file

@ -0,0 +1,237 @@
/*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#include "../rd_mouse.h"
//setter functions
int mouse_m913::set_profile( rd_profile profile ){
_s_profile = profile;
return 0;
}
int mouse_m913::set_scrollspeed( rd_profile profile, uint8_t speed ){
//check if bounds exceeded
if( speed < _c_scrollspeed_min || speed > _c_scrollspeed_max ){
return 1;
}
_s_scrollspeeds[profile] = speed;
return 0;
}
int mouse_m913::set_lightmode( rd_profile profile, rd_lightmode lightmode ){
_s_lightmodes[profile] = lightmode;
return 0;
}
int mouse_m913::set_color( rd_profile profile, std::array<uint8_t, 3> color ){
_s_colors[profile] = color;
return 0;
}
int mouse_m913::set_brightness( rd_profile profile, uint8_t brightness ){
//check bounds
if( brightness < _c_brightness_min || brightness > _c_brightness_max ){
return 1;
}
_s_brightness_levels[profile] = brightness;
return 0;
}
int mouse_m913::set_speed( rd_profile profile, uint8_t speed ){
//check bounds
if( speed < _c_speed_min || speed > _c_speed_max ){
return 1;
}
_s_speed_levels[profile] = speed;
return 0;
}
int mouse_m913::set_dpi_enable( rd_profile profile, int level, bool enabled ){
//check bounds
if( level < _c_level_min || level > _c_level_max ){
return 1;
}
_s_dpi_enabled[profile][level] = enabled;
// check if at least one level enabled
int sum = 0;
for( int i = _c_level_min; i <= _c_level_max; i++ ){
if( _s_dpi_enabled[profile][i] ){
sum++;
}
}
// if no level enabled: reenable specified level
if( sum == 0 ){
_s_dpi_enabled[profile][level] = true;
return 1;
}
return 0;
}
int mouse_m913::set_dpi( rd_profile profile, int level, std::string dpi ){
// check DPI level bounds
if( level < _c_level_min || level > _c_level_max )
return 1;
// check format: 0xABCD (raw bytes)
if( std::regex_match( dpi, std::regex("0x[[:xdigit:]]{4}") ) ){
uint8_t b0 = (uint8_t)stoi( dpi.substr(2,2), 0, 16 );
uint8_t b1 = (uint8_t)stoi( dpi.substr(4,2), 0, 16 );
//check bounds
if( b0 < _c_dpi_min || b0 > _c_dpi_max || b1 < _c_dpi_2_min || b1 > _c_dpi_2_max )
return 1;
_s_dpi_levels[profile][level][0] = b0;
_s_dpi_levels[profile][level][1] = b1;
return 0;
}
return 1;
}
int mouse_m913::set_dpi( rd_profile profile, int level, std::array<uint8_t, 2> dpi ){
// check DPI level bounds
if( level < _c_level_min || level > _c_level_max )
return 1;
//check bounds
if( dpi[0] < _c_dpi_min || dpi[0] > _c_dpi_max || dpi[1] < _c_dpi_2_min || dpi[1] > _c_dpi_2_max )
return 1;
_s_dpi_levels[profile][level][0] = dpi[0];
_s_dpi_levels[profile][level][1] = dpi[1];
return 0;
}
int mouse_m913::set_key_mapping( rd_profile profile, int key, std::array<uint8_t, 4> mapping ){
_s_keymap_data[profile][key][0] = mapping[0];
_s_keymap_data[profile][key][1] = mapping[1];
_s_keymap_data[profile][key][2] = mapping[2];
_s_keymap_data[profile][key][3] = mapping[3];
return 0;
}
int mouse_m913::set_key_mapping( rd_profile profile, int key, std::string mapping ){
// valid key ?
if( _c_button_names[key] == "" )
return 1;
std::array< uint8_t, 4 > bytes;
int return_value = _i_encode_button_mapping( mapping, bytes );
if( return_value == 0 ){
_s_keymap_data[profile][key][0] = bytes[0];
_s_keymap_data[profile][key][1] = bytes[1];
_s_keymap_data[profile][key][2] = bytes[2];
_s_keymap_data[profile][key][3] = bytes[3];
}
return return_value;
}
int mouse_m913::set_report_rate( rd_profile profile, rd_report_rate report_rate ){
_s_report_rates[profile] = report_rate;
return 0;
}
int mouse_m913::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;
}
std::array< uint8_t, 256 > macro_bytes;
_i_encode_macro( macro_bytes, config_in, 8 );
std::copy( macro_bytes.begin()+8, macro_bytes.end(), _s_macro_data[macro_number-1].begin()+8 );
config_in.close();
return 0;
}
int mouse_m913::set_all_macros( std::string file ){
//open file
std::ifstream config_in( file );
if( !config_in.is_open() ){
return 1;
}
int macro_number = 0; // initially invalid
std::array< std::stringstream, 15 > macro_streams;
// get all macros from file
for( std::string line; std::getline(config_in, line); ){
// empty line → skip
if( line.length() == 0 )
continue;
// macro header → set macro_number
if( std::regex_match( line, std::regex(";## macro[0-9]*") ) ){
macro_number = stoi( std::regex_replace( line, std::regex(";## macro"), "" ), 0, 10 );
}
// macro action
if( std::regex_match( line, std::regex(";# .*") ) ){
// valid macronumber ?
if( macro_number < 1 || macro_number > 15 )
continue;
macro_streams.at( macro_number-1 ) << std::regex_replace( line, std::regex(";# "), "" ) << "\n";
}
}
// encode and store all macros
for( int i = 0; i < 15; i++ ){
std::array< uint8_t, 256 > macro_bytes;
_i_encode_macro( macro_bytes, macro_streams.at(i), 8 );
std::copy( macro_bytes.begin()+8, macro_bytes.end(), _s_macro_data.at(i).begin()+8 );
}
return 0;
}

37
include/m913/writers.cpp Normal file
View file

@ -0,0 +1,37 @@
/*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
#include "../rd_mouse.h"
//writer functions (apply changes to mouse)
int mouse_m913::write_profile(){
// missing data
return 0;
}
int mouse_m913::write_settings(){
// missing data
return 0;
}
int mouse_m913::write_macro( int macro_number ){
// missing data
(void)macro_number;
return 0;
}

View file

@ -44,6 +44,7 @@ class mouse_m709;
class mouse_m711;
class mouse_m715;
class mouse_m908;
class mouse_m913;
class mouse_m990;
class mouse_m990chroma;
@ -120,6 +121,7 @@ class rd_mouse{
mouse_m711,
mouse_m715,
mouse_m908,
mouse_m913,
mouse_m990,
mouse_m990chroma
> mouse_variant;
@ -277,6 +279,7 @@ class rd_mouse{
#include "m709/mouse_m709.h"
#include "m711/mouse_m711.h"
#include "m715/mouse_m715.h"
#include "m913/mouse_m913.h"
#include "m990/mouse_m990.h"
#include "m990chroma/mouse_m990chroma.h"
#include "generic/mouse_generic.h"

View file

@ -14,7 +14,7 @@ LIBS != pkg-config --libs libusb-1.0
VERSION_STRING = "\"3.1\""
# compile
build: m908 m709 m711 m715 m990 m990chroma generic data_rd.o rd_mouse.o load_config.o mouse_m908.o
build: m908 m709 m711 m715 m913 m990 m990chroma generic data_rd.o rd_mouse.o load_config.o mouse_m908.o
$(CC) *.o -o mouse_m908 $(LIBS) $(CC_OPTIONS)
# copy all files to their correct location
@ -81,6 +81,8 @@ m711: constructor_m711.o data_m711.o getters_m711.o helpers_m711.o setters_m711.
m715: constructor_m715.o data_m715.o getters_m715.o helpers_m715.o setters_m715.o writers_m715.o readers_m715.o
m913: constructor_m913.o data_m913.o getters_m913.o helpers_m913.o setters_m913.o writers_m913.o readers_m913.o
m990: constructor_m990.o data_m990.o getters_m990.o helpers_m990.o setters_m990.o writers_m990.o readers_m990.o
m990chroma: constructor_m990chroma.o data_m990chroma.o getters_m990chroma.o helpers_m990chroma.o setters_m990chroma.o writers_m990chroma.o readers_m990chroma.o
@ -205,6 +207,27 @@ writers_generic.o:
readers_generic.o:
$(CC) -c include/generic/readers.cpp $(CC_OPTIONS) -o readers_generic.o
constructor_m913.o:
$(CC) -c include/m913/constructor.cpp $(CC_OPTIONS) -o constructor_m913.o
data_m913.o:
$(CC) -c include/m913/data.cpp $(CC_OPTIONS) -o data_m913.o
getters_m913.o:
$(CC) -c include/m913/getters.cpp $(CC_OPTIONS) -o getters_m913.o
helpers_m913.o:
$(CC) -c include/m913/helpers.cpp $(CC_OPTIONS) -o helpers_m913.o
setters_m913.o:
$(CC) -c include/m913/setters.cpp $(CC_OPTIONS) -o setters_m913.o
writers_m913.o:
$(CC) -c include/m913/writers.cpp $(CC_OPTIONS) -o writers_m913.o
readers_m913.o:
$(CC) -c include/m913/readers.cpp $(CC_OPTIONS) -o readers_m913.o
constructor_m990.o:
$(CC) -c include/m990/constructor.cpp $(CC_OPTIONS) -o constructor_m990.o