[new device] a very well tested addition for the Lenovo Legion 7, with a framework for adding more Lenovo Devices

This commit is contained in:
Cooper Hall 2022-06-03 23:02:15 +00:00 committed by Adam Honse
parent e8e24ac243
commit 15be3f6336
7 changed files with 1053 additions and 0 deletions

View file

@ -0,0 +1,464 @@
/*-------------------------------------------------------------------*\
| LenovoDevices.h |
| |
| Describes zones for various Lenovo Legion Devices |
| |
| Cooper Hall (geobot19) 17 Apr 2022 |
| |
| Note: additions here must be adeed to RGBController_LenovoUSB.cpp in|
| the switch statements which are on lines 28 and 60 at time of |
| writing |
\*-------------------------------------------------------------------*/
#include <string>
#include "RGBControllerKeyNames.h"
#include "RGBController.h"
#ifndef LENOVODEVICES_H
#define LENOVODEVICES_H
/*-----------------------------------------------------*\
| Keyboard product IDs |
\*-----------------------------------------------------*/
#define LEGION_7_6_PID_1 0xC968
#define LEGION_7_6_PID_2 0xC957
#define LEGION_7_6_PID_3 0xC956
struct lenovo_led
{
uint8_t zone_num;
uint8_t led_num;
std::string name;
};
/*---------*\
| LED MAPS |
\*---------*/
const lenovo_led legion_7_g_6_ansi_leds[]
{
/*----------------*\
| zone 1, keyboard |
\*----------------*/
//row 1
{1, 0x01, KEY_EN_ESCAPE},//0
{1, 0x02, KEY_EN_F1},//1
{1, 0x03, KEY_EN_F2},//2
{1, 0x04, KEY_EN_F3},//3
{1, 0x05, KEY_EN_F4},//4
{1, 0x06, KEY_EN_F5},//5
{1, 0x07, KEY_EN_F6},//6
{1, 0x08, KEY_EN_F7},//7
{1, 0x09, KEY_EN_F8},//8
{1, 0x0A, KEY_EN_F9},//9
{1, 0x0B, KEY_EN_F10},//10
{1, 0x0C, KEY_EN_F11},//11
{1, 0x0D, KEY_EN_F12},//12
{1, 0x0E, KEY_EN_INSERT},//13
{1, 0x0F, KEY_EN_PRINT_SCREEN},//14
{1, 0x10, KEY_EN_DELETE},//15
{1, 0x11, KEY_EN_HOME},//16
{1, 0x12, KEY_EN_END},//17
{1, 0x13, KEY_EN_PAGE_UP},//18
{1, 0x14, KEY_EN_PAGE_DOWN},//19
//row 2
{1, 0x16, "Key: ~"},//20
{1, 0x17, "Key: !"},//21
{1, 0x18, "Key: @"},//22
{1, 0x19, "Key: #"},//23
{1, 0x1A, "Key: $"},//24
{1, 0x1B, "Key: %"},//25
{1, 0x1C, "Key: ^"},//26
{1, 0x1D, "Key: &"},//27
{1, 0x1E, "Key: *"},//28
{1, 0x1F, "Key: ("},//29
{1, 0x20, "Key: )"},//30
{1, 0x21, "Key: _"},//31
{1, 0x22, "Key: +"},//32
{1, 0x26, KEY_EN_NUMPAD_LOCK},//33
{1, 0x27, KEY_EN_NUMPAD_DIVIDE},//34
{1, 0x28, KEY_EN_NUMPAD_TIMES},//35
{1, 0x29, KEY_EN_NUMPAD_MINUS},//36
//row 3
{1, 0x2B, KEY_EN_BACK_TICK},//37
{1, 0x2C, KEY_EN_1},//38
{1, 0x2D, KEY_EN_2},//39
{1, 0x2E, KEY_EN_3},//40
{1, 0x2F, KEY_EN_4},//41
{1, 0x30, KEY_EN_5},//42
{1, 0x31, KEY_EN_6},//43
{1, 0x32, KEY_EN_7},//44
{1, 0x33, KEY_EN_8},//45
{1, 0x34, KEY_EN_9},//46
{1, 0x35, KEY_EN_0},//47
{1, 0x36, KEY_EN_MINUS},//48
{1, 0x37, KEY_EN_EQUALS},//49
{1, 0x38, KEY_EN_BACKSPACE},//50
{1, 0x39, KEY_EN_BACKSPACE},//51
{1, 0x3A, KEY_EN_BACKSPACE},//52
{1, 0x3B, KEY_EN_NUMPAD_LOCK},//53
//row 4
{1, 0x40, KEY_EN_TAB},//54
{1, 0x42, KEY_EN_Q},//55
{1, 0x43, KEY_EN_W},//56
{1, 0x44, KEY_EN_E},//57
{1, 0x45, KEY_EN_R},//58
{1, 0x46, KEY_EN_T},//59
{1, 0x47, KEY_EN_Y},//60
{1, 0x48, KEY_EN_U},//61
{1, 0x49, KEY_EN_I},//62
{1, 0x4A, KEY_EN_O},//63
{1, 0x4B, KEY_EN_P},//64
{1, 0x4C, "Key: {"},//65
{1, 0x4D, "Key: }"},//66
{1, 0x4E, "Key: |"},//67
{1, 0x4F, KEY_EN_NUMPAD_7},//68
{1, 0x50, KEY_EN_NUMPAD_8},//69
{1, 0x51, KEY_EN_NUMPAD_9},//70
{1, 0x67, KEY_EN_NUMPAD_PLUS},//71
//row 5
{1, 0x55, KEY_EN_CAPS_LOCK},//72
{1, 0x56, KEY_EN_CAPS_LOCK},//73
{1, 0x57, KEY_EN_CAPS_LOCK},//74
{1, 0x6D, KEY_EN_A},//75
{1, 0x6E, KEY_EN_S},//76
{1, 0x58, KEY_EN_D},//77
{1, 0x59, KEY_EN_F},//78
{1, 0x5A, KEY_EN_G},//79
{1, 0x71, KEY_EN_H},//80
{1, 0x72, KEY_EN_J},//81
{1, 0x5B, KEY_EN_K},//82
{1, 0x5C, KEY_EN_L},//83
{1, 0x5D, "Key: :"},//84
{1, 0x5E, KEY_EN_SEMICOLON},//85
{1, 0x5F, "Key: \""},//86
{1, 0x60, KEY_EN_QUOTE},//87
{1, 0x77, KEY_EN_ANSI_ENTER},//88
{1, 0x78, KEY_EN_ANSI_ENTER},//89
{1, 0x61, KEY_EN_LEFT_BRACKET},//90
{1, 0x62, KEY_EN_RIGHT_BRACKET},//91
{1, 0x63, KEY_EN_ANSI_BACK_SLASH},//92
{1, 0x64, "Key: Numpad Home"},//93
{1, 0x65, "Key: Numpad Up Arrow"},//94
{1, 0x66, "Key: Numpad PgUP"},//95
{1, 0x68, KEY_EN_NUMPAD_PLUS},//96
//row 6
{1, 0x6A, KEY_EN_LEFT_SHIFT},//97
{1, 0x6B, KEY_EN_LEFT_SHIFT},//98
{1, 0x82, KEY_EN_Z},//99
{1, 0x83, KEY_EN_X},//100
{1, 0x6F, KEY_EN_C},//101
{1, 0x70, KEY_EN_V},//102
{1, 0x87, KEY_EN_B},//103
{1, 0x88, KEY_EN_N},//104
{1, 0x73, KEY_EN_M},//105
{1, 0x74, "Key: <"},//106
{1, 0x75, "Key: >"},//107
{1, 0x76, "Key: ?"},//108
{1, 0x8D, KEY_EN_RIGHT_SHIFT},//109
{1, 0xa2, KEY_EN_RIGHT_SHIFT},//110
{1, 0x79, KEY_EN_NUMPAD_4},//111
{1, 0x7A, "Key: Numpad Right Arrow"},//112
{1, 0x7B, KEY_EN_NUMPAD_5},//113
{1, 0x7C, KEY_EN_NUMPAD_6},//114
{1, 0x7D, "Key: Numpad Left Arrow"},//115
//row 7
{1, 0x89, KEY_EN_COMMA},//116
{1, 0x8A, KEY_EN_PERIOD},//117
{1, 0x8B, KEY_EN_FORWARD_SLASH},//118
{1, 0x8E, KEY_EN_NUMPAD_1},//119
{1, 0x8F, "Key: Numpad End"},//120
{1, 0x90, KEY_EN_NUMPAD_2},//121
{1, 0x91, "Key: Numpad Down Arrow"},//122
{1, 0x92, KEY_EN_NUMPAD_3},//123
{1, 0x93, "Key: Numpad PgDn"},//124
{1, 0xa7, KEY_EN_NUMPAD_ENTER},//125
//row 8
{1, 0x7F, KEY_EN_LEFT_CONTROL},//126
{1, 0x80, KEY_EN_LEFT_FUNCTION},//127
{1, 0x96, KEY_EN_LEFT_WINDOWS},//128
{1, 0x97, KEY_EN_LEFT_ALT},//129
{1, 0x98, KEY_EN_SPACE},//130
{1, 0x99, KEY_EN_SPACE},//131
{1, 0x9A, KEY_EN_RIGHT_ALT},//132
{1, 0x9B, KEY_EN_RIGHT_CONTROL},//133
{1, 0x9C, KEY_EN_LEFT_ARROW},//134
{1, 0x9D, KEY_EN_UP_ARROW},//135
{1, 0x9E, "Key: Up Brightness"},//136
{1, 0x9F, KEY_EN_DOWN_ARROW},//137
{1, 0xA0, "Key: Down Brightness"},//138
{1, 0xA1, KEY_EN_RIGHT_ARROW},//139
{1, 0xA3, KEY_EN_NUMPAD_0},//140
{1, 0xA4, "Key: Numpad Insert"},//141
{1, 0xA5, KEY_EN_NUMPAD_PERIOD},//142
{1, 0xA6, "Key: Numpad Delete"},//143
{1, 0xA8, KEY_EN_NUMPAD_ENTER},//144
//ISO
{1, 0x6C, "Key: | (ISO)"},//145
{1, 0x81, KEY_EN_ISO_BACK_SLASH},//146
/*----------------*\
| zone 2, logo |
\*----------------*/
{2, 0x01, "Logo Bottom Left"},//147
{2, 0x02, "Logo LED 2"},
{2, 0x03, "Logo LED 3"},
{2, 0x04, "Logo LED 4"},
{2, 0x05, "Logo LED Top Left"},
{2, 0x06, "Logo LED 6"},
{2, 0x07, "Logo LED 7"},
{2, 0x08, "Logo LED 8"},
{2, 0x09, "Logo LED Top Right"},
{2, 0x0A, "Logo LED 10"},
{2, 0x0B, "Logo LED 11"},
{2, 0x0C, "Logo LED 12"},
{2, 0x0D, "Logo Bottom Right"},//159
/*----------------*\
| zone 3, vents |
\*----------------*/
//left
{3, 0x01, "Left Vent Front"},//160
{3, 0x02, "Left Vent LED 2"},
{3, 0x03, "Left Vent LED 3"},
{3, 0x04, "Left Vent LED 4"},
{3, 0x05, "Left Vent LED 5"},
{3, 0x06, "Left Vent LED 6"},
{3, 0x07, "Left Vent LED 7"},
{3, 0x08, "Left Vent LED 8"},
{3, 0x09, "Left Vent LED 9"},
{3, 0x0A, "Left Vent LED 10"},
{3, 0x0B, "Left Vent LED 11"},
{3, 0x0C, "Left Vent LED 12"},
{3, 0x0D, "Left Vent LED 13"},
{3, 0x0E, "Left Vent LED 14"},
{3, 0x0F, "Left Vent LED 15"},
{3, 0x10, "Left Vent LED 16"},
{3, 0x11, "Left Vent LED 17"},
{3, 0x12, "Left Vent LED 18"},
{3, 0x13, "Left Vent LED 19"},
{3, 0x14, "Left Vent LED 20"},
{3, 0x15, "Left Vent LED 21"},
{3, 0x16, "Left Vent LED 22"},
{3, 0x17, "Left Vent LED 23"},
{3, 0x18, "Left Vent LED 24"},
{3, 0x19, "Left Vent LED 25"},
{3, 0x1A, "Left Vent LED 26"},
{3, 0x1B, "Left Vent Back"},//186
//right
{3, 0x1C, "Right Vent Front"},//187
{3, 0x1D, "Right Vent LED 2"},
{3, 0x1E, "Right Vent LED 3"},
{3, 0x1F, "Right Vent LED 4"},
{3, 0x20, "Right Vent LED 5"},
{3, 0x21, "Right Vent LED 6"},
{3, 0x22, "Right Vent LED 7"},
{3, 0x23, "Right Vent LED 8"},
{3, 0x24, "Right Vent LED 9"},
{3, 0x25, "Right Vent LED 10"},
{3, 0x26, "Right Vent LED 11"},
{3, 0x27, "Right Vent LED 12"},
{3, 0x28, "Right Vent LED 13"},
{3, 0x29, "Right Vent LED 14"},
{3, 0x2A, "Right Vent LED 15"},
{3, 0x2B, "Right Vent LED 16"},
{3, 0x2C, "Right Vent LED 17"},
{3, 0x2D, "Right Vent LED 18"},
{3, 0x2E, "Right Vent LED 19"},
{3, 0x2F, "Right Vent LED 20"},
{3, 0x30, "Right Vent LED 21"},
{3, 0x31, "Right Vent LED 22"},
{3, 0x32, "Right Vent LED 23"},
{3, 0x33, "Right Vent LED 24"},
{3, 0x34, "Right Vent LED 25"},
{3, 0x35, "Right Vent LED 26"},
{3, 0x36, "Right Vent Back"},//213
//back right vent
{3, 0x37, "Back Right Vent Left"},//214
{3, 0x38, "Back Right Vent 2"},
{3, 0x39, "Back Right Vent 3"},
{3, 0x3A, "Back Right Vent 4"},
{3, 0x3B, "Back Right Vent 5"},
{3, 0x3C, "Back Right Vent 6"},
{3, 0x3D, "Back Right Vent 7"},
{3, 0x3E, "Back Right Vent 8"},
{3, 0x3F, "Back Right Vent 10"},
{3, 0x40, "Back Right Vent 11"},
{3, 0x41, "Back Right Vent 12"},
{3, 0x42, "Back Right Vent 13"},
{3, 0x43, "Back Right Vent 14"},
{3, 0x44, "Back Right Vent 15"},
{3, 0x45, "Back Right Vent 16"},
{3, 0x46, "Back Right Vent 17"},
{3, 0x47, "Back Right Vent 18"},
{3, 0x48, "Back Right Vent 19"},
{3, 0x49, "Back Right Vent 20"},
{3, 0x4A, "Back Right Vent 21"},
{3, 0x4B, "Back Right Vent 22"},
{3, 0x4C, "Back Right Vent 23"},
{3, 0x4D, "Back Right Vent 24"},
{3, 0x4E, "Back Right Vent 25"},
{3, 0x4F, "Back Right Vent 26"},
{3, 0x50, "Back Right Vent Right"},//239
//back left vent
{3, 0x51, "Back Left Vent Right"},//240
{3, 0x52, "Back Left Vent 2"},
{3, 0x53, "Back Left Vent 3"},
{3, 0x54, "Back Left Vent 4"},
{3, 0x55, "Back Left Vent 5"},
{3, 0x56, "Back Left Vent 6"},
{3, 0x57, "Back Left Vent 7"},
{3, 0x58, "Back Left Vent 8"},
{3, 0x59, "Back Left Vent 10"},
{3, 0x5A, "Back Left Vent 11"},
{3, 0x5B, "Back Left Vent 12"},
{3, 0x5C, "Back Left Vent 13"},
{3, 0x5D, "Back Left Vent 14"},
{3, 0x5E, "Back Left Vent 15"},
{3, 0x5F, "Back Left Vent 16"},
{3, 0x60, "Back Left Vent 17"},
{3, 0x61, "Back Left Vent 18"},
{3, 0x62, "Back Left Vent 19"},
{3, 0x63, "Back Left Vent 20"},
{3, 0x64, "Back Left Vent 21"},
{3, 0x65, "Back Left Vent 22"},
{3, 0x66, "Back Left Vent 23"},
{3, 0x67, "Back Left Vent 24"},
{3, 0x68, "Back Left Vent 25"},
{3, 0x69, "Back Left Vent 26"},
{3, 0x6A, "Back Left Vent Left"},//265
/*-----------------*\
| zone 4, neon |
\*-----------------*/
//left side
{4, 0x01, "Neon LED 1 Top Left"},//266
{4, 0x02, "Neon LED 2"},
{4, 0x03, "Neon LED 3"},
{4, 0x04, "Neon LED 4"},
{4, 0x05, "Neon LED 5"},
{4, 0x06, "Neon LED 6"},
{4, 0x07, "Neon LED 7"},
{4, 0x08, "Neon LED 8"},
{4, 0x09, "Neon LED 9"},
{4, 0x0A, "Neon LED 10"},
{4, 0x0B, "Neon LED 11"},
{4, 0x0C, "Neon LED 12"},
{4, 0x0D, "Neon LED 13"},
{4, 0x0E, "Neon LED 14"},
{4, 0x0F, "Neon LED 15"},
{4, 0x10, "Neon LED 16"},
{4, 0x11, "Neon LED 17"},
{4, 0x12, "Neon LED 18"},
{4, 0x13, "Neon LED 19"},
{4, 0x14, "Neon LED 20"},
{4, 0x15, "Neon LED 21 Left Corner"},//286
//front
{4, 0x16, "Neon LED 22 Left Corner"},//287
{4, 0x17, "Neon LED 23"},
{4, 0x18, "Neon LED 24"},
{4, 0x19, "Neon LED 25"},
{4, 0x1A, "Neon LED 26"},
{4, 0x1B, "Neon LED 27"},
{4, 0x1C, "Neon LED 28"},
{4, 0x1D, "Neon LED 29"},
{4, 0x1E, "Neon LED 30"},
{4, 0x1F, "Neon LED 31"},
{4, 0x20, "Neon LED 32"},
{4, 0x21, "Neon LED 33"},
{4, 0x22, "Neon LED 34"},
{4, 0x23, "Neon LED 35"},
{4, 0x24, "Neon LED 36"},
{4, 0x25, "Neon LED 37"},
{4, 0x26, "Neon LED 38"},
{4, 0x27, "Neon LED 39"},
{4, 0x28, "Neon LED 40"},
{4, 0x29, "Neon LED 41"},
{4, 0x2A, "Neon LED 42"},
{4, 0x2B, "Neon LED 43"},
{4, 0x2C, "Neon LED 44"},
{4, 0x2D, "Neon LED 45"},
{4, 0x2E, "Neon LED 46"},
{4, 0x2F, "Neon LED 47"},
{4, 0x30, "Neon LED 48"},
{4, 0x31, "Neon LED 49"},
{4, 0x32, "Neon LED 50"},
{4, 0x33, "Neon LED 51"},
{4, 0x34, "Neon LED 52"},
{4, 0x35, "Neon LED 53"},
{4, 0x36, "Neon LED 54"},
{4, 0x37, "Neon LED 55"},
{4, 0x38, "Neon LED 56"},
{4, 0x39, "Neon LED 57"},
{4, 0x3A, "Neon LED 58"},
{4, 0x3B, "Neon LED 59"},
{4, 0x3C, "Neon LED 60"},
{4, 0x3D, "Neon LED 61"},
{4, 0x3E, "Neon LED 62"},
{4, 0x3F, "Neon LED 63"},
{4, 0x40, "Neon LED 64"},
{4, 0x41, "Neon LED 65"},
{4, 0x42, "Neon LED 66"},
{4, 0x43, "Neon LED 67"},
{4, 0x44, "Neon LED 68"},
{4, 0x45, "Neon LED 69"},
{4, 0x46, "Neon LED 70"},
{4, 0x47, "Neon LED 71"},
{4, 0x48, "Neon LED 72"},
{4, 0x49, "Neon LED 73"},
{4, 0x4A, "Neon LED 74"},
{4, 0x4B, "Neon LED 75"},
{4, 0x4C, "Neon LED 76"},
{4, 0x4D, "Neon LED 77"},
{4, 0x4E, "Neon LED 78 Right Corner"},//343
//right side
{4, 0x4F, "Neon LED 79 Right Corner"},//344
{4, 0x50, "Neon LED 80"},
{4, 0x51, "Neon LED 81"},
{4, 0x52, "Neon LED 82"},
{4, 0x53, "Neon LED 83"},
{4, 0x54, "Neon LED 84"},
{4, 0x55, "Neon LED 85"},
{4, 0x56, "Neon LED 86"},
{4, 0x57, "Neon LED 87"},
{4, 0x58, "Neon LED 88"},
{4, 0x59, "Neon LED 89"},
{4, 0x5A, "Neon LED 90"},
{4, 0x5B, "Neon LED 91"},
{4, 0x5C, "Neon LED 92"},
{4, 0x5D, "Neon LED 93"},
{4, 0x5E, "Neon LED 94"},
{4, 0x5F, "Neon LED 95"},
{4, 0x60, "Neon LED 96"},
{4, 0x61, "Neon LED 97"},
{4, 0x62, "Neon LED 98"},
{4, 0x63, "Neon LED 99 Top Right"},//364
};
/*-------------------*\
| Zone Definitions |
\*-------------------*/
struct lenovo_zone
{
std::string name;
zone_type type;
unsigned int height;
unsigned int width;
unsigned int start; //index to start reading the list of leds
unsigned int end; //end index
};
#endif

View file

@ -0,0 +1,118 @@
/*-------------------------------------------------------------------*\
| LenovoUSBController.cpp |
| |
| Driver for various Lenovo Devices |
| |
| Cooper Hall (geobot19) 17 Apr 2022 |
| |
\*-------------------------------------------------------------------*/
#include "LenovoUSBController.h"
#include "LogManager.h"
using namespace std;
LenovoUSBController::LenovoUSBController(hid_device* dev_handle, const char* path, uint16_t in_pid)
{
const uint8_t sz = HID_MAX_STR;
wchar_t tmp[sz];
dev = dev_handle;
location = path;
pid = in_pid;
hid_get_manufacturer_string(dev, tmp, sz);
std::wstring w_tmp = wstring(tmp);
name = string(w_tmp.begin(), w_tmp.end());
hid_get_product_string(dev, tmp, sz);
w_tmp = wstring(tmp);
name.append(" ").append(string(w_tmp.begin(), w_tmp.end()));
setDeviceSoftwareMode();
}
LenovoUSBController::~LenovoUSBController()
{
hid_close(dev);
}
uint16_t LenovoUSBController::getPid()
{
return pid;
}
string LenovoUSBController::getName()
{
return name;
}
string LenovoUSBController::getLocation()
{
return location;
}
void LenovoUSBController::setZoneLeds(uint8_t zone_num, vector<pair<uint8_t, RGBColor>> &led_colors)
{
for(size_t curr = 0; curr < led_colors.size();)
{
uint8_t buffer[LENOVO_HID_PACKET_SIZE] = {LENOVO_INSTRUCTION_START, LENOVO_ZONE_ID_0+zone_num, 0, 0};
/*---------------------------------------------------------*\
| Set the colour bytes in the packet |
| buffer[2] is required to know the amount of leds in packet|
| so it is set here as well |
\*---------------------------------------------------------*/
for(; buffer[2] < LENOVO_MAX_LEDS_PER_PACKET && curr < led_colors.size(); ++buffer[2])
{
uint8_t offset = (buffer[2] * 4) + 4;
/*------------------*\
|write the led number|
\*------------------*/
buffer[offset] = led_colors[curr].first;
/*--------------*\
|write the colors|
\*--------------*/
buffer[offset + 1] = RGBGetRValue(led_colors[curr].second);
buffer[offset + 2] = RGBGetGValue(led_colors[curr].second);
buffer[offset + 3] = RGBGetBValue(led_colors[curr].second);
++curr;
}
hid_send_feature_report(dev, buffer, LENOVO_HID_PACKET_SIZE);
}
}
void LenovoUSBController::setSingleLED(uint8_t zone_num, uint8_t led_num, RGBColor color)
{
uint8_t buffer[LENOVO_HID_PACKET_SIZE] = {LENOVO_INSTRUCTION_START, LENOVO_ZONE_ID_0+zone_num, 1, 0, led_num, RGBGetRValue(color), RGBGetGValue(color), RGBGetBValue(color)};
hid_send_feature_report(dev, buffer, LENOVO_HID_PACKET_SIZE);
}
void LenovoUSBController::sendBasicInstruction(uint8_t instruction)
{
uint8_t buffer[LENOVO_HID_PACKET_SIZE] = {LENOVO_INSTRUCTION_START, instruction};
hid_send_feature_report(dev, buffer, LENOVO_HID_PACKET_SIZE);
}
void LenovoUSBController::setDeviceSoftwareMode()
{
/*---------------------------------------*\
| this is required for the device listen |
| to the software protocol |
\*---------------------------------------*/
sendBasicInstruction(0xB2);
}
void LenovoUSBController::setDeviceHardwareMode()
{
/*---------------------------------------*\
|releases the device from sofware mode so |
|that onboard controlls can be used |
|this has not been shown to happen between|
|reboots |
\*---------------------------------------*/
sendBasicInstruction(0xB1);
}

View file

@ -0,0 +1,67 @@
/*-------------------------------------------------------------------*\
| LenovoUSBController.h |
| |
| Driver for various Lenovo Devices |
| |
| Cooper Hall (geobot19) 17 Apr 2022 |
| |
\*-------------------------------------------------------------------*/
#include "RGBController.h"
#include "LogManager.h"
#include <string>
#include <array>
#include <vector>
#include <utility>
#include <hidapi/hidapi.h>
#ifndef HID_MAX_STR
#define HID_MAX_STR 255
#endif
#ifndef LENOVOUSBCONTROLLER_H
#define LENOVOUSBCONTROLLER_H
#define LENOVO_INSTRUCTION_START 0x07
#define LENOVO_ZONE_ID_0 0xA0
#define LENOVO_HID_PACKET_SIZE 192
#define LENOVO_MAX_LEDS_PER_PACKET 0x2F
class LenovoUSBController
{
public:
/*--------------*\
|ctor(s) and dtor|
\*--------------*/
LenovoUSBController(hid_device* dev_handle, const char* path, uint16_t in_pid);
~LenovoUSBController();
/*--------------*\
|device functions|
\*--------------*/
void setZoneLeds(uint8_t zone_num, std::vector<std::pair<uint8_t, RGBColor>> &led_colors);
void setSingleLED(uint8_t zone_num, uint8_t led_num, RGBColor color);
uint16_t getPid();
std::string getName();
std::string getLocation();
void setDeviceSoftwareMode();
void setDeviceHardwareMode();
private:
/*--------------*\
|data members |
\*--------------*/
std::string name;
hid_device *dev;
std::string location;
uint16_t pid;
/*--------------*\
|device functions|
\*--------------*/
void sendBasicInstruction(uint8_t instruction);
};
#endif

View file

@ -0,0 +1,50 @@
/*-------------------------------------------------------------------*\
| LenovoUSBDetect.h |
| |
| Describes zones for various Lenovo Legion Devices |
| |
| Cooper Hall (geobot19) 17 Apr 2022 |
| |
\*-------------------------------------------------------------------*/
#include "Detector.h"
#include "LogManager.h"
#include "RGBController.h"
#include "LenovoUSBController.h"
#include "LenovoDevices.h"
#include "RGBController_LenovoUSB.h"
#include <hidapi/hidapi.h>
/*-----------------------------------------------------*\
| vendor IDs |
\*-----------------------------------------------------*/
#define ITE_VID 0x048D
/*-----------------------------------------------------*\
| Interface, Usage, and Usage Page |
\*-----------------------------------------------------*/
enum
{
LENOVO_PAGE = 0xFF89,
LENOVO_USEAGE = 0x07
};
void DetectLenovoLegionUSBControllers(hid_device_info* info, const std::string& name)
{
static const char* controller_name = "Lenovo Legion Laptop";
hid_device* dev = hid_open_path(info->path);
if(dev)
{
LenovoUSBController* controller = new LenovoUSBController(dev, info->path, info->product_id);
RGBController_LenovoUSB* rgb_controller = new RGBController_LenovoUSB(controller);
rgb_controller->name = name;
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 gen 6", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_7_6_PID_1, LENOVO_PAGE, LENOVO_USEAGE);
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 gen 6", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_7_6_PID_2, LENOVO_PAGE, LENOVO_USEAGE);
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 gen 6", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_7_6_PID_3, LENOVO_PAGE, LENOVO_USEAGE);

View file

@ -0,0 +1,303 @@
#include "LenovoDevices.h"
#include "RGBController_LenovoUSB.h"
#include <vector>
#include <string>
#include <utility>
using namespace std;
/*--------------------------------------------------------------------------------------*\
|note: the RGBController_LenovoUSB constructor determines which list of leds to pull from|
\*--------------------------------------------------------------------------------------*/
/**------------------------------------------------------------------*\
@name Lenovo USB
@category Keyboard
@type USB
@save :x:
@direct :white_check_mark:
@effects :x:
@detectors DetectLenovoLegionUSBControllers
@comment Tested on Lenovo Legion 7/7i gen. 6 ANSI and ISO models
Hardware modes are not implented
PLEASE UPDATE YOUR BIOS IF YOU HAVE ISSUES WITH HARDWARE MODES AFTER CLOSING OPENRGB
\*-------------------------------------------------------------------*/
/*--------------------------------------------------------*\
| Legion 7 gen 6: 6 zones |
| |
|Note: the device has 4 zones in the protocol however, the |
|vent lights have been split into 4 zones to improve ease |
|of use |
\*--------------------------------------------------------*/
/*------*\
|keyboard|
\*------*/
lenovo_zone lenovo_legion_7_gen_6_kbd
{
"Keyboard",
ZONE_TYPE_MATRIX,
10,
22,
0,
146,
};
/*------*\
|logo |
\*------*/
lenovo_zone lenovo_legion_7_gen_6_logo
{
"Logo",
ZONE_TYPE_LINEAR,
1,
13,
147,
159,
};
/*------*\
|vents |
\*------*/
lenovo_zone lenovo_legion_7_gen_6_vent_left
{
"Left vent",
ZONE_TYPE_LINEAR,
1,
26,
160,
186,
};
lenovo_zone lenovo_legion_7_gen_6_vent_right
{
"Right vent",
ZONE_TYPE_LINEAR,
1,
26,
187,
213,
};
lenovo_zone lenovo_legion_7_gen_6_vent_back_right
{
"Back Right vent",
ZONE_TYPE_LINEAR,
1,
25,
214,
239,
};
lenovo_zone lenovo_legion_7_gen_6_vent_back_left
{
"Back Left vent",
ZONE_TYPE_LINEAR,
1,
25,
240,
265,
};
/*------*\
|neon |
\*------*/
lenovo_zone lenovo_legion_7_gen_6_neon
{
"Neon",
ZONE_TYPE_LINEAR,
1,
99,
266,
364,
};
RGBController_LenovoUSB::RGBController_LenovoUSB(LenovoUSBController* controller_ptr)
{
controller = controller_ptr;
mode Direct;
Direct.name = "Direct";
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
name = controller->getName();
type = DEVICE_TYPE_KEYBOARD;
vendor = "Lenovo";
switch(controller->getPid())
{
case LEGION_7_6_PID_1:
case LEGION_7_6_PID_2:
case LEGION_7_6_PID_3:
description = "Lenovo Legion 7 gen 6, ANSI VERSION";
lenovo_leds = legion_7_g_6_ansi_leds;
lenovo_size_of_leds = sizeof(legion_7_g_6_ansi_leds)/sizeof(lenovo_led);
break;
}
for(unsigned int i = 0; i < lenovo_size_of_leds; i++)
{
leds.push_back({lenovo_leds[i].name, i});
}
leds.shrink_to_fit();
SetupZones();
}
RGBController_LenovoUSB::~RGBController_LenovoUSB()
{
/*--------------------------------*\
| see LenovoUSBController.cpp for |
| details |
\*--------------------------------*/
controller->setDeviceHardwareMode();
delete controller;
}
void RGBController_LenovoUSB::SetupZones()
{
vector<lenovo_zone> lenovo_zones;
switch(controller->getPid())
{
case LEGION_7_6_PID_1:
case LEGION_7_6_PID_2:
case LEGION_7_6_PID_3:
lenovo_zones.push_back(lenovo_legion_7_gen_6_kbd);
lenovo_zones.push_back(lenovo_legion_7_gen_6_logo);
lenovo_zones.push_back(lenovo_legion_7_gen_6_vent_left);
lenovo_zones.push_back(lenovo_legion_7_gen_6_vent_right);
lenovo_zones.push_back(lenovo_legion_7_gen_6_vent_back_right);
lenovo_zones.push_back(lenovo_legion_7_gen_6_vent_back_left);
lenovo_zones.push_back(lenovo_legion_7_gen_6_neon);
break;
}
for(int i = 0; i < lenovo_zones.size(); i++)
{
zone new_zone;
new_zone.name = lenovo_zones[i].name;
new_zone.type = lenovo_zones[i].type;
new_zone.leds_count = lenovo_zones[i].end - lenovo_zones[i].start + 1;
new_zone.leds_max = new_zone.leds_count;
new_zone.leds_min = new_zone.leds_count;
if(lenovo_zones[i].type == ZONE_TYPE_MATRIX)
{
new_zone.matrix_map = new matrix_map_type;
new_zone.matrix_map->height = lenovo_zones[i].height;
new_zone.matrix_map->width = lenovo_zones[i].width;
new_zone.matrix_map->map = new unsigned int[new_zone.matrix_map->height * new_zone.matrix_map->width];
/*----------------------------------------------------*\
| This section sets up the maps of zones where elements|
| may have an oddly aligned on the matrix |
| please be sure to document in some way which zones |
| in a device you may be implementing have this poperty|
| (Example in the LENOVO_7_6 section bellow) |
\*----------------------------------------------------*/
switch(controller->getPid())
{
case LEGION_7_6_PID_1:
case LEGION_7_6_PID_2:
case LEGION_7_6_PID_3:
/*----------------------------------------------------------------------*\
| for this device, only the keyboard map (lenovo_legion_7_gen_6_kbd) uses|
| a custom map, so that map is setup here |
\*----------------------------------------------------------------------*/
new_zone.matrix_map->map = new unsigned int[lenovo_zones[i].width * lenovo_zones[i].height]
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, NA, NA, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, NA, NA, NA, NA, 53, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, NA, NA, 68, 69, 70, NA,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 90, 65, 91, 66, 92, 67, NA, 93, 94, 95, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 84, 87, 86, 88, 89, 111, 113, 114, 96,
97, 98, 99, 100, 101, 102, 103, 104, 105, 116, 106, 117, 107, 118, 108, 109, 110, NA, 112, NA, 115, NA,
126, 127, 128, 129, 130, NA, NA, NA, NA, 131, 132, 133, NA, NA, NA, 136, NA, NA, 119, 121, 123, 125,
NA, 146, 145, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 135, NA, NA, 120, 122, 124, 144,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 134, 137, 139, NA, 140, 141, 143, NA,
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 138, NA, NA, NA, NA, 142, NA
};
break;
}
}
else
{
new_zone.matrix_map = NULL;
}
zones.push_back(new_zone);
}
SetupColors();
}
void RGBController_LenovoUSB::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_LenovoUSB::UpdateSingleLED(int led)
{
if(led != NA)
{
controller->setSingleLED(lenovo_leds[led].zone_num, lenovo_leds[led].led_num, colors[led]);
}
}
void RGBController_LenovoUSB::UpdateZoneLEDs(int zone)
{
uint8_t device_zone = lenovo_leds[zones[zone].start_idx].zone_num;
vector<pair<uint8_t, RGBColor>> color_map;
for(int i = 0; i < zones[zone].leds_count; i++)
{
int index = zones[zone].start_idx+i;
color_map.push_back({lenovo_leds[index].led_num, colors[index]});
}
color_map.shrink_to_fit();
controller->setZoneLeds(device_zone, color_map);
}
void RGBController_LenovoUSB::DeviceUpdateLEDs()
{
for(unsigned int i = 0; i < lenovo_size_of_leds;)
{
uint8_t curr_device_zone = lenovo_leds[i].zone_num;
vector<pair<uint8_t, RGBColor>> curr_color_map;
for(; i < lenovo_size_of_leds && lenovo_leds[i].zone_num == curr_device_zone && i < colors.size(); i++)
{
curr_color_map.push_back({lenovo_leds[i].led_num, colors[i]});
}
controller->setZoneLeds(curr_device_zone, curr_color_map);
}
}
void RGBController_LenovoUSB::SetCustomMode()
{
/*---------------------------------------------------------*\
| This device has only one mode |
\*---------------------------------------------------------*/
active_mode = 0;
}
void RGBController_LenovoUSB::DeviceUpdateMode()
{
/*---------------------------------------------------------*\
| This device does not support multiple modes |
\*---------------------------------------------------------*/
}
void RGBController_LenovoUSB::DeviceSaveMode()
{
/*---------------------------------------------------------*\
| This device does not support saving or multiple modes |
\*---------------------------------------------------------*/
}

View file

@ -0,0 +1,44 @@
/*-------------------------------------------------------------------*\
| RGBController_LenovoUSB.h |
| |
| interface for various Lenovo Legion Devices |
| |
| Cooper Hall (geobot19) 17 Apr 2022 |
| |
\*-------------------------------------------------------------------*/
#include "LenovoDevices.h"
#include "LenovoUSBController.h"
#include "RGBController.h"
#include <vector>
#ifndef RGBCONTROLLER_LENOVOUSB_H
#define RGBCONTROLLER_LENOVOUSB_H
#define NA 0xFFFFFFFF
class RGBController_LenovoUSB : public RGBController
{
public:
RGBController_LenovoUSB(LenovoUSBController* controller_ptr);
~RGBController_LenovoUSB();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void SetCustomMode();
void DeviceUpdateMode();
void DeviceSaveMode();
private:
unsigned int lenovo_size_of_leds;
LenovoUSBController *controller;
const lenovo_led *lenovo_leds;
};
#endif

View file

@ -126,6 +126,7 @@ INCLUDEPATH +=
Controllers/HyperXMouseController/ \
Controllers/HyperXMousematController/ \
Controllers/LEDStripController/ \
Controllers/LenovoControllers/ \
Controllers/LianLiController/ \
Controllers/LIFXController/ \
Controllers/LogitechController/ \
@ -408,6 +409,9 @@ HEADERS +=
Controllers/KeychronKeyboardController/RGBController_KeychronKeyboard.h \
Controllers/LEDStripController/LEDStripController.h \
Controllers/LEDStripController/RGBController_LEDStrip.h \
Controllers/LenovoControllers/LenovoDevices.h \
Controllers/LenovoControllers/LenovoUSBController.h \
Controllers/LenovoControllers/RGBController_LenovoUSB.h \
Controllers/LexipMouseController/LexipMouseController.h \
Controllers/LexipMouseController/RGBController_LexipMouse.h \
Controllers/LIFXController/LIFXController.h \
@ -897,6 +901,9 @@ SOURCES +=
Controllers/LEDStripController/LEDStripController.cpp \
Controllers/LEDStripController/LEDStripControllerDetect.cpp \
Controllers/LEDStripController/RGBController_LEDStrip.cpp \
Controllers/LenovoControllers/LenovoUSBController.cpp \
Controllers/LenovoControllers/LenovoUSBDetect.cpp \
Controllers/LenovoControllers/RGBController_LenovoUSB.cpp \
Controllers/LexipMouseController/LexipMouseController.cpp \
Controllers/LexipMouseController/LexipMouseControllerDetect.cpp \
Controllers/LexipMouseController/RGBController_LexipMouse.cpp \