set dpi destroys everything, media button only works on windows

This commit is contained in:
Denis Manherz 2024-09-01 03:08:37 +02:00
parent 01299aa9a8
commit efbeeac8d5
14 changed files with 1059 additions and 29 deletions

View file

@ -11,3 +11,15 @@ install udev rule that automatically runs driver when you plug in the device??
irgendwie hab ich ne zeit lang timout beim config writen bekommen nachdem des config restored wurde bzw wo ich immer mal wireless und wire geswitched habe irgendwie hab ich ne zeit lang timout beim config writen bekommen nachdem des config restored wurde bzw wo ich immer mal wireless und wire geswitched habe
nach reboot und write von original software gehts aber wieder nach reboot und write von original software gehts aber wieder
take a look at fire_key
validate macros
dpi things are weird
setButton could be accepting multiple keybardkeys max 2
test le _keyboardKeys
multimedia keys working on windows but not on linux for some reason

BIN
asd

Binary file not shown.

View file

@ -46,10 +46,11 @@ First Part
0x04-0x07 ?? 0x04-0x07 ??
0x08-0x09 0x64 0x17 Profil 1, 0x64 0x01 Profil 2 ????? 0x08-0x09 0x64 0x17 Profil 1, 0x64 0x01 Profil 2 ?????
0x0a USB Polling Rate [0x01-0x04]->[125,250,500,1000] 0x0a USB Polling Rate [0x01-0x04]->[125,250,500,1000]
0x0b 0x11-0x15 wert für häckchen bei dpi, erstes 0x11 zweites 0x12 usw.. 0x0b 0x11-0x15 wert für häckchen bei dpi, erstes 0x11 zweites 0x12 usw.. (selected mode)(available modes)
0x0c ? 0x0c ?
0x0d-0x16 jeweils 2 byte most significant byte last, * 50 -> annäherung an dpi -50 0x0d-0x16 jeweils 2 byte most significant byte last, * 50 -> annäherung an dpi -50
0x17-0x44 ??? 0x2d-0x3b Colorcode für welche DPI selected RGB * 5
0x3c-0x44 ???
0x45 Lighting Mode, 02 Steady, 01 Colorful Streaming, 03 Breathing 0x45 Lighting Mode, 02 Steady, 01 Colorful Streaming, 03 Breathing
0x46 0-4 Brightness und 0-4 Speed bei colorful 0x(br)(sp) 0x46 0-4 Brightness und 0-4 Speed bei colorful 0x(br)(sp)
0x47 ? 0x47 ?
@ -133,7 +134,7 @@ Tastenbelegung
ThreeClick -> 0x31 0x01 0x32 0x03, whatever this is? ThreeClick -> 0x31 0x01 0x32 0x03, whatever this is?
RGB on/off -> 0x50 0x02 0x00 0x00 -> hat die letzten bytes mit 0 geschrieben RGB on/off -> 0x50 0x02 0x00 0x00 -> hat die letzten bytes mit 0 geschrieben
Disable -> 0x50 0x01 0x00 0x00 Disable -> 0x50 0x01 0x00 0x00
Fire Key -> 0x31 0x01 0xff 0x03 -> 0xff ist the firespeed und iie kann man die klick anzahl (3) nicht ändern aber denke ist 0x03 Fire Key -> 0x31 0x01 0xff 0x03 -> 0xff ist the firespeed und iwie kann man die klick anzahl (3) nicht ändern aber denke ist 0x03
Multimedia->Starts with 0x22 Multimedia->Starts with 0x22
Media Player -> 0x22 0x00 0x01 0x00 Media Player -> 0x22 0x00 0x01 0x00

Binary file not shown.

View file

@ -10,6 +10,8 @@ target_sources(kirigami-hello
main.cpp main.cpp
conf.cpp conf.h conf.cpp conf.h
usb_thingy.cpp usb_thingy.h usb_thingy.cpp usb_thingy.h
a811.cpp a811.h
le_buttons.cpp
) )
ecm_target_qml_sources(kirigami-hello ecm_target_qml_sources(kirigami-hello

411
src/a811.cpp Normal file
View file

@ -0,0 +1,411 @@
#include <cstring>
#include <string.h>
#include "a811.h"
#include "usb_thingy.h"
#define CHK(X) \
if ((r = (X)) != 0) \
return r;
ssize_t logError(const std::string &errorMessage, const char *file, int line,
const char *function)
{
std::cerr << "ERROR: " << file << ":" << line << " - " << function << ": "
<< errorMessage << std::endl;
return 1;
}
A811::A811()
{
// Init usb lib
_connection = &(Connection::getInstance());
// init other vars
_conf12 = (conf_12 *)malloc(sizeof(conf_12));
memset(_conf12, 0, sizeof(conf_12));
readConfigFromDevice(CONF_TYPE::LIGHT);
_macros = nullptr;
}
ssize_t A811::setLightMode(LIGHT_MODE mode, int p1, int p2)
{
switch (mode)
{
case LIGHT_MODE::COLORFUL_STREAMING:
if (p1 <= 0 || p1 > 4 || p2 <= 0 || p2 > 4)
logError("ERROR: Invalid brightness or speed.", __FILE__, __LINE__,
__func__);
_conf12->c1.light_mode = (uint8_t)mode;
_conf12->c1.col_brightness_speed =
(uint8_t)((p1 & 0x0F) | ((p2 & 0x0F) << 4));
std::cout << std::hex << (int)_conf12->c1.light_mode << "-2\n";
break;
case LIGHT_MODE::STEADY:
if (p1 <= 0 || p1 > 4 || p2 <= 0 || p2 > 4)
logError("ERROR: Invalid brightness or speed.", __FILE__, __LINE__,
__func__);
_conf12->c1.col_brightness_speed =
(uint8_t)((p1 & 0x0F) | ((p2 & 0x0F) << 4));
_conf12->c1.light_mode = (uint8_t)mode;
break;
case LIGHT_MODE::BREATHING:
if (p1 <= 0 || p1 > 4 || p2 <= 0 || p2 > 6)
logError("ERROR: Invalid brightness or color number.", __FILE__, __LINE__,
__func__);
_conf12->c1.light_mode = (uint8_t)mode;
_conf12->c1.br_brightness_speed =
(uint8_t)((p1 & 0x0F) | ((p2 & 0x0F) << 4));
break;
default:
logError("ERROR: Invalid LIGHT_MODE.", __FILE__, __LINE__, __func__);
return ssize_t(1);
}
return ssize_t(0);
}
LIGHT_MODE A811::getLightMode() { return LIGHT_MODE(_conf12->c1.light_mode); }
ssize_t A811::setLightModeColors(LIGHT_MODE mode, unsigned char colors[21])
{
switch (mode)
{
case LIGHT_MODE::STEADY:
std::memcpy(&_conf12->c1.col_steady, colors, sizeof(_conf12->c1.col_steady));
break;
case LIGHT_MODE::BREATHING:
std::memcpy(&_conf12->c1.col_breathing, colors,
sizeof(_conf12->c1.col_breathing));
break;
default:
logError("ERROR: Invalid LIGHT_MODE.", __FILE__, __LINE__, __func__);
return ssize_t(1);
}
return ssize_t(0);
}
unsigned char *A811::getLightModeColors(LIGHT_MODE mode)
{
switch (mode)
{
case LIGHT_MODE::STEADY:
return _conf12->c1.col_steady;
case LIGHT_MODE::BREATHING:
return _conf12->c1.col_breathing;
default:
logError("ERROR: Invalid LIGHT_MODE.", __FILE__, __LINE__, __func__);
return nullptr;
}
}
ssize_t A811::setUSBPollingRate(POLLING_RATE pr)
{
if ((uint8_t)pr <= 0 || (uint8_t)pr > 4)
logError("ERROR: Invalid POLLING_RATE.", __FILE__, __LINE__, __func__);
_conf12->c1.polling_rate = (uint8_t)pr;
return ssize_t();
}
POLLING_RATE A811::getUSBPollingRate()
{
return POLLING_RATE(_conf12->c1.polling_rate);
}
ssize_t A811::setDPI(DPI_MODE mode, unsigned char color[3], int dpi)
{
if ((uint8_t)mode < (uint8_t)DPI_MODE::DPI_1 ||
(uint8_t)mode > (uint8_t)DPI_MODE::DPI_5)
{
logError("ERROR: Invalid DPI_MODE.", __FILE__, __LINE__, __func__);
return ssize_t(1);
}
if (dpi > 26000 || dpi < 50)
{
logError("ERROR: Invalid dpi.", __FILE__, __LINE__, __func__);
return ssize_t(2);
}
// Calculate the DPI value according to the formula
int dpi_value = (dpi - 50) / 50;
// Split the value into two bytes (least significant byte first)
uint8_t lsb = dpi_value & 0xFF; // Extract the least significant byte
uint8_t msb = (dpi_value >> 8) & 0xFF; // Extract the most significant byte
_conf12->c1.dpi_modes =
(uint8_t)(((uint8_t)mode & 0x0F) | ((0x1 & 0x0F) << 4));
_conf12->c1.hdpi[(uint8_t)mode - 1 * 2] = lsb;
_conf12->c1.hdpi[(uint8_t)mode - 1 * 2 + 1] = msb;
_conf12->c1.col_dpi[0] = color[(uint8_t)mode - 1 * 3];
_conf12->c1.col_dpi[1] = color[(uint8_t)mode - 1 * 3 + 1];
_conf12->c1.col_dpi[2] = color[(uint8_t)mode - 1 * 3 + 2];
return ssize_t(0);
}
int A811::getDPI(DPI_MODE mode)
{
if ((uint8_t)mode < (uint8_t)DPI_MODE::DPI_1 ||
(uint8_t)mode > (uint8_t)DPI_MODE::DPI_5)
{
logError("ERROR: Invalid DPI_MODE.", __FILE__, __LINE__, __func__);
return ssize_t(1);
}
return 0;
}
BATTERY_STAT A811::getBatteryStatus()
{
if (_batStat.wired == 0x10)
{
if (_batStat.capacity == 0x01)
return BATTERY_STAT::CHARGING;
else if (_batStat.capacity == 0x02)
return BATTERY_STAT::NOT_CHARGING;
}
return BATTERY_STAT::DISCHARGING;
}
int A811::getBatteryCapacity()
{
if (_batStat.wired == 0x11)
return (int)_batStat.capacity;
//@comment thats weird what to do i cant read the battery level if it is
// plugged???
else
return 0;
}
ssize_t A811::setMultimediaButton(int id, std::string keyname)
{
if (id >= 0 && id < 7)
{
// Assuming keyname is a valid key in the _keycodes map
if (_keycodes.find(keyname) == _keycodes.end())
{
logError("ERROR: Keyname not found in keycodes.", __FILE__, __LINE__, __func__);
return ssize_t(1); // or handle the error appropriately
}
auto arr = _keycodes[keyname];
unsigned char *mahbytes = (unsigned char *)&_conf12->c2.mouse_buttons[id];
for (int i = 0; i < (int)sizeof(_conf12->c2.mouse_buttons[id]); ++i)
{
std::cout << std::hex << (int)mahbytes[i] << "|";
mahbytes[i] = ((unsigned char *)&arr)[i];
std::cout << std::hex << (int)mahbytes[i] << std::endl;
}
}
else if (id >= 7 && id < 15)
{
// Assuming keyname is a valid key in the _keycodes map
auto it = _keycodes.find(keyname);
if (it != _keycodes.end())
{
const std::array<uint8_t, 4> &keycode_array = it->second; // Get the array from the map
// std::copy(keycode_array.begin(), keycode_array.end(), _conf12->c2.side[id - 7].keycode);
}
else
{
logError("ERROR: Keyname not found in keycodes.", __FILE__, __LINE__, __func__);
return ssize_t(1); // or handle the error appropriately
}
}
else
{
logError("ERROR: Invalid button id.", __FILE__, __LINE__, __func__);
return ssize_t(1);
}
return ssize_t(0);
}
ssize_t A811::setMacroButton(int id, int macro_id, int cycle_type, int cycle_cnt)
{
unsigned char keyConf[4] = {0x70, macro_id, cycle_type, cycle_cnt};
// maybe check if macro is on mouse
// check validity of data
// also i am not sure at all how the macro ids work like why is the 1st key alway macro nr 1 and so on
if (id >= 0 && id < 7)
{
memcpy(&_conf12->c2.mouse_buttons[id], keyConf, sizeof(_conf12->c2.mouse_buttons[id]));
}
else if (id >= 7 && id < 15)
{
memcpy(&_conf12->c2.side[id - 7], keyConf, sizeof(_conf12->c2.side[id]));
}
else
{
logError("ERROR: Invalid button id.", __FILE__, __LINE__, __func__);
return ssize_t(1);
}
return ssize_t(0);
}
ssize_t A811::setButton(int id, std::string keyboardKey, int mod)
{
unsigned char key[4];
key[0] = 0x21;
key[1] = mod;
if (id >= 0 && id < 7)
{
// Assuming keyname is a valid key in the _keycodes map
auto it = _keyboardKeys.find(keyboardKey);
if (it != _keyboardKeys.end())
{
key[2] = it->second;
key[3] = 0x00; // optional button
memcpy(&_conf12->c2.mouse_buttons[id], key, sizeof(_conf12->c2.mouse_buttons[id]));
}
else
{
logError("ERROR: Keyname not found in _keyboardKeys.", __FILE__, __LINE__, __func__);
return ssize_t(1); // or handle the error appropriately
}
}
else if (id >= 7 && id < 15)
{
// Assuming keyname is a valid key in the _keycodes map
auto it = _keyboardKeys.find(keyboardKey);
if (it != _keyboardKeys.end())
{
key[2] = it->second;
key[3] = 0x00; // optional button
memcpy(&_conf12->c2.side[id], key, sizeof(_conf12->c2.side[id]));
}
else
{
logError("ERROR: Keyname not found in _keyboardKeys.", __FILE__, __LINE__, __func__);
return ssize_t(1); // or handle the error appropriately
}
}
else
{
logError("ERROR: Invalid button id.", __FILE__, __LINE__, __func__);
return ssize_t(1);
}
return ssize_t(0);
}
_r_button A811::getButton(int id)
{
_r_button b;
/*
if (id >= 0 && id < 7){
// Assuming keyname is a valid key in the _keycodes map
auto it = _buttonNames.find(id);
if (it != _buttonNames.end()) {
b.name = it->second;
} else {
logError("ERROR: Button name not found in _buttonNames.", __FILE__, __LINE__, __func__);
// Handle the error appropriately, e.g., returning an empty _r_button
return _r_button(); // Return empty or error _r_button
}
}
else if (id >= 7 && id < 15)
{
// Assuming keyname is a valid key in the _keycodes map
auto it = _buttonNames.find(id-7);
if (it != _buttonNames.end()) {
b.name = it->second;
} else {
logError("ERROR: Button name not found in _buttonNames.", __FILE__, __LINE__, __func__);
// Handle the error appropriately, e.g., returning an empty _r_button
return _r_button(); // Return empty or error _r_button
}
}
else
{
logError("ERROR: Invalid button id.", __FILE__, __LINE__, __func__);
}
*/
return _r_button();
}
ssize_t A811::readConfigFromDevice(CONF_TYPE t_conf)
{
unsigned char _data[8] = {0x05, 0x21, 0, 0, 0, 0, 0, 0};
unsigned char _datas[520];
memset(_datas, 0, 520);
/*if(!connection->isWireless())
_data[1] = 0x11;*/
// not sure if this means anything
ssize_t r;
CHK(_connection->open());
switch (t_conf)
{
case CONF_TYPE::LIGHT:
_data[1] = 0x21;
CHK(_connection->setReport(0x0305, _data, 8));
CHK(_connection->getReport(0x0308, (unsigned char*)&_conf12->c1, 520));
break;
case CONF_TYPE::KEY:
_data[1] = 0x22;
CHK(_connection->setReport(0x0305, (unsigned char *)_data, 8));
CHK(_connection->getReport(0x0308, (unsigned char *)&_conf12->c2, 520));
break;
case CONF_TYPE::MACRO:
logError("ERROR: Macros not implemented.", __FILE__, __LINE__, __func__);
break;
case CONF_TYPE::BATTERY:
_data[1] = 0x90;
CHK(_connection->setReport(0x0305, (unsigned char *)_data, 8));
CHK(_connection->getReport(0x0305, (unsigned char *)&_batStat, 8));
break;
default:
logError("ERROR: Invalid CONF_TYPE.", __FILE__, __LINE__, __func__);
CHK(_connection->close());
return ssize_t(1);
}
CHK(_connection->close());
return ssize_t(0);
}
ssize_t A811::writeConfigToDevice(CONF_TYPE t_conf)
{
ssize_t r;
CHK(_connection->open());
switch (t_conf)
{
case CONF_TYPE::LIGHT:
_conf12->c1.req_type = 0x92;
std::cout << std::hex << (int)_conf12->c1.light_mode << "-3\n";
CHK(_connection->setReport(0x0308, (unsigned char *)&_conf12->c1, 520));
break;
case CONF_TYPE::KEY:
_conf12->c2.req_type = 0x50;
CHK(_connection->setReport(0x0308, (unsigned char *)&_conf12->c2, 520));
break;
case CONF_TYPE::MACRO:
logError("ERROR: Macros not implemented.", __FILE__, __LINE__, __func__);
break;
case CONF_TYPE::BATTERY:
logError("ERROR: Invalid write to CONF_TYPE::BATTERY.", __FILE__, __LINE__,
__func__);
break;
default:
logError("ERROR: Invalid CONF_TYPE.", __FILE__, __LINE__, __func__);
CHK(_connection->close());
return ssize_t(1);
}
CHK(_connection->close());
return ssize_t(0);
}

256
src/a811.h Normal file
View file

@ -0,0 +1,256 @@
#include <map>
#include <array>
#include "structs.h"
#include "usb_thingy.h"
#define MOD_CTRL 1
#define MOD_SHIFT 2
#define MOD_ALT 4
#define MOD_SUPER 8
struct _r_keyCode
{
std::string mods;
std::string keyCode;
};
struct _r_button
{
std::string name;
_r_keyCode key;
};
enum class LIGHT_MODE : uint8_t
{
COLORFUL_STREAMING = 1,
STEADY,
BREATHING
};
enum class POLLING_RATE : uint8_t
{
P_125 = 1,
P_250,
P_500,
P_1000
};
enum class DPI_MODE : uint8_t
{
DPI_1 = 1,
DPI_2,
DPI_3,
DPI_4,
DPI_5
};
enum class CONF_TYPE : uint8_t
{
LIGHT,
KEY,
MACRO,
BATTERY
};
enum class BATTERY_STAT : uint8_t
{
CHARGING,
DISCHARGING,
NOT_CHARGING
};
class A811
{
public:
A811();
/**
* @brief Set the light mode and its associated parameters.
*
* This function sets the light mode for a device. Depending on the `mode`
* parameter, the meanings of `param1` and `param2` will vary.
*
* @param mode The mode in which the light should operate.
*
* Possible values are:
*
* - `LIGHT_MODE::STEADY`: The light remains steady.
* - `param1`: Brightness (0-4).
* - `param2`: Index of Color (0-6).
* - `LIGHT_MODE::COLORFUL_STREAMING`: Rainbow effect.
* - `param1`: Brightness (0-4).
* - `param2`: Transition speed (0-4).
* - `LIGHT_MODE::BREATHING`: The light pulses gradually in intensity.
* - `param1`: Brightness (0-4).
* - `param2`: Transition speed (0-4).
*
* @param param1 The first parameter, whose meaning depends on the selected
* `mode`.
* @param param2 The second parameter, whose meaning depends on the selected
* `mode`.
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t setLightMode(LIGHT_MODE, int, int);
/**
* @brief Get the current light mode.
*
* This function retrieves the current light mode of the device.
*
* @return LIGHT_MODE The current mode in which the light is operating.
*/
LIGHT_MODE getLightMode();
/**
* @brief Set the colors for the light modes.
*
* This function allows you to set specific color values for different light
* modes.
*
* @param mode The mode for which to set the color values.
* @param colors An array of 21 unsigned char values representing 7 RGB
* values.
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t setLightModeColors(LIGHT_MODE, unsigned char[21]);
/**
* @brief Set the colors for the light modes.
*
* This function allows you to set specific color values for different light
* modes.
*
* @param mode The mode for which to set the color values.
* @param colors An array of 21 unsigned char values representing 7 RGB
* values.
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
unsigned char *getLightModeColors(LIGHT_MODE);
/**
* @brief Set the polling rate.
*
* This function allows you to set a specific polling rate.
*
* @param p_rate The mode for which to set the color values.
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t setUSBPollingRate(POLLING_RATE);
/**
* @brief Get the current polling rate.
*
* This function retrieves the current light mode of the device.
*
* @return POLLING_RATE The current mode in which the light is operating.
*/
POLLING_RATE getUSBPollingRate();
// dpi loop loops consecutively throug dpi modes, e.g. if 1 is active but 2
// not it will loop to 2 before 3 how to solve this see witch modes are active
// and save them consecutively with according color and shit but then you need
// to put non active modes last and when you activate them again need to
// insert them in the right position int is DPI max is 26000 in is 50
/// itse not a this class probelm i think just set the values,
// itse more a dpi loop problem just need to set the values from frontend like
// explained before
ssize_t setDPI(DPI_MODE, unsigned char[3], int);
// returns all active dpi configurations
int getDPI(DPI_MODE);
BATTERY_STAT getBatteryStatus();
/**
* @brief Retrieves the battery capacity.
*
* This function returns the battery capacity of the device.
*
* @note If the device is plugged in (wired mode), the battery level cannot be
* read and the function will return 0.
*
* @return int The current battery capacity if not plugged in; otherwise,
* returns 0.
*/
int getBatteryCapacity();
/**
* @brief Assign a multimedia key to a button.
*
* Assign a multimedia key to a button.
*
* @param id id of the button to assign to 0-14.
* @param keyname name of the assigned key. @see _keycodes
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t setMultimediaButton(int, std::string);
/**
* @brief Assign a macro to a button.
*
* Assign a macro to a button.
*
* @param id id of the button to assign to 0-14.
* @param macro_id id of the macro to assign. @see _keycodes
* @param cycle_type if 0x02 cycle until any button pressed, if 0x04 cycle till the key is released
* @param cycle_cnt if cycle type 0x01 how often the macro should be cycled
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t setMacroButton(int, int, int, int);
/**
* @brief Assign a simple keyboard key w/o modifier to a button.
*
* Assign a simple keyboard key w/o modifier to a button.
*
* @param id id of the button to assign to 0-14.
* @param keyboardKey name of the assigned key. @see le_buttons.cpp
* @param mod which modifiers should be used.
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t setButton(int, std::string, int);
/**
* @brief Get the button and its config.
*
* Get the configuration of a button.
*
* @param id id of the button to assign to 0-14.
*
* @return _r_button returns the button name, and the assigned keyCode
*/
_r_button getButton(int);
ssize_t readConfigFromDevice(CONF_TYPE);
ssize_t writeConfigToDevice(CONF_TYPE);
private:
conf_12 *_conf12;
battery_stat _batStat;
static std::map<std::string, std::array<uint8_t, 4>> _keycodes;
static std::map<int, std::string> _buttonNames;
static std::map<std::string, uint8_t> _keyboardKeys;
// still need to find out how many macros fit on device
// if i wanna do a full conf struct size of macros needs to be known?
macro **_macros;
Connection *_connection;
};

View file

@ -31,7 +31,8 @@ int main(int argc, char *argv[])
if (Connection::getInstance().findDevice()) if (Connection::getInstance().findDevice())
{ {
std::cerr << "ERROR: Device not found!"; std::cerr << "ERROR: Device not found!"
<< "\n";
return 1; return 1;
} }

View file

@ -1,8 +1,8 @@
#include "conf.h" #include "conf.h"
#include <iostream>
#include <QDebug> #include <QDebug>
#include <qfiledialog.h> #include <iostream>
#include <klocalizedstring.h> #include <klocalizedstring.h>
#include <qfiledialog.h>
#define CHK(X) \ #define CHK(X) \
if ((r = (X)) != 0) \ if ((r = (X)) != 0) \
@ -12,12 +12,17 @@ Conf::Conf(QObject *parent) : QObject(parent)
{ {
m_conf1 = (conf_1 *)malloc(sizeof(conf_1)); m_conf1 = (conf_1 *)malloc(sizeof(conf_1));
m_conf2 = (conf_2 *)malloc(sizeof(conf_2)); m_conf2 = (conf_2 *)malloc(sizeof(conf_2));
std::cout << std::dec << sizeof(conf_1) << "; " << sizeof(conf_2) << std::endl; std::cout << std::dec << sizeof(conf_1) << "; " << sizeof(conf_2)
<< std::endl;
memset(m_conf1, 0, sizeof(conf_1)); memset(m_conf1, 0, sizeof(conf_1));
memset(m_conf2, 0, sizeof(conf_2)); memset(m_conf2, 0, sizeof(conf_2));
connection = &(Connection::getInstance()); connection = &(Connection::getInstance());
connection->findDevice(); if (connection->findDevice())
{
std::cerr << "ERROR: device not found" << std::endl;
exit(1);
}
// read initial config from device // read initial config from device
readConfigFromDevice(m_conf1); readConfigFromDevice(m_conf1);
@ -76,7 +81,8 @@ ssize_t Conf::deleteMacroFromFile(macro *_macro, const char *filePath)
// Read each macro from the original file // Read each macro from the original file
while (fread(&temp_macro, sizeof(macro), 1, infile) == 1) while (fread(&temp_macro, sizeof(macro), 1, infile) == 1)
{ {
// If the macro ID does not match the one to delete, write it to the temp file // If the macro ID does not match the one to delete, write it to the temp
// file
if (temp_macro.macro_nr != _macro->macro_nr) if (temp_macro.macro_nr != _macro->macro_nr)
{ {
fwrite(&temp_macro, sizeof(macro), 1, tempfile); fwrite(&temp_macro, sizeof(macro), 1, tempfile);
@ -93,7 +99,8 @@ ssize_t Conf::deleteMacroFromFile(macro *_macro, const char *filePath)
// Replace the original file with the temp file // Replace the original file with the temp file
remove(filePath); // Delete the original file remove(filePath); // Delete the original file
rename("tempfile.bin", filePath); // Rename the temp file to the original file name rename("tempfile.bin",
filePath); // Rename the temp file to the original file name
return 0; return 0;
@ -102,18 +109,56 @@ ssize_t Conf::deleteMacroFromFile(macro *_macro, const char *filePath)
void Conf::testFunc() void Conf::testFunc()
{ {
macro **macros; /*macro **macros;
readMacrosFromDevice(macros, 4); readMacrosFromDevice(macros, 4);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
appendMacroToFile(macros[i], "macrofileappend"); appendMacroToFile(macros[i], "macrofileappend");
} }*/
A811 *asd = new A811();
asd->readConfigFromDevice(CONF_TYPE::BATTERY);
asd->readConfigFromDevice(CONF_TYPE::LIGHT);
asd->readConfigFromDevice(CONF_TYPE::KEY);
asd->setLightMode(LIGHT_MODE::BREATHING, 1, 4);
asd->writeConfigToDevice(CONF_TYPE::LIGHT);
asd->setUSBPollingRate(POLLING_RATE::P_1000);
std::cout << "UBS Polling rate: " << (int)asd->getUSBPollingRate() << std::endl;
std::cout << "BATTERYSTATUS: " << (int)asd->getBatteryStatus() << std::endl;
std::cout << "LIGHTMODE: " << (int)asd->getLightMode() << std::endl;
asd->setLightMode(LIGHT_MODE::COLORFUL_STREAMING, 1, 2);
asd->writeConfigToDevice(CONF_TYPE::LIGHT);
sleep(2);
asd->setMultimediaButton(2, "media_volume_up");
asd->writeConfigToDevice(CONF_TYPE::KEY);
std::cout << asd->getButton(3).name << std::endl;
asd->setLightMode(LIGHT_MODE::BREATHING, 4, 4);
unsigned char *cols;
cols = asd->getLightModeColors(LIGHT_MODE::BREATHING);
asd->getLightModeColors(LIGHT_MODE::COLORFUL_STREAMING);
unsigned char cols2[21] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00};
asd->setLightModeColors(LIGHT_MODE::BREATHING, cols2);
unsigned char cols3[3] = {0xff, 0xff, 0x00};
//asd->setDPI(DPI_MODE::DPI_1, cols3, 13000); --> setting this kills everything
//asd->writeConfigToDevice(CONF_TYPE::KEY);
std::cout << "Battery capacity:" << std::dec << asd->getBatteryCapacity() << std::endl;
asd->writeConfigToDevice(CONF_TYPE::LIGHT);
} }
int Conf::lightMode() int Conf::lightMode() { return m_conf1->light_mode; }
{
return m_conf1->light_mode;
}
void Conf::setLightMode(int mode) void Conf::setLightMode(int mode)
{ {
@ -214,6 +259,12 @@ ssize_t Conf::writeConfigToDevice(conf_1 *conf)
CHK(connection->setReport(0x0308, (unsigned char *)conf, 520)); CHK(connection->setReport(0x0308, (unsigned char *)conf, 520));
CHK(connection->close()); CHK(connection->close());
for (int i = 0; i < (0x44 - 0x16); i++)
{
std::cout << std::hex << (int)conf->__u5[i] << "\t";
}
std::cout << std::endl;
return 0; return 0;
} }
@ -335,7 +386,8 @@ ssize_t Conf::readAssignedMacrosFromDevice()
int macroCnt = 0; int macroCnt = 0;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
if (m_conf2->side[i].pref == 0x70 || (m_conf2->mouse_buttons[i].pref == 0x70 && i < 6)) if (m_conf2->side[i].pref == 0x70 ||
(m_conf2->mouse_buttons[i].pref == 0x70 && i < 6))
macroCnt++; macroCnt++;
} }
std::cout << macroCnt << std::endl; std::cout << macroCnt << std::endl;
@ -370,6 +422,12 @@ ssize_t Conf::readConfigFromDevice(conf_1 *conf)
CHK(connection->getReport(0x0308, (unsigned char *)conf, 520)); CHK(connection->getReport(0x0308, (unsigned char *)conf, 520));
CHK(connection->close()); CHK(connection->close());
for (int i = 0; i < (0x44 - 0x16); i++)
{
std::cout << std::hex << (int)conf->__u5[i] << "\t";
}
std::cout << std::endl;
return ssize_t(0); return ssize_t(0);
} }
@ -467,6 +525,40 @@ ssize_t Conf::readConfigFromFile(const char *filePath)
return 0; return 0;
} }
ssize_t Conf::getIdleStatus()
{
unsigned char conf[8] = {
0,
0,
0,
0,
0,
0,
0,
0,
};
unsigned char _data[8] = {0x05, 0x80, 0, 0, 0, 0, 0, 0};
/*if(!connection->isWireless())
_data[1] = 0x11;*/
ssize_t r;
CHK(connection->open());
CHK(connection->setReport(0x0305, _data, 8));
CHK(connection->getReport(0x0305, (unsigned char *)conf, 8));
CHK(connection->close());
std::cout << "IDLE STATUS --------------------------" << std::endl;
for (int i = 0; i < 8; i++)
{
std::cout << std::hex << (int)conf[i] << "\t";
}
std::cout << "---------------" << std::endl;
return ssize_t(0);
return ssize_t();
}
ssize_t Conf::readConfigFromFile() ssize_t Conf::readConfigFromFile()
{ {
QFileDialog dialog(nullptr); QFileDialog dialog(nullptr);

View file

@ -12,9 +12,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "structs.h" #include "structs.h"
#include <libusb-1.0/libusb.h>
#include <unistd.h> #include <unistd.h>
#include "usb_thingy.h" #include "usb_thingy.h"
#include "a811.h"
#define CONF_FILE "conf.bin" #define CONF_FILE "conf.bin"
@ -42,6 +42,8 @@ public:
Q_INVOKABLE ssize_t readConfigFromFile(); Q_INVOKABLE ssize_t readConfigFromFile();
ssize_t readConfigFromFile(const char *filePath); ssize_t readConfigFromFile(const char *filePath);
ssize_t getIdleStatus();
// all the config should be in a single file // all the config should be in a single file
ssize_t writeConfigToFile(conf_1 *conf, const char *filePath); ssize_t writeConfigToFile(conf_1 *conf, const char *filePath);
ssize_t writeConfigToFile(conf_2 *conf, const char *filePath); ssize_t writeConfigToFile(conf_2 *conf, const char *filePath);
@ -76,8 +78,6 @@ private:
int m_lightMode; int m_lightMode;
conf_1 *m_conf1; conf_1 *m_conf1;
conf_2 *m_conf2; conf_2 *m_conf2;
libusb_device *m_device = NULL;
libusb_context *m_ctx = NULL;
QString m_fileName; QString m_fileName;
Connection *connection; Connection *connection;
}; };

242
src/le_buttons.cpp Normal file
View file

@ -0,0 +1,242 @@
#include <map>
#include <string>
#include <cstdint>
#include <array>
#include "a811.h"
std::map< int, std::string > A811::_buttonNames = {
{ 0, "button_left" },
{ 1, "button_right" },
{ 2, "button_middle" },
{ 3, "button_backward" },
{ 4, "button_forward" },
{ 5, "button_dpi_down" },
{ 6, "button_dpi_up" },
{ 7, "button_1" },
{ 8, "button_2" },
{ 9, "button_3" },
{ 10, "button_4" },
{ 11, "button_5" },
{ 12, "button_6" },
{ 13, "button_7" },
{ 14, "button_8" },
};
std::map<std::string, std::array<uint8_t, 4>> A811::_keycodes = {
{"left", {0x11, 0x01, 0x00, 0x00}},
{"right", {0x11, 0x02, 0x00, 0x00}},
{"middle", {0x11, 0x04, 0x00, 0x00}},
{"backward", {0x11, 0x08, 0x00, 0x00}},
{"forward", {0x11, 0x10, 0x00, 0x00}},
{"dpi-cycle", {0x41, 0x00, 0x00, 0x00}},
{"dpi-", {0x41, 0x02, 0x00, 0x00}},
{"dpi+", {0x41, 0x01, 0x00, 0x00}},
{"media_player", {0x22, 0x00, 0x01, 0x00}},
{"media_play_pause", {0x22, 0x08, 0x00, 0x00}},
{"media_stop", {0x22, 0x04, 0x00, 0x00}},
{"media_previous", {0x22, 0x02, 0x00, 0x00}},
{"media_next", {0x22, 0x01, 0x00, 0x00}},
{"media_volume_up", {0x22, 0x40, 0x00, 0x00}},
{"media_volume_down", {0x22, 0x80, 0x00, 0x00}},
{"email", {0x22, 0x00, 0x10, 0x00}},
{"calculator", {0x22, 0x00, 0x20, 0x00}},
{"explorer", {0x22, 0x00, 0x02, 0x00}},
{"homepage", {0x22, 0x00, 0x00, 0x02}},
{"search", {0x22, 0x00, 0x00, 0x01}},
{"m_forward", {0x22, 0x00, 0x00, 0x08}},
{"m_backward", {0x22, 0x00, 0x00, 0x04}},
{"stopweb", {0x22, 0x00, 0x00, 0x10}},
{"refresh", {0x22, 0x00, 0x00, 0x20}},
{"favorites", {0x22, 0x00, 0x00, 0x40}},
{"disable_key", {0x50, 0x01, 0x00, 0x01}},
{"toggle_rgb", {0x50, 0x02, 0x00, 0x00}},
{"threeclick", {0x31, 0x01, 0x32, 0x03}},
{"firekey", {0x31, 0x01, 0xff, 0x03}},
};
std::map<std::string, uint8_t> A811::_keyboardKeys = {
// top row
{"Esc", 0x29},
{"F1", 0x3a},
{"F2", 0x3b},
{"F3", 0x3c},
{"F4", 0x3d},
{"F5", 0x3e},
{"F6", 0x3f},
{"F7", 0x40},
{"F8", 0x41},
{"F9", 0x42},
{"F10", 0x43},
{"F11", 0x44},
{"F12", 0x45},
{"PrtSc", 0x46},
{"ScrLk", 0x47},
{"Pause", 0x48},
// alphanumeric
{"a", 0x04},
{"b", 0x05},
{"c", 0x06},
{"d", 0x07},
{"e", 0x08},
{"f", 0x09},
{"g", 0x0a},
{"h", 0x0b},
{"i", 0x0c},
{"j", 0x0d},
{"k", 0x0e},
{"l", 0x0f},
{"m", 0x10},
{"n", 0x11},
{"o", 0x12},
{"p", 0x13},
{"q", 0x14},
{"r", 0x15},
{"s", 0x16},
{"t", 0x17},
{"u", 0x18},
{"v", 0x19},
{"w", 0x1a},
{"x", 0x1b},
{"y", 0x1c},
{"z", 0x1d},
{"1", 0x1e},
{"2", 0x1f},
{"3", 0x20},
{"4", 0x21},
{"5", 0x22},
{"6", 0x23},
{"7", 0x24},
{"8", 0x25},
{"9", 0x26},
{"0", 0x27},
// modifiers
{"Tab", 0x2b},
{"Caps_Lock", 0x39},
{"Shift_l", 0xe1},
{"Ctrl_l", 0xe0},
{"Alt_l", 0xe2},
{"Super_l", 0xe3},
{"Super_r", 0xe7},
{"Alt_r", 0xe6},
{"Menu", 0x65},
{"Ctrl_r", 0xe4},
{"Shift_r", 0xe5},
{"Return", 0x28},
{"Backspace", 0x2a},
// special characters
{"Space", 0x2c},
{"Tilde", 0x35},
{"Minus", 0x2d},
{"Equals", 0x2e},
{"Bracket_l", 0x2f},
{"Bracket_r", 0x30},
{"Backslash", 0x31},
{"Hash", 0x32},
{"Semicolon", 0x33},
{"Apostrophe", 0x34},
{"Comma", 0x36},
{"Period", 0x37},
{"Slash", 0x38},
{"Int_Key", 0x64},
// navigation
{"Right", 0x4f},
{"Left", 0x50},
{"Down", 0x51},
{"Up", 0x52},
{"Insert", 0x49},
{"Home", 0x4a},
{"PgUp", 0x4b},
{"Delete", 0x4c},
{"End", 0x4d},
{"PgDown", 0x4e},
// numpad
{"Num_Slash", 0x54},
{"Num_Asterisk", 0x55},
{"Num_Minus", 0x56},
{"Num_Plus", 0x57},
{"Num_Return", 0x58},
{"Num_1", 0x59},
{"Num_2", 0x5a},
{"Num_3", 0x5b},
{"Num_4", 0x5c},
{"Num_5", 0x5d},
{"Num_6", 0x5e},
{"Num_7", 0x5f},
{"Num_8", 0x60},
{"Num_9", 0x61},
{"Num_0", 0x62},
{"Num_Period", 0x63},
{"Num_Lock", 0x53},
{"Num_Equals", 0x67},
{"Num_Comma", 0x85},
{"Num_Paren_l", 0xb6},
{"Num_Paren_r", 0xb7},
// special keys
{"Power", 0x66},
{"Lang1", 0x90},
{"Lang2", 0x91},
{"Lang3", 0x92},
{"Lang4", 0x93},
{"Lang5", 0x94},
{"Lang6", 0x95},
{"Lang7", 0x96},
{"Lang8", 0x97},
{"Lang9", 0x98},
{"F13", 0x68},
{"F14", 0x69},
{"F15", 0x6a},
{"F16", 0x6b},
{"F17", 0x6c},
{"F18", 0x6d},
{"F19", 0x6e},
{"F20", 0x6f},
{"F21", 0x70},
{"F22", 0x71},
{"F23", 0x72},
{"F24", 0x73},
{"Execute", 0x74},
{"Help", 0x75},
{"Props", 0x76},
{"Select", 0x77},
{"Stop", 0x78},
{"Again", 0x79},
{"Undo", 0x7a},
{"Cut", 0x7b},
{"Copy", 0x7c},
{"Paste", 0x7d},
{"Find", 0x7e},
{"Mute", 0x7f},
{"Volume_Up", 0x80},
{"Volume_Down", 0x81},
{"International1", 0x87},
{"International2", 0x88},
{"International3", 0x89},
{"International4", 0x8a},
{"International5", 0x8b},
{"International6", 0x8c},
{"International7", 0x8d},
{"International8", 0x8e},
{"International9", 0x8f},
// media keys
{"Media_Play_Pause", 0xe8},
{"Media_Stop_CD", 0xe9},
{"Media_Previous", 0xea},
{"Media_Next", 0xeb},
{"Media_Eject_CD", 0xec},
{"Media_Volume_Up", 0xed},
{"Media_Volume_Down", 0xee},
{"Media_Mute", 0xef},
{"Media_WWW", 0xf0},
{"Media_Back", 0xf1},
{"Media_Forward", 0xf2},
{"Media_Stop", 0xf3},
{"Media_Find", 0xf4},
{"Media_Scroll_Up", 0xf5},
{"Media_Scroll_Down", 0xf6},
{"Media_Edit", 0xf7},
{"Media_Sleep", 0xf8},
{"Media_Screenlock", 0xf9},
{"Media_Refresh", 0xfa},
{"Media_Calc", 0xfb},
};

View file

@ -16,7 +16,9 @@ struct conf_1
uint8_t dpi_modes; // 0x0b, 0x11-0x15 erste 4 welches ist aktiv? dann welhce für conf?? uint8_t dpi_modes; // 0x0b, 0x11-0x15 erste 4 welches ist aktiv? dann welhce für conf??
uint8_t __u4; // 0x0c zero uint8_t __u4; // 0x0c zero
uint8_t hdpi[10]; // 0x0 0x0d-0x16 jeweils 2 byte most significant byte last, * 50 -> annäherung an dpi -50 uint8_t hdpi[10]; // 0x0 0x0d-0x16 jeweils 2 byte most significant byte last, * 50 -> annäherung an dpi -50
uint8_t __u5[0x44 - 0x16]; // 0x17 - 0x44 ????? zeros uint8_t __uff[0x2c - 0x16]; // 22*something i fucking stayed up a night for
uint8_t col_dpi[15]; // 0x2d-0x3b Mouse wheel color for dpi modes 5 * RGB
uint8_t __u5[0x44 - 0x3b]; // 0x17 - 0x44 ????? zeros
uint8_t light_mode; // 0x45 Lighting Mode, 02 Steady, 01 Colorful Streaming, 03 Breathing uint8_t light_mode; // 0x45 Lighting Mode, 02 Steady, 01 Colorful Streaming, 03 Breathing
uint8_t col_brightness_speed; // 0x46 0-4 Brightness und 0-4 Speed bei colorful 0x(br)(sp) uint8_t col_brightness_speed; // 0x46 0-4 Brightness und 0-4 Speed bei colorful 0x(br)(sp)
uint8_t __u8; // 0x47 ??? uint8_t __u8; // 0x47 ???
@ -59,7 +61,8 @@ struct conf_2
uint8_t __u5[0x207 - 0x47]; // 0x48-0x58 ?? 0x58-end zeros uint8_t __u5[0x207 - 0x47]; // 0x48-0x58 ?? 0x58-end zeros
}; };
struct macro_event{ struct macro_event
{
uint8_t updown_plus_delay_upper; uint8_t updown_plus_delay_upper;
uint8_t delay_lower; uint8_t delay_lower;
uint8_t keycode; uint8_t keycode;
@ -67,7 +70,7 @@ struct macro_event{
struct macro struct macro
{ {
uint8_t set_report_req[3]; //wirte macro Set_report 0x08 0x30 0x02 uint8_t set_report_req[3]; // wirte macro Set_report 0x08 0x30 0x02
uint8_t __u1[5]; uint8_t __u1[5];
uint8_t macro_nr; uint8_t macro_nr;
uint8_t __u2; uint8_t __u2;
@ -82,4 +85,12 @@ struct conf_12
conf_2 c2; conf_2 c2;
}; };
struct battery_stat
{
uint8_t pref[2]; // 0x05, 0x90
uint8_t wired; // 0x10 -> wired, 0x11 -> wireless
uint8_t capacity; // if is 0x02 and wired is 0x10 then full and plugged, 0x01 plugged and loading
uint8_t __u1[4];
};
#endif #endif

View file

@ -39,6 +39,8 @@ ssize_t Connection::findDevice()
} }
} }
libusb_free_device_list(list, 1); libusb_free_device_list(list, 1);
if(!found_device) if(!found_device)
@ -87,7 +89,7 @@ ssize_t Connection::setReport(uint16_t wValue, unsigned char *send_data, uint16_
{ {
int r; int r;
if ((r = libusb_control_transfer(handle, 0x21, 0x09, wValue, 1, send_data, 8, 2000)) < 0) if ((r = libusb_control_transfer(handle, 0x21, 0x09, wValue, 1, send_data, wLength, 2000)) < 0)
return logError("ERROR: libusb_control_transfer: ", libusb_error_name(r), __FILE__, __LINE__, __func__); return logError("ERROR: libusb_control_transfer: ", libusb_error_name(r), __FILE__, __LINE__, __func__);
return ssize_t(0); return ssize_t(0);

BIN
testdpi Normal file

Binary file not shown.