1
0
Fork 0
forked from denis/a811

Compare commits

..

6 commits
main ... main

15 changed files with 1303 additions and 288 deletions

View file

@ -10,4 +10,18 @@ write a nixos module that also sets udev rules
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
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
if u bind media keys from _keyboardKeys in le_buttons.cpp its working dont know what the other keycodes are about maybe only specific for windows??

BIN
asd

Binary file not shown.

View file

@ -0,0 +1,48 @@
conf_12 check:
class datacheck:
type : (type?, [0,...,3], {2, 7, 19}, <x, >x)
length
funcptr
datachekc(type, typedef, length, ptr):
funcpotr = ptr
check(*data):
actdata = funcpotr(data)
switch(type):
case a: return actdata > typedef[0]
case b: return (actdata > typedef[0]) && (actdata < typedef[1])
map [pos] -> datacheck(0, [0,7], 16, (data) => return (data << 4) | (data >> 4))
map [pos+16] -> datacheck(0, [0,7], 16, (data) => return (data << 4) | (data >> 4))
map [pos] -> datacheck(1, [0], 8*16, (data) => uint8_t x = 0; for (int i = 0; i < 16; ++i) x | data[i]; return !x;)
func a(pos):
return map[pos]
pos not per byte but bit
a(pos).check
confch3ck():
isok = True
extralen = 0
chk;
for(int i = 0; i < (int)sizeof(conf_12) * 8;):
chk = map[i]
res = chk.check(&(((unsigned char *)conf_12)[i]))
i+=chk.length;
if not res:
isok = False
break;
if chk.type == set;
print("is fucked at byte x / bit y with length chk.length it is not part of set [chk.typedef]")

View file

@ -46,10 +46,11 @@ First Part
0x04-0x07 ??
0x08-0x09 0x64 0x17 Profil 1, 0x64 0x01 Profil 2 ?????
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 ?
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
0x46 0-4 Brightness und 0-4 Speed bei colorful 0x(br)(sp)
0x47 ?
@ -133,7 +134,7 @@ Tastenbelegung
ThreeClick -> 0x31 0x01 0x32 0x03, whatever this is?
RGB on/off -> 0x50 0x02 0x00 0x00 -> hat die letzten bytes mit 0 geschrieben
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
Media Player -> 0x22 0x00 0x01 0x00

Binary file not shown.

View file

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

535
src/a811.cpp Normal file
View file

@ -0,0 +1,535 @@
#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, int active)
{
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);
}
if (active > 5 || active < 1)
{
logError("ERROR: Invalid active dpi modes.", __FILE__, __LINE__, __func__);
return ssize_t(2);
}
// Calculate the DPI value according to the formula
uint16_t 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 = // number of active modes
(1 & 0x0f) << 4 | ((active & 0x0F));
_conf12->c1.hdpi[((uint8_t)mode - 1) * 2] = lsb;
_conf12->c1.hdpi[((uint8_t)mode - 1) * 2 + 1] = msb;
_conf12->c1.col_dpi[((uint8_t)mode - 1) * 3] = color[0];
_conf12->c1.col_dpi[((uint8_t)mode - 1) * 3 + 1] = color[1];
_conf12->c1.col_dpi[((uint8_t)mode - 1) * 3 + 2] = color[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);
}
// Assume lsb and msb are given or extracted from your configuration structure
uint8_t lsb = _conf12->c1.hdpi[((uint8_t)mode - 1) * 2];
uint8_t msb = _conf12->c1.hdpi[((uint8_t)mode - 1) * 2 + 1];
// Reconstruct the dpi_value
uint16_t dpi_value = msb << 8 | (lsb & 0xFF);
std::cout << std::hex << dpi_value << " : " << (int)lsb << " : " << (int)msb << std::endl;
// Reverse the formula to get the original dpi
uint16_t dpi = (dpi_value * 50) + 50;
return dpi;
}
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)
{
mahbytes[i] = ((unsigned char *)&arr)[i];
}
}
else if (id >= 7 && id < 15)
{
// 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.side[id - 7];
for (int i = 0; i < (int)sizeof(_conf12->c2.mouse_buttons[id]); ++i)
{
mahbytes[i] = ((unsigned char *)&arr)[i];
}
}
else
{
logError("ERROR: Invalid button id.", __FILE__, __LINE__, __func__);
return ssize_t(1);
}
return ssize_t(0);
}
ssize_t A811::setMacroButton(int id, uint8_t macro_id, uint8_t cycle_type, uint8_t 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 - 7], 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);
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::readMacrosFromDevice(int cnt)
{
if (cnt > 255)
{
std::cout << "No more than 255 macros on device" << std::endl;
return ssize_t(1);
}
_macros = (macro **)malloc(cnt * sizeof(macro *));
_connection->open();
_connection->keepConnection(true);
for (int i = 1; i <= cnt; i++)
{
// get macro
// ist das bissl kacke weil immer neuer handle und detach und attach hmm
_macros[i - 1] = (macro *)malloc(sizeof(macro));
readMacroFromDevice(_macros[i - 1], i);
}
_connection->keepConnection(false);
_connection->close();
// check if any macros are read or if any empty macros are read
// maybe just read all possible macros
// or this function is actually completely useless just keep track of the macros in the gui code
return ssize_t(0);
}
ssize_t A811::readMacroFromDevice(macro *_macro, int id)
{
if (id > (uint8_t)255)
{
std::cout << "No more than 255 macros on device" << std::endl;
return ssize_t(0);
}
memset(_macro, 0, 520 * sizeof(unsigned char));
unsigned char _data[8] = {0x05, 0x31, (uint8_t)id, 0, 0, 0, 0, 0};
ssize_t r;
CHK(_connection->open());
CHK(_connection->setReport(0x0305, (unsigned char *)_data, 8));
CHK(_connection->getReport(0x0308, (unsigned char *)_macro, 520));
CHK(_connection->close());
// check if empty macro, if valid macro
return ssize_t(0);
}
ssize_t A811::writeMacroToDevice(macro *p_macro)
{
// conf_1
p_macro->set_report_req[0] = 0x80;
p_macro->set_report_req[1] = 0x30;
p_macro->set_report_req[2] = 0x02;
ssize_t r;
CHK(_connection->open());
CHK(_connection->setReport(0x0308, (unsigned char *)p_macro, 520));
CHK(_connection->close());
// check if macro is valid
return ssize_t(0);
}
bool A811::isIdle()
{
unsigned char conf[8];
memset(conf, 0, 8);
unsigned char _data[8] = {0x05, 0x80, 0, 0, 0, 0, 0, 0};
ssize_t r;
CHK(_connection->open());
CHK(_connection->setReport(0x0305, _data, 8));
CHK(_connection->getReport(0x0305, (unsigned char *)conf, 8));
CHK(_connection->close());
if (conf[2] == 0x0 && conf[3] == 0x1)
return true;
else if (conf[2] == 0x1 && conf[3] == 0x1)
return false;
logError("ERROR: Reading idle status.", __FILE__, __LINE__, __func__);
return false;
}
ssize_t A811::restoreConfig()
{
unsigned char _data[8] = {0x05, 0x40, 0x01, 0, 0, 0, 0, 0};
ssize_t r;
CHK(_connection->open());
CHK(_connection->setReport(0x0305, (unsigned char *)_data, 8));
CHK(_connection->close());
return ssize_t(0);
}
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);
}

337
src/a811.h Normal file
View file

@ -0,0 +1,337 @@
#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
//-- maybe active should be optional
/**
* @brief Set the DPI for a specific DPI MODE.
*
* This function allows you to set a specific DPI and an associated color
* for the mouse wheel for a Specific DPI mode.
*
* @param mode The mode for which to set the DPI and color values.
* @param color RGB
* @param dpi DPI value 50-26000
* @param active 1-5 how many DPI_MODE should be active.
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t setDPI(DPI_MODE, unsigned char[3], int, int);
/**
* @brief Get the current DPI value for a DPI_MODE.
*
* This function retrieves the current light mode of the device.
*
* @return int The current DPI for DPI_MODE.
*/
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, uint8_t, uint8_t, uint8_t);
/**
* @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);
/**
* @brief Read macros from the mouse.
*
* Read a specific number of macros from the mouse.
*
* @param macros where the macros should be saved.
* @param cnt how many macros should be read.
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t readMacrosFromDevice(int);
/**
* @brief Read a single macro from the mouse.
*
* Read a specific macro from the mouse.
*
* @param macro where the macro should be saved.
* @param id id of the macro.
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t readMacroFromDevice(macro *, int);
/**
* @brief Write a single macro to the mouse.
*
* Read a specific macro from the mouse.
*
* @param macro the macro to be written.
*
* @return ssize_t Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t writeMacroToDevice(macro *);
/**
* @brief Get the idle status of the mouse.
*
* Get the idle status of the mouse.
*
* @return bool returns true if idle, false else
*/
// the error logging here is kinda weird
bool isIdle();
// should be writing a custom thingy so i know what the restored config looks like
/**
* @brief Apply standard config.
*
* Write a standard configuration to the mouse if something went wrong.
*
* @return Returns the status of the operation, where 0 indicates
* success and a negative value indicates failure.
*/
ssize_t restoreConfig();
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())
{
std::cerr << "ERROR: Device not found!";
std::cerr << "ERROR: Device not found!"
<< "\n";
return 1;
}

View file

@ -1,8 +1,8 @@
#include "conf.h"
#include <iostream>
#include <QDebug>
#include <qfiledialog.h>
#include <iostream>
#include <klocalizedstring.h>
#include <qfiledialog.h>
#define CHK(X) \
if ((r = (X)) != 0) \
@ -12,16 +12,20 @@ Conf::Conf(QObject *parent) : QObject(parent)
{
m_conf1 = (conf_1 *)malloc(sizeof(conf_1));
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_conf2, 0, sizeof(conf_2));
connection = &(Connection::getInstance());
connection->findDevice();
// read initial config from device
readConfigFromDevice(m_conf1);
readConfigFromDevice(m_conf2);
connection = &(Connection::getInstance());
if (connection->findDevice())
{
std::cerr << "ERROR: device not found" << std::endl;
exit(1);
}
m_mouse = new A811();
}
ssize_t Conf::appendMacroToFile(macro *macro, const char *filePath)
@ -76,7 +80,8 @@ ssize_t Conf::deleteMacroFromFile(macro *_macro, const char *filePath)
// Read each macro from the original file
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)
{
fwrite(&temp_macro, sizeof(macro), 1, tempfile);
@ -92,8 +97,9 @@ ssize_t Conf::deleteMacroFromFile(macro *_macro, const char *filePath)
fclose(tempfile);
// Replace the original file with the temp file
remove(filePath); // Delete the original file
rename("tempfile.bin", filePath); // Rename the temp file to the original file name
remove(filePath); // Delete the original file
rename("tempfile.bin",
filePath); // Rename the temp file to the original file name
return 0;
@ -102,59 +108,77 @@ ssize_t Conf::deleteMacroFromFile(macro *_macro, const char *filePath)
void Conf::testFunc()
{
macro **macros;
readMacrosFromDevice(macros, 4);
for (int i = 0; i < 4; i++)
m_mouse->readConfigFromDevice(CONF_TYPE::BATTERY);
m_mouse->readConfigFromDevice(CONF_TYPE::LIGHT);
m_mouse->readConfigFromDevice(CONF_TYPE::KEY);
m_mouse->setLightMode(LIGHT_MODE::BREATHING, 1, 4);
m_mouse->writeConfigToDevice(CONF_TYPE::LIGHT);
m_mouse->setUSBPollingRate(POLLING_RATE::P_1000);
std::cout << "UBS Polling rate: " << (int)m_mouse->getUSBPollingRate() << std::endl;
std::cout << "BATTERYSTATUS: " << (int)m_mouse->getBatteryStatus() << std::endl;
std::cout << "LIGHTMODE: " << (int)m_mouse->getLightMode() << std::endl;
m_mouse->setLightMode(LIGHT_MODE::COLORFUL_STREAMING, 1, 2);
m_mouse->writeConfigToDevice(CONF_TYPE::LIGHT);
sleep(2);
m_mouse->setMultimediaButton(2, "media_volume_up");
// does not work for some reason
m_mouse->setMultimediaButton(6, "dpi-cycle");
m_mouse->setButton(7, "Volume_Up", 0);
m_mouse->setButton(8, "b", 2);
m_mouse->setButton(9, "c", 4);
m_mouse->setButton(10, "d", 8);
m_mouse->setButton(11, "e", 3);
m_mouse->setButton(12, "f", 5);
m_mouse->setButton(13, "g", 7);
m_mouse->setButton(14, "h", 9);
// dont know if every keycode is working
int bid = 0;
std::cout << "Button " << bid << m_mouse->getButton(bid).name << std::endl;
m_mouse->writeConfigToDevice(CONF_TYPE::KEY);
std::cout << m_mouse->getButton(3).name << std::endl;
m_mouse->setLightMode(LIGHT_MODE::BREATHING, 4, 4);
unsigned char *cols;
cols = m_mouse->getLightModeColors(LIGHT_MODE::BREATHING);
for (int i = 0; i < 21; i++)
{
appendMacroToFile(macros[i], "macrofileappend");
std::cout << cols[i];
}
}
std::cout << std::endl;
m_mouse->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};
m_mouse->setLightModeColors(LIGHT_MODE::BREATHING, cols2);
unsigned char cols3[3] = {0xff, 0x00, 0x00};
m_mouse->setDPI(DPI_MODE::DPI_1, cols3, 800, 5);
cols3[0] = 0x0;
cols3[1] = 0xff;
m_mouse->setDPI(DPI_MODE::DPI_2, cols3, 1000, 5);
cols3[1] = 0x0;
cols3[2] = 0xff;
m_mouse->setDPI(DPI_MODE::DPI_3, cols3, 1200, 5);
cols3[0] = 0xff;
cols3[2] = 0xff;
m_mouse->setDPI(DPI_MODE::DPI_4, cols3, 1400, 5);
cols3[0] = 0xff;
cols3[1] = 0xff;
cols3[2] = 0xff;
m_mouse->setDPI(DPI_MODE::DPI_5, cols3, 1500, 5);
// m_mouse->writeConfigToDevice(CONF_TYPE::KEY);
std::cout << "DPI at this: " << m_mouse->getDPI(DPI_MODE::DPI_1) << std::endl;
int Conf::lightMode()
{
return m_conf1->light_mode;
}
std::cout << "Battery capacity:" << std::dec << m_mouse->getBatteryCapacity() << std::endl;
m_mouse->writeConfigToDevice(CONF_TYPE::LIGHT);
void Conf::setLightMode(int mode)
{
m_conf1->light_mode = (unsigned char)mode;
std::cout << (int)m_conf1->light_mode << std::endl;
Q_EMIT lightModeChanged();
}
ssize_t Conf::restoreConfigs()
{
unsigned char _data[8] = {0x05, 0x40, 0x01, 0, 0, 0, 0, 0};
ssize_t r;
CHK(connection->open());
CHK(connection->setReport(0x0305, (unsigned char *)_data, 8));
CHK(connection->close());
return 0;
}
ssize_t Conf::deviceConfig()
{
unsigned char _data[8] = {0x05, 0x22, 0, 0, 0, 0, 0, 0};
/*if(!connection->isWireless())
_data[1] = 0x12;*/
ssize_t r;
CHK(connection->open());
CHK(connection->setReport(0x0305, (unsigned char *)_data, 8));
CHK(connection->getReport(0x0308, (unsigned char *)0x0, 520));
CHK(connection->close());
return 0;
}
void Conf::setDeviceConfig(ssize_t stat)
{
std::cout << "Setting new conf" << std::endl;
writeConfigToDevice(m_conf1);
writeConfigToDevice(m_conf2);
Q_EMIT deviceConfigChanged();
m_mouse->readMacrosFromDevice(4);
}
ssize_t Conf::writeConfigToFile(const char *filePath)
@ -195,184 +219,6 @@ ssize_t Conf::writeConfigToFile(const char *filePath)
return 0;
}
ssize_t Conf::writeConfigToDevice(conf_2 *conf)
{
ssize_t r;
CHK(connection->open());
conf->req_type = 0x50;
CHK(connection->setReport(0x0308, (unsigned char *)conf, 520));
CHK(connection->close());
return 0;
}
ssize_t Conf::writeConfigToDevice(conf_1 *conf)
{
ssize_t r;
CHK(connection->open());
conf->req_type = 0x92;
CHK(connection->setReport(0x0308, (unsigned char *)conf, 520));
CHK(connection->close());
return 0;
}
ssize_t Conf::readConfigFromDevice(conf_2 *conf)
{
unsigned char _data[8] = {0x05, 0x22, 0, 0, 0, 0, 0, 0};
/*if(!connection->isWireless())
_data[1] = 0x12;*/
ssize_t r;
CHK(connection->open());
CHK(connection->setReport(0x0305, (unsigned char *)_data, 8));
CHK(connection->getReport(0x0308, (unsigned char *)conf, 520));
CHK(connection->close());
return 0;
}
ssize_t Conf::batteryStatus()
{
unsigned char dat[8];
memset(dat, 0, 8 * sizeof(unsigned char));
unsigned char _data[8] = {0x05, 0x90, 0, 0, 0, 0, 0, 0};
ssize_t r;
CHK(connection->open());
CHK(connection->setReport(0x0305, (unsigned char *)_data, 8));
CHK(connection->getReport(0x0305, (unsigned char *)dat, 8));
CHK(connection->close());
for (int i = 0; i < 16; i++)
{
std::cout << std::hex << (int)dat[i] << "\t";
}
std::cout << std::endl;
if (dat[2] == 0x10 && dat[3] == 0x01)
return -1;
return (int)dat[3];
}
void Conf::setBatteryStatus(ssize_t bat)
{
m_bat = batteryStatus();
Q_EMIT batteryStatusChanged();
}
ssize_t Conf::readMacroFromDevice(macro *_macro, int id)
{
if (id > 255)
{
std::cout << "No more than 255 macros on device" << std::endl;
return -1;
}
memset(_macro, 0, 520 * sizeof(unsigned char));
unsigned char _data[8] = {0x05, 0x31, id, 0, 0, 0, 0, 0};
ssize_t r;
CHK(connection->open());
CHK(connection->setReport(0x0305, (unsigned char *)_data, 8));
CHK(connection->getReport(0x0308, (unsigned char *)_macro, 520));
CHK(connection->close());
std::cout << std::hex << (int)_macro->macro_nr << "\t";
std::cout << std::endl;
return 0;
}
ssize_t Conf::writeMacroToDevice(macro *_macro)
{
// conf_1
_macro->set_report_req[0] = 0x80;
_macro->set_report_req[1] = 0x30;
_macro->set_report_req[2] = 0x02;
ssize_t r;
CHK(connection->open());
CHK(connection->setReport(0x0308, (unsigned char *)_macro, 520));
CHK(connection->close());
return 0;
}
ssize_t Conf::readMacrosFromDevice(macro **&macros, int cnt)
{
if (cnt > 255)
{
std::cout << "No more than 255 macros on device" << std::endl;
return -1;
}
macros = (macro **)malloc(cnt * sizeof(macro *));
connection->open();
connection->keepConnection(true);
for (int i = 1; i <= cnt; i++)
{
// get macro
// ist das bissl kacke weil immer neuer handle und detach und attach hmm
macros[i - 1] = (macro *)malloc(sizeof(macro));
readMacroFromDevice(macros[i - 1], i);
}
connection->keepConnection(false);
connection->close();
return 0;
}
ssize_t Conf::readAssignedMacrosFromDevice()
{
// check all the keys for macro mod
int macroCnt = 0;
for (int i = 0; i < 8; i++)
{
if (m_conf2->side[i].pref == 0x70 || (m_conf2->mouse_buttons[i].pref == 0x70 && i < 6))
macroCnt++;
}
std::cout << macroCnt << std::endl;
unsigned char conf[520];
memset(conf, 0, 520 * sizeof(unsigned char));
unsigned char _data[8] = {0x05, 0x31, 1, 0, 0, 0, 0, 0};
ssize_t r;
CHK(connection->open());
for (int i = 1; i <= macroCnt; i++)
{
_data[2] = i;
CHK(connection->setReport(0x0305, _data, 8));
CHK(connection->getReport(0x0308, (unsigned char *)conf, 520));
}
CHK(connection->close());
return 0;
}
ssize_t Conf::readConfigFromDevice(conf_1 *conf)
{
unsigned char _data[8] = {0x05, 0x21, 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(0x0308, (unsigned char *)conf, 520));
CHK(connection->close());
return ssize_t(0);
}
ssize_t Conf::writeConfigToFile()
{
QString path = QFileDialog::getSaveFileName(nullptr, i18n("Save File As"));
@ -416,16 +262,17 @@ ssize_t Conf::readConfigFromFile(const char *filePath, conf_1 *conf)
if (infile == NULL)
{
fprintf(stderr, "\nError opening file\n");
exit(1);
return ssize_t(1);
}
// reading to read_struct
fread(conf, sizeof(struct conf_1), 1, infile);
if (sizeof(struct conf_1) > fread(conf, sizeof(struct conf_1), 1, infile))
fprintf(stderr, "\nError file\n");
// close file
fclose(infile);
return 0;
return ssize_t(0);
}
ssize_t Conf::readConfigFromFile(const char *filePath, conf_2 *conf)
@ -437,16 +284,17 @@ ssize_t Conf::readConfigFromFile(const char *filePath, conf_2 *conf)
if (infile == NULL)
{
fprintf(stderr, "\nError opening file\n");
exit(1);
return ssize_t(1);
}
// reading to read_struct
fread(conf, sizeof(struct conf_2), 1, infile);
if (sizeof(struct conf_2) > fread(conf, sizeof(struct conf_2), 1, infile))
fprintf(stderr, "\nError file\n");
// close file
fclose(infile);
return 0;
return ssize_t(0);
}
ssize_t Conf::readConfigFromFile(const char *filePath)
@ -457,11 +305,12 @@ ssize_t Conf::readConfigFromFile(const char *filePath)
if (infile == NULL)
{
fprintf(stderr, "\nError opening file\n");
exit(1);
return ssize_t(1);
}
fread(m_conf1, sizeof(struct conf_1), 1, infile);
fread(m_conf2, sizeof(struct conf_2), 1, infile);
if (sizeof(struct conf_1) > fread(m_conf1, sizeof(struct conf_1), 1, infile) ||
sizeof(struct conf_2) > fread(m_conf2, sizeof(struct conf_2), 1, infile))
fprintf(stderr, "\nError file\n");
fclose(infile);
return 0;
@ -477,4 +326,4 @@ ssize_t Conf::readConfigFromFile()
readConfigFromFile(path.toUtf8().constData());
return 0;
}
}

View file

@ -12,30 +12,18 @@
#include <stdio.h>
#include <stdlib.h>
#include "structs.h"
#include <libusb-1.0/libusb.h>
#include <unistd.h>
#include "usb_thingy.h"
#include "a811.h"
#define CONF_FILE "conf.bin"
class Conf : public QObject
{
Q_OBJECT
Q_PROPERTY(ssize_t deviceConfig READ deviceConfig WRITE setDeviceConfig NOTIFY deviceConfigChanged)
Q_PROPERTY(int lightMode READ lightMode WRITE setLightMode NOTIFY lightModeChanged)
Q_PROPERTY(ssize_t batteryStatus READ batteryStatus WRITE setBatteryStatus NOTIFY batteryStatusChanged)
public:
explicit Conf(QObject *parent = nullptr);
ssize_t deviceConfig();
Q_INVOKABLE void setDeviceConfig(ssize_t stat);
Q_SIGNAL void deviceConfigChanged();
int lightMode();
Q_INVOKABLE void setLightMode(int mode);
Q_SIGNAL void lightModeChanged();
Q_INVOKABLE ssize_t restoreConfigs();
Q_INVOKABLE ssize_t writeConfigToFile();
ssize_t writeConfigToFile(const char *filePath);
@ -47,37 +35,22 @@ public:
ssize_t writeConfigToFile(conf_2 *conf, const char *filePath);
ssize_t readConfigFromFile(const char *filePath, conf_1 *conf);
ssize_t readConfigFromFile(const char *filePath, conf_2 *conf);
ssize_t writeConfigToDevice(conf_1 *conf);
ssize_t writeConfigToDevice(conf_2 *conf);
ssize_t readConfigFromDevice(conf_1 *conf);
ssize_t readConfigFromDevice(conf_2 *conf);
Q_INVOKABLE ssize_t readAssignedMacrosFromDevice();
Q_INVOKABLE ssize_t readMacrosFromDevice(macro **&macros, int cnt);
Q_INVOKABLE ssize_t readMacroFromDevice(macro *_macro, int id);
Q_INVOKABLE ssize_t writeMacroToDevice(macro *_macro);
Q_INVOKABLE ssize_t appendMacroToFile(macro *_macro, const char *filePath);
Q_INVOKABLE ssize_t deleteMacroFromFile(macro *_macro, const char *filePath);
ssize_t batteryStatus();
Q_INVOKABLE void setBatteryStatus(ssize_t bat);
Q_SIGNAL void batteryStatusChanged();
Q_INVOKABLE void testFunc();
Q_SIGNALS:
private:
macro **m_macros;
A811 *m_mouse;
ssize_t m_stat;
ssize_t m_bat;
int m_lightMode;
conf_1 *m_conf1;
conf_2 *m_conf2;
libusb_device *m_device = NULL;
libusb_context *m_ctx = NULL;
QString m_fileName;
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 __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 __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 col_brightness_speed; // 0x46 0-4 Brightness und 0-4 Speed bei colorful 0x(br)(sp)
uint8_t __u8; // 0x47 ???
@ -33,8 +35,8 @@ struct conf_1
struct key_conf
{
uint8_t pref;
uint8_t mod; // or macro id
uint8_t keycode; // for macro cycle type
uint8_t mod; // or macro id
uint8_t keycode; // for macro cycle type
uint8_t macro_cycle; // for macro cycle count
};
@ -59,7 +61,8 @@ struct conf_2
uint8_t __u5[0x207 - 0x47]; // 0x48-0x58 ?? 0x58-end zeros
};
struct macro_event{
struct macro_event
{
uint8_t updown_plus_delay_upper;
uint8_t delay_lower;
uint8_t keycode;
@ -67,7 +70,7 @@ struct macro_event{
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 macro_nr;
uint8_t __u2;
@ -82,4 +85,12 @@ struct conf_12
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

View file

@ -39,6 +39,8 @@ ssize_t Connection::findDevice()
}
}
libusb_free_device_list(list, 1);
if(!found_device)
@ -87,7 +89,7 @@ ssize_t Connection::setReport(uint16_t wValue, unsigned char *send_data, uint16_
{
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 ssize_t(0);

BIN
testdpi Normal file

Binary file not shown.