Publish LumaOps source
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| Lenovo4ZoneUSBController.cpp |
|
||||
| |
|
||||
| Driver for Lenovo 4-Zone devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <iostream>
|
||||
#include "Lenovo4ZoneUSBController.h"
|
||||
#include "LogManager.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
Lenovo4ZoneUSBController::Lenovo4ZoneUSBController(hid_device* dev_handle, const char* path, uint16_t in_pid, std::string dev_name)
|
||||
{
|
||||
dev = dev_handle;
|
||||
location = path;
|
||||
pid = in_pid;
|
||||
name = dev_name;
|
||||
}
|
||||
|
||||
Lenovo4ZoneUSBController::~Lenovo4ZoneUSBController()
|
||||
{
|
||||
hid_close(dev);
|
||||
}
|
||||
|
||||
void Lenovo4ZoneUSBController::setMode(const KeyboardState &in_mode)
|
||||
{
|
||||
uint8_t buffer[LENOVO_4_ZONE_HID_PACKET_SIZE] =
|
||||
{
|
||||
in_mode.header[0], in_mode.header[1],
|
||||
in_mode.effect,
|
||||
in_mode.speed,
|
||||
in_mode.brightness,
|
||||
in_mode.zone0_rgb[0], in_mode.zone0_rgb[1], in_mode.zone0_rgb[2],
|
||||
in_mode.zone1_rgb[0], in_mode.zone1_rgb[1], in_mode.zone1_rgb[2],
|
||||
in_mode.zone2_rgb[0], in_mode.zone2_rgb[1], in_mode.zone2_rgb[2],
|
||||
in_mode.zone3_rgb[0], in_mode.zone3_rgb[1], in_mode.zone3_rgb[2],
|
||||
0x00,
|
||||
in_mode.wave_ltr, in_mode.wave_rtl
|
||||
};
|
||||
hid_send_feature_report(dev, buffer, LENOVO_4_ZONE_HID_PACKET_SIZE);
|
||||
}
|
||||
|
||||
uint16_t Lenovo4ZoneUSBController::getPid()
|
||||
{
|
||||
return pid;
|
||||
}
|
||||
|
||||
std::string Lenovo4ZoneUSBController::getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string Lenovo4ZoneUSBController::getLocation()
|
||||
{
|
||||
return location;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| Lenovo4ZoneUSBController.h |
|
||||
| |
|
||||
| Driver for Lenovo 4-Zone devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "LogManager.h"
|
||||
#include "LenovoDevices4Zone.h"
|
||||
|
||||
#ifndef HID_MAX_STR
|
||||
#define HID_MAX_STR 255
|
||||
#endif
|
||||
|
||||
#define LENOVO_4_ZONE_HID_PACKET_SIZE 33
|
||||
|
||||
class Lenovo4ZoneUSBController
|
||||
{
|
||||
public:
|
||||
/*--------------*\
|
||||
|ctor(s) and dtor|
|
||||
\*--------------*/
|
||||
Lenovo4ZoneUSBController(hid_device* dev_handle, const char* path, uint16_t in_pid, std::string dev_name);
|
||||
~Lenovo4ZoneUSBController();
|
||||
|
||||
void setMode(const KeyboardState &in_mode);
|
||||
|
||||
/*--------------*\
|
||||
|device functions|
|
||||
\*--------------*/
|
||||
uint16_t getPid();
|
||||
std::string getName();
|
||||
std::string getLocation();
|
||||
|
||||
private:
|
||||
/*--------------*\
|
||||
|data members |
|
||||
\*--------------*/
|
||||
std::string name;
|
||||
hid_device *dev;
|
||||
std::string location;
|
||||
uint16_t pid;
|
||||
KeyboardState mode;
|
||||
|
||||
/*--------------*\
|
||||
|device functions|
|
||||
\*--------------*/
|
||||
void sendBasicInstruction(uint8_t instruction);
|
||||
};
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| Lenovo4ZoneUSBControllerDetect.cpp |
|
||||
| |
|
||||
| Detector for Lenovo 4-Zone devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <hidapi.h>
|
||||
#include "Detector.h"
|
||||
#include "Lenovo4ZoneUSBController.h"
|
||||
#include "LenovoDevices4Zone.h"
|
||||
#include "RGBController_Lenovo4ZoneUSB.h"
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| vendor IDs |
|
||||
\*-----------------------------------------------------*/
|
||||
#define ITE_VID 0x048D
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Interface, Usage, and Usage Page |
|
||||
\*-----------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
LENOVO_PAGE = 0xFF89,
|
||||
LENOVO_USAGE = 0xCC
|
||||
};
|
||||
|
||||
void DetectLenovo4ZoneUSBControllers(hid_device_info* info, const std::string& name)
|
||||
{
|
||||
hid_device* dev = hid_open_path(info->path);
|
||||
|
||||
if(dev)
|
||||
{
|
||||
Lenovo4ZoneUSBController* controller = new Lenovo4ZoneUSBController(dev, info->path, info->product_id, name);
|
||||
RGBController_Lenovo4ZoneUSB* rgb_controller = new RGBController_Lenovo4ZoneUSB(controller);
|
||||
|
||||
ResourceManager::get()->RegisterRGBController(rgb_controller);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Ideapad 3-15ach6", DetectLenovo4ZoneUSBControllers, ITE_VID, IDEAPAD_315ACH6, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo 5 2023", DetectLenovo4ZoneUSBControllers, ITE_VID, LEGION_5_2023_PID, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo 5 2023 Ideapad", DetectLenovo4ZoneUSBControllers, ITE_VID, LEGION_5_2023_IDEAPAD_PID, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo 5 2022", DetectLenovo4ZoneUSBControllers, ITE_VID, LEGION_5_2022_PID, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo 5 2022 Ideapad", DetectLenovo4ZoneUSBControllers, ITE_VID, LEGION_5_2022_IDEAPAD_PID, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo 5 2021", DetectLenovo4ZoneUSBControllers, ITE_VID, LEGION_5_2021_PID, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo 5 2021 Ideapad", DetectLenovo4ZoneUSBControllers, ITE_VID, LEGION_5_2021_IDEAPAD_PID, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo 5 2020", DetectLenovo4ZoneUSBControllers, ITE_VID, LEGION_5_2020_PID, LENOVO_PAGE, LENOVO_USAGE);
|
||||
@@ -0,0 +1,107 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoDevices4Zone.h |
|
||||
| |
|
||||
| Device list for Lenovo 4-Zone devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "RGBControllerKeyNames.h"
|
||||
#include "RGBController.h"
|
||||
#include "LenovoDevices.h"
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Keyboard product IDs |
|
||||
\*-----------------------------------------------------*/
|
||||
#define IDEAPAD_315ACH6 0xC963
|
||||
#define LEGION_5_2023_PID 0xC985
|
||||
#define LEGION_5_2023_IDEAPAD_PID 0xC984
|
||||
#define LEGION_5_2022_PID 0xC975
|
||||
#define LEGION_5_2022_IDEAPAD_PID 0xC973
|
||||
#define LEGION_5_2021_PID 0xC965
|
||||
#define LEGION_5_2021_IDEAPAD_PID 0xC963
|
||||
#define LEGION_5_2020_PID 0xC955
|
||||
|
||||
enum LENOVO_4_ZONE_EFFECT
|
||||
{
|
||||
LENOVO_4_ZONE_EFFECT_STATIC = 1,
|
||||
LENOVO_4_ZONE_EFFECT_BREATH = 3,
|
||||
LENOVO_4_ZONE_EFFECT_WAVE = 4,
|
||||
LENOVO_4_ZONE_EFFECT_SMOOTH = 6,
|
||||
};
|
||||
|
||||
enum LENOVO_4_ZONE_BRIGHTNESS
|
||||
{
|
||||
LENOVO_4_ZONE_BRIGHTNESS_LOW = 1,
|
||||
LENOVO_4_ZONE_BRIGHTNESS_HIGH = 2,
|
||||
};
|
||||
|
||||
enum LENOVO_4_ZONE_SPEED
|
||||
{
|
||||
LENOVO_4_ZONE_SPEED_SLOWEST = 1,
|
||||
LENOVO_4_ZONE_SPEED_SLOW = 2,
|
||||
LENOVO_4_ZONE_SPEED_FAST = 3,
|
||||
LENOVO_4_ZONE_SPEED_FASTEST = 4,
|
||||
};
|
||||
|
||||
/// struct a USB packet for set the keyboard LEDs
|
||||
class KeyboardState
|
||||
{
|
||||
public:
|
||||
uint8_t header[2] = {0xCC, 0x16};
|
||||
uint8_t effect = LENOVO_4_ZONE_EFFECT_STATIC;
|
||||
uint8_t speed = LENOVO_4_ZONE_SPEED_SLOWEST;
|
||||
uint8_t brightness = LENOVO_4_ZONE_BRIGHTNESS_LOW;
|
||||
uint8_t zone0_rgb[3] = {0xFF, 0xFF, 0xFF};
|
||||
uint8_t zone1_rgb[3] = {0xFF, 0xFF, 0xFF};
|
||||
uint8_t zone2_rgb[3] = {0xFF, 0xFF, 0xFF};
|
||||
uint8_t zone3_rgb[3] = {0xFF, 0xFF, 0xFF};
|
||||
uint8_t wave_ltr = 0;
|
||||
uint8_t wave_rtl = 0;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
header[0] = 0xCC, header[1] = 0x16;
|
||||
effect = LENOVO_4_ZONE_EFFECT_STATIC;
|
||||
speed = LENOVO_4_ZONE_SPEED_SLOWEST;
|
||||
brightness = LENOVO_4_ZONE_BRIGHTNESS_LOW;
|
||||
zone0_rgb[0] = 0xFF, zone0_rgb[1] = 0xFF, zone0_rgb[2] = 0xFF;
|
||||
zone1_rgb[0] = 0xFF, zone1_rgb[1] = 0xFF, zone1_rgb[2] = 0xFF;
|
||||
zone2_rgb[0] = 0xFF, zone2_rgb[1] = 0xFF, zone2_rgb[2] = 0xFF;
|
||||
zone3_rgb[0] = 0xFF, zone3_rgb[1] = 0xFF, zone3_rgb[2] = 0xFF;
|
||||
wave_ltr = 0;
|
||||
wave_rtl = 0;
|
||||
}
|
||||
|
||||
void SetColors(std::vector<RGBColor> group_colors)
|
||||
{
|
||||
zone0_rgb[0] = RGBGetRValue(group_colors[0]);
|
||||
zone0_rgb[1] = RGBGetGValue(group_colors[0]);
|
||||
zone0_rgb[2] = RGBGetBValue(group_colors[0]);
|
||||
zone1_rgb[0] = RGBGetRValue(group_colors[1]);
|
||||
zone1_rgb[1] = RGBGetGValue(group_colors[1]);
|
||||
zone1_rgb[2] = RGBGetBValue(group_colors[1]);
|
||||
zone2_rgb[0] = RGBGetRValue(group_colors[2]);
|
||||
zone2_rgb[1] = RGBGetGValue(group_colors[2]);
|
||||
zone2_rgb[2] = RGBGetBValue(group_colors[2]);
|
||||
zone3_rgb[0] = RGBGetRValue(group_colors[3]);
|
||||
zone3_rgb[1] = RGBGetGValue(group_colors[3]);
|
||||
zone3_rgb[2] = RGBGetBValue(group_colors[3]);
|
||||
}
|
||||
};
|
||||
|
||||
/*-------------------------*\
|
||||
| 4-Zone keyboard |
|
||||
\*-------------------------*/
|
||||
|
||||
static const lenovo_led lenovo_4_zone_leds[]
|
||||
{
|
||||
{0x00, "Left side"},
|
||||
{0x01, "Left center"},
|
||||
{0x02, "Right center"},
|
||||
{0x03, "Right side"},
|
||||
};
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_Lenovo4ZoneUSB.cpp |
|
||||
| |
|
||||
| Device list for Lenovo 4-Zone devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "Lenovo4ZoneUSBController.h"
|
||||
#include "LenovoDevices4Zone.h"
|
||||
#include "RGBController_Lenovo4ZoneUSB.h"
|
||||
#include "LogManager.h"
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name Lenovo 4 Zone USB
|
||||
@category Keyboard
|
||||
@type USB
|
||||
@save :x:
|
||||
@direct :white_check_mark:
|
||||
@effects :x:
|
||||
@detectors DetectLenovo4ZoneUSBControllers
|
||||
@comment Tested on Lenovo Legion 5 2021
|
||||
\*-------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#define LENOVO_4_ZONE_NUM_LEDS 4
|
||||
|
||||
RGBController_Lenovo4ZoneUSB::RGBController_Lenovo4ZoneUSB(Lenovo4ZoneUSBController* controller_ptr)
|
||||
{
|
||||
controller = controller_ptr;
|
||||
|
||||
name = controller->getName();
|
||||
type = DEVICE_TYPE_LAPTOP;
|
||||
vendor = "Lenovo";
|
||||
description = "Lenovo 4-Zone device";
|
||||
|
||||
mode Direct;
|
||||
Direct.name = "Direct";
|
||||
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Direct.color_mode = MODE_COLORS_PER_LED;
|
||||
Direct.brightness_min = 1;
|
||||
Direct.brightness_max = 2;
|
||||
|
||||
modes.push_back(Direct);
|
||||
|
||||
mode Breath;
|
||||
Breath.name = "Breathing";
|
||||
Breath.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
|
||||
Breath.color_mode = MODE_COLORS_PER_LED;
|
||||
Breath.brightness_min = 1;
|
||||
Breath.brightness_max = 2;
|
||||
Breath.speed_min = 1;
|
||||
Breath.speed_max = 4;
|
||||
|
||||
modes.push_back(Breath);
|
||||
|
||||
mode Wave;
|
||||
Wave.name = "Rainbow Wave";
|
||||
Wave.flags = MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR;
|
||||
Wave.color_mode = MODE_COLORS_RANDOM;
|
||||
Wave.brightness_min = 1;
|
||||
Wave.brightness_max = 2;
|
||||
Wave.speed_min = 1;
|
||||
Wave.speed_max = 4;
|
||||
Wave.direction = MODE_DIRECTION_LEFT | MODE_DIRECTION_RIGHT;
|
||||
modes.push_back(Wave);
|
||||
|
||||
mode Smooth;
|
||||
Smooth.name = "Spectrum Cycle";
|
||||
Smooth.flags = MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED;
|
||||
Smooth.color_mode = MODE_COLORS_RANDOM;
|
||||
Smooth.brightness_min = 1;
|
||||
Smooth.brightness_max = 2;
|
||||
Smooth.speed_min = 1;
|
||||
Smooth.speed_max = 4;
|
||||
modes.push_back(Smooth);
|
||||
|
||||
SetupZones();
|
||||
}
|
||||
|
||||
RGBController_Lenovo4ZoneUSB::~RGBController_Lenovo4ZoneUSB()
|
||||
{
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void RGBController_Lenovo4ZoneUSB::SetupZones()
|
||||
{
|
||||
zone new_zone;
|
||||
new_zone.name = ZONE_EN_KEYBOARD;
|
||||
new_zone.type = ZONE_TYPE_LINEAR;
|
||||
new_zone.leds_count = LENOVO_4_ZONE_NUM_LEDS;
|
||||
new_zone.leds_max = new_zone.leds_count;
|
||||
new_zone.leds_min = new_zone.leds_count;
|
||||
|
||||
new_zone.matrix_map = NULL;
|
||||
|
||||
|
||||
zones.push_back(new_zone);
|
||||
|
||||
for(unsigned int led_idx = 0; led_idx < LENOVO_4_ZONE_NUM_LEDS; led_idx++ )
|
||||
{
|
||||
led new_led;
|
||||
new_led.name = lenovo_4_zone_leds[led_idx].name;
|
||||
new_led.value = lenovo_4_zone_leds[led_idx].led_num;
|
||||
leds.push_back(new_led);
|
||||
}
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_Lenovo4ZoneUSB::ResizeZone(int /*zone*/, int /*new_size*/)
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| This device does not support resizing zones |
|
||||
\*---------------------------------------------------------*/
|
||||
}
|
||||
|
||||
void RGBController_Lenovo4ZoneUSB::UpdateSingleLED(int /*led*/)
|
||||
{
|
||||
}
|
||||
|
||||
void RGBController_Lenovo4ZoneUSB::UpdateZoneLEDs(int /*zone*/)
|
||||
{
|
||||
}
|
||||
|
||||
void RGBController_Lenovo4ZoneUSB::DeviceUpdateLEDs()
|
||||
{
|
||||
state.SetColors(colors);
|
||||
controller->setMode(state);
|
||||
}
|
||||
|
||||
void RGBController_Lenovo4ZoneUSB::DeviceUpdateMode()
|
||||
{
|
||||
state.Reset();
|
||||
state.SetColors(colors);
|
||||
|
||||
switch (active_mode)
|
||||
{
|
||||
case 0:
|
||||
state.effect = LENOVO_4_ZONE_EFFECT_STATIC;
|
||||
break;
|
||||
case 1:
|
||||
state.effect = LENOVO_4_ZONE_EFFECT_BREATH;
|
||||
break;
|
||||
case 2:
|
||||
state.effect = LENOVO_4_ZONE_EFFECT_WAVE;
|
||||
state.wave_ltr = modes[active_mode].direction?0:1;
|
||||
state.wave_rtl = modes[active_mode].direction?1:0;
|
||||
break;
|
||||
case 3:
|
||||
state.effect = LENOVO_4_ZONE_EFFECT_SMOOTH;
|
||||
break;
|
||||
}
|
||||
|
||||
if(active_mode != (LENOVO_4_ZONE_EFFECT_STATIC - 1)) // mode number from 0, but in mode from 1
|
||||
{
|
||||
state.speed = modes[active_mode].speed;
|
||||
}
|
||||
state.brightness = modes[active_mode].brightness;
|
||||
|
||||
controller->setMode(state);
|
||||
}
|
||||
|
||||
void RGBController_Lenovo4ZoneUSB::DeviceSaveMode()
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| This device does not support saving or multiple modes |
|
||||
\*---------------------------------------------------------*/
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_Lenovo4ZoneUSB.h |
|
||||
| |
|
||||
| RGBController for Lenovo 4-Zone devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "LenovoDevices.h"
|
||||
#include "Lenovo4ZoneUSBController.h"
|
||||
#include "RGBController.h"
|
||||
|
||||
#define NA 0xFFFFFFFF
|
||||
|
||||
class RGBController_Lenovo4ZoneUSB : public RGBController
|
||||
{
|
||||
public:
|
||||
RGBController_Lenovo4ZoneUSB(Lenovo4ZoneUSBController* controller_ptr);
|
||||
~RGBController_Lenovo4ZoneUSB();
|
||||
|
||||
void SetupZones();
|
||||
void ResizeZone(int zone, int new_size);
|
||||
|
||||
void DeviceUpdateLEDs();
|
||||
void UpdateZoneLEDs(int zone);
|
||||
void UpdateSingleLED(int led);
|
||||
|
||||
void DeviceUpdateMode();
|
||||
void DeviceSaveMode();
|
||||
|
||||
private:
|
||||
KeyboardState state;
|
||||
|
||||
Lenovo4ZoneUSBController *controller;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,101 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoK510Controller.cpp |
|
||||
| |
|
||||
| Driver for Lenovo Legion K510 keyboard |
|
||||
| |
|
||||
| Bnyro 27 Oct 2025 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include "LenovoK510Controller.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
LenovoK510Controller::LenovoK510Controller(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
|
||||
{
|
||||
device = dev_handle;
|
||||
location = info.path;
|
||||
name = dev_name;
|
||||
}
|
||||
|
||||
LenovoK510Controller::~LenovoK510Controller()
|
||||
{
|
||||
hid_close(device);
|
||||
}
|
||||
|
||||
std::string LenovoK510Controller::GetDeviceLocation()
|
||||
{
|
||||
return("HID: " + location);
|
||||
}
|
||||
|
||||
std::string LenovoK510Controller::GetDeviceName()
|
||||
{
|
||||
return(name);
|
||||
}
|
||||
|
||||
void LenovoK510Controller::SetMode(unsigned int color_mode, RGBColor color, unsigned char mode_value, unsigned int brigthness, unsigned int speed, unsigned int direction)
|
||||
{
|
||||
unsigned char usb_buf[K510_DATA_SIZE];
|
||||
memset(usb_buf, 0x00, K510_DATA_SIZE);
|
||||
usb_buf[0x00] = 0x04; // ReportID
|
||||
|
||||
// magic bytes to trigger an LED update
|
||||
usb_buf[0x03] = 0x06;
|
||||
usb_buf[0x04] = 0x38;
|
||||
|
||||
usb_buf[0x09] = mode_value;
|
||||
usb_buf[0x0A] = static_cast<unsigned char>(brigthness);
|
||||
// speed behaves contrary to normal expectations: the lower the value, the higher the speed
|
||||
usb_buf[0x0B] = static_cast<unsigned char>(speed);
|
||||
|
||||
if(direction == MODE_DIRECTION_UP || direction == MODE_DIRECTION_LEFT)
|
||||
{
|
||||
// 0x01 reverses the direction of the animation
|
||||
usb_buf[0x0C] = 0x01;
|
||||
}
|
||||
|
||||
if(color_mode == MODE_COLORS_MODE_SPECIFIC)
|
||||
{
|
||||
usb_buf[0x0D] = 0x00;
|
||||
usb_buf[0x0E] = static_cast<unsigned char>(RGBGetRValue(color));
|
||||
usb_buf[0x0F] = static_cast<unsigned char>(RGBGetGValue(color));
|
||||
usb_buf[0x10] = static_cast<unsigned char>(RGBGetBValue(color));
|
||||
}
|
||||
else
|
||||
{
|
||||
// sets color to automatic
|
||||
usb_buf[0x0D] = 0x01;
|
||||
}
|
||||
|
||||
hid_write(device, usb_buf, K510_DATA_SIZE);
|
||||
}
|
||||
|
||||
mode LenovoK510Controller::GetCurrentState()
|
||||
{
|
||||
unsigned char usb_buf[K510_DATA_SIZE];
|
||||
memset(usb_buf, 0x00, K510_DATA_SIZE);
|
||||
usb_buf[0x00] = 0x04; // ReportID
|
||||
|
||||
// magic bytes to get a response containing the current configuration
|
||||
usb_buf[0x03] = 0x05;
|
||||
usb_buf[0x04] = 0x38;
|
||||
|
||||
hid_write(device, usb_buf, K510_DATA_SIZE);
|
||||
|
||||
unsigned char res_buf[K510_DATA_SIZE];
|
||||
hid_read_timeout(device, res_buf, K510_DATA_SIZE, 50);
|
||||
|
||||
mode current_mode;
|
||||
current_mode.value = res_buf[0x09];
|
||||
current_mode.brightness = res_buf[0x0A];
|
||||
current_mode.speed = res_buf[0x0B];
|
||||
current_mode.direction = res_buf[0x0C];
|
||||
current_mode.color_mode = res_buf[0x0D] ? MODE_COLORS_RANDOM : MODE_COLORS_MODE_SPECIFIC;
|
||||
current_mode.colors.push_back(ToRGBColor(res_buf[0x0E], res_buf[0x0F], res_buf[0x10]));
|
||||
|
||||
return(current_mode);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoK510Controller.h |
|
||||
| |
|
||||
| Driver for Lenovo Legion K510 keyboard |
|
||||
| |
|
||||
| Bnyro 27 Oct 2025 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
|
||||
#define K510_DATA_SIZE 64
|
||||
|
||||
#define K510_BRIGHTNESS_DEFAULT 2
|
||||
#define K510_BRIGHTNESS_MIN 0
|
||||
#define K510_BRIGHTNESS_MAX 2
|
||||
|
||||
// the lower the speed value, the faster the animation
|
||||
#define K510_SPEED_DEFAULT 2
|
||||
#define K510_SPEED_MIN 4
|
||||
#define K510_SPEED_MAX 0
|
||||
|
||||
enum
|
||||
{
|
||||
K510_MODE_CORRUGATED = 0x01,
|
||||
K510_MODE_CLOUD = 0x02,
|
||||
K510_MODE_SERPENTINE = 0x03,
|
||||
K510_MODE_SPECTRUM = 0x04,
|
||||
K510_MODE_BREATH = 0x05,
|
||||
K510_MODE_NORMAL = 0x06,
|
||||
K510_MODE_REACTION = 0x07,
|
||||
K510_MODE_RIPPLES = 0x08,
|
||||
K510_MODE_TRAVERSE = 0x09,
|
||||
K510_MODE_STARS = 0x0A,
|
||||
K510_MODE_FLOWERS = 0x0B,
|
||||
K510_MODE_ROLL = 0x0C,
|
||||
K510_MODE_WAVE = 0x0D,
|
||||
K510_MODE_CARTOON = 0x0E,
|
||||
K510_MODE_RAIN = 0x0F,
|
||||
K510_MODE_SCAN = 0x10,
|
||||
K510_MODE_SURMOUNT = 0x11,
|
||||
K510_MODE_SPEED = 0x12,
|
||||
};
|
||||
|
||||
class LenovoK510Controller
|
||||
{
|
||||
public:
|
||||
LenovoK510Controller(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
|
||||
~LenovoK510Controller();
|
||||
|
||||
std::string GetDeviceLocation();
|
||||
std::string GetDeviceName();
|
||||
|
||||
void SetMode(unsigned int color_mode, RGBColor color, unsigned char mode_value, unsigned int brightness, unsigned int speed, unsigned int direction);
|
||||
mode GetCurrentState();
|
||||
;
|
||||
|
||||
private:
|
||||
hid_device* device;
|
||||
std::string location;
|
||||
std::string name;
|
||||
};
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoK510ControllerDetect.cpp |
|
||||
| |
|
||||
| Detector for Lenovo Legion K510 keyboard |
|
||||
| |
|
||||
| Bnyro 27 Oct 2025 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "Detector.h"
|
||||
#include "RGBController_LenovoK510.h"
|
||||
#include "LenovoK510Controller.h"
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Lenovo vendor, product, usage and page IDs |
|
||||
\*---------------------------------------------------------*/
|
||||
#define LENOVO_VID 0x17EF
|
||||
#define LEGION_K510_PID 0x619A
|
||||
#define LENOVO_IFACE_NUM 0x01
|
||||
#define LENOVO_PAGE 0xFF1C
|
||||
#define LENOVO_USAGE 0x0092
|
||||
|
||||
void DetectLenovoLegionK510Controllers(hid_device_info* info, const std::string& name)
|
||||
{
|
||||
hid_device* dev = hid_open_path(info->path);
|
||||
|
||||
if(dev)
|
||||
{
|
||||
LenovoK510Controller* controller = new LenovoK510Controller(dev, *info, name);
|
||||
RGBController_LenovoK510* rgb_controller = new RGBController_LenovoK510(controller);
|
||||
|
||||
ResourceManager::get()->RegisterRGBController(rgb_controller);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_HID_DETECTOR_IPU("Lenovo Legion K510 Mini Pro", DetectLenovoLegionK510Controllers, LENOVO_VID, LEGION_K510_PID, LENOVO_IFACE_NUM, LENOVO_PAGE, LENOVO_USAGE);
|
||||
+352
@@ -0,0 +1,352 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_LenovoM300.cpp |
|
||||
| |
|
||||
| RGBController for Lenovo Legion K510 keyboard |
|
||||
| |
|
||||
| Bnyro 27 Oct 2025 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "RGBController_LenovoK510.h"
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name Lenovo Legion K510
|
||||
@category Keyboard
|
||||
@type USB
|
||||
@save :robot:
|
||||
@direct :x:
|
||||
@effects :white_check_mark:
|
||||
@detectors DetectLenovoLegionK510Controllers
|
||||
@comment
|
||||
\*-------------------------------------------------------------------*/
|
||||
|
||||
RGBController_LenovoK510::RGBController_LenovoK510(LenovoK510Controller* controller_ptr)
|
||||
{
|
||||
controller = controller_ptr;
|
||||
|
||||
name = controller->GetDeviceName();
|
||||
vendor = "Lenovo";
|
||||
type = DEVICE_TYPE_KEYBOARD;
|
||||
description = "Lenovo Legion K510 Mini Pro";
|
||||
location = controller->GetDeviceLocation();
|
||||
|
||||
mode Corrugated;
|
||||
Corrugated.name = "Corrugated";
|
||||
Corrugated.value = K510_MODE_CORRUGATED;
|
||||
Corrugated.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_DIRECTION_LR;
|
||||
Corrugated.color_mode = MODE_COLORS_RANDOM;
|
||||
Corrugated.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Corrugated.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Corrugated.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Corrugated.speed = K510_SPEED_DEFAULT;
|
||||
Corrugated.speed_min = K510_SPEED_MIN;
|
||||
Corrugated.speed_max = K510_SPEED_MAX;
|
||||
Corrugated.colors.resize(1);
|
||||
modes.push_back(Corrugated);
|
||||
|
||||
mode Cloud;
|
||||
Cloud.name = "Cloud";
|
||||
Cloud.value = K510_MODE_CLOUD;
|
||||
Cloud.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_DIRECTION_LR;
|
||||
Cloud.color_mode = MODE_COLORS_RANDOM;
|
||||
Cloud.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Cloud.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Cloud.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Cloud.speed = K510_SPEED_DEFAULT;
|
||||
Cloud.speed_min = K510_SPEED_MIN;
|
||||
Cloud.speed_max = K510_SPEED_MAX;
|
||||
Cloud.colors.resize(1);
|
||||
modes.push_back(Cloud);
|
||||
|
||||
mode Serpentine;
|
||||
Serpentine.name = "Serpentine";
|
||||
Serpentine.value = K510_MODE_SERPENTINE;
|
||||
Serpentine.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_DIRECTION_LR;
|
||||
Serpentine.color_mode = MODE_COLORS_RANDOM;
|
||||
Serpentine.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Serpentine.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Serpentine.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Serpentine.speed = K510_SPEED_DEFAULT;
|
||||
Serpentine.speed_min = K510_SPEED_MIN;
|
||||
Serpentine.speed_max = K510_SPEED_MAX;
|
||||
Serpentine.colors.resize(1);
|
||||
modes.push_back(Serpentine);
|
||||
|
||||
mode Spectrum;
|
||||
Spectrum.name = "Spectrum Cycle";
|
||||
Spectrum.value = K510_MODE_SPECTRUM;
|
||||
Spectrum.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Spectrum.color_mode = MODE_COLORS_NONE;
|
||||
Spectrum.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Spectrum.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Spectrum.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Spectrum.speed = K510_SPEED_DEFAULT;
|
||||
Spectrum.speed_min = K510_SPEED_MIN;
|
||||
Spectrum.speed_max = K510_SPEED_MAX;
|
||||
modes.push_back(Spectrum);
|
||||
|
||||
mode Breath;
|
||||
Breath.name = "Breathing";
|
||||
Breath.value = K510_MODE_BREATH;
|
||||
Breath.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Breath.color_mode = MODE_COLORS_RANDOM;
|
||||
Breath.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Breath.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Breath.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Breath.speed = K510_SPEED_DEFAULT;
|
||||
Breath.speed_min = K510_SPEED_MIN;
|
||||
Breath.speed_max = K510_SPEED_MAX;
|
||||
Breath.colors.resize(1);
|
||||
modes.push_back(Breath);
|
||||
|
||||
mode Normal;
|
||||
Normal.name = "Static";
|
||||
Normal.value = K510_MODE_NORMAL;
|
||||
Normal.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Normal.color_mode = MODE_COLORS_RANDOM;
|
||||
Normal.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Normal.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Normal.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Normal.colors.resize(1);
|
||||
modes.push_back(Normal);
|
||||
|
||||
mode Reaction;
|
||||
Reaction.name = "Reaction";
|
||||
Reaction.value = K510_MODE_REACTION;
|
||||
Reaction.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Reaction.color_mode = MODE_COLORS_RANDOM;
|
||||
Reaction.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Reaction.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Reaction.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Reaction.speed = K510_SPEED_DEFAULT;
|
||||
Reaction.speed_min = K510_SPEED_MIN;
|
||||
Reaction.speed_max = K510_SPEED_MAX;
|
||||
Reaction.colors.resize(1);
|
||||
modes.push_back(Reaction);
|
||||
|
||||
mode Ripples;
|
||||
Ripples.name = "Ripples";
|
||||
Ripples.value = K510_MODE_RIPPLES;
|
||||
Ripples.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Ripples.color_mode = MODE_COLORS_RANDOM;
|
||||
Ripples.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Ripples.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Ripples.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Ripples.speed = K510_SPEED_DEFAULT;
|
||||
Ripples.speed_min = K510_SPEED_MIN;
|
||||
Ripples.speed_max = K510_SPEED_MAX;
|
||||
Ripples.colors.resize(1);
|
||||
modes.push_back(Ripples);
|
||||
|
||||
mode Traverse;
|
||||
Traverse.name = "Traverse";
|
||||
Traverse.value = K510_MODE_TRAVERSE;
|
||||
Traverse.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Traverse.color_mode = MODE_COLORS_RANDOM;
|
||||
Traverse.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Traverse.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Traverse.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Traverse.speed = K510_SPEED_DEFAULT;
|
||||
Traverse.speed_min = K510_SPEED_MIN;
|
||||
Traverse.speed_max = K510_SPEED_MAX;
|
||||
Traverse.colors.resize(1);
|
||||
modes.push_back(Traverse);
|
||||
|
||||
mode Stars;
|
||||
Stars.name = "Stars";
|
||||
Stars.value = K510_MODE_STARS;
|
||||
Stars.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Stars.color_mode = MODE_COLORS_RANDOM;
|
||||
Stars.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Stars.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Stars.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Stars.speed = K510_SPEED_DEFAULT;
|
||||
Stars.speed_min = K510_SPEED_MIN;
|
||||
Stars.speed_max = K510_SPEED_MAX;
|
||||
Stars.colors.resize(1);
|
||||
modes.push_back(Stars);
|
||||
|
||||
mode Flowers;
|
||||
Flowers.name = "Flowers";
|
||||
Flowers.value = K510_MODE_FLOWERS;
|
||||
Flowers.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Flowers.color_mode = MODE_COLORS_RANDOM;
|
||||
Flowers.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Flowers.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Flowers.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Flowers.speed = K510_SPEED_DEFAULT;
|
||||
Flowers.speed_min = K510_SPEED_MIN;
|
||||
Flowers.speed_max = K510_SPEED_MAX;
|
||||
modes.push_back(Flowers);
|
||||
|
||||
mode Roll;
|
||||
Roll.name = "Rainbow Wave";
|
||||
Roll.value = K510_MODE_ROLL;
|
||||
Roll.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Roll.color_mode = MODE_COLORS_NONE;
|
||||
Roll.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Roll.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Roll.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Roll.speed = K510_SPEED_DEFAULT;
|
||||
Roll.speed_min = K510_SPEED_MIN;
|
||||
Roll.speed_max = K510_SPEED_MAX;
|
||||
modes.push_back(Roll);
|
||||
|
||||
mode Wave;
|
||||
Wave.name = "Wave";
|
||||
Wave.value = K510_MODE_WAVE;
|
||||
Wave.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Wave.color_mode = MODE_COLORS_RANDOM;
|
||||
Wave.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Wave.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Wave.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Wave.speed = K510_SPEED_DEFAULT;
|
||||
Wave.speed_min = K510_SPEED_MIN;
|
||||
Wave.speed_max = K510_SPEED_MAX;
|
||||
Wave.colors.resize(1);
|
||||
modes.push_back(Wave);
|
||||
|
||||
mode Cartoon;
|
||||
Cartoon.name = "Cartoon";
|
||||
Cartoon.value = K510_MODE_CARTOON;
|
||||
Cartoon.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Cartoon.color_mode = MODE_COLORS_RANDOM;
|
||||
Cartoon.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Cartoon.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Cartoon.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Cartoon.speed = K510_SPEED_DEFAULT;
|
||||
Cartoon.speed_min = K510_SPEED_MIN;
|
||||
Cartoon.speed_max = K510_SPEED_MAX;
|
||||
Cartoon.colors.resize(1);
|
||||
modes.push_back(Cartoon);
|
||||
|
||||
mode Rain;
|
||||
Rain.name = "Rain";
|
||||
Rain.value = K510_MODE_RAIN;
|
||||
Rain.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Rain.color_mode = MODE_COLORS_RANDOM;
|
||||
Rain.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Rain.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Rain.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Rain.speed = K510_SPEED_DEFAULT;
|
||||
Rain.speed_min = K510_SPEED_MIN;
|
||||
Rain.speed_max = K510_SPEED_MAX;
|
||||
Rain.colors.resize(1);
|
||||
modes.push_back(Rain);
|
||||
|
||||
mode Scan;
|
||||
Scan.name = "Scan";
|
||||
Scan.value = K510_MODE_SCAN;
|
||||
Scan.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Scan.color_mode = MODE_COLORS_NONE;
|
||||
Scan.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Scan.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Scan.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
modes.push_back(Scan);
|
||||
|
||||
mode Surmount;
|
||||
Surmount.name = "Surmount";
|
||||
Surmount.value = K510_MODE_SURMOUNT;
|
||||
Surmount.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Surmount.color_mode = MODE_COLORS_NONE;
|
||||
Surmount.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Surmount.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Surmount.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
modes.push_back(Surmount);
|
||||
|
||||
mode Speed;
|
||||
Speed.name = "Speed";
|
||||
Speed.value = K510_MODE_SPEED;
|
||||
Speed.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_DIRECTION_LR;
|
||||
Speed.color_mode = MODE_COLORS_NONE;
|
||||
Speed.brightness = K510_BRIGHTNESS_DEFAULT;
|
||||
Speed.brightness_min = K510_BRIGHTNESS_MIN;
|
||||
Speed.brightness_max = K510_BRIGHTNESS_MAX;
|
||||
Speed.speed = K510_SPEED_DEFAULT;
|
||||
Speed.speed_min = K510_SPEED_MIN;
|
||||
Speed.speed_max = K510_SPEED_MAX;
|
||||
modes.push_back(Speed);
|
||||
|
||||
SetupZones();
|
||||
ReadAndUpdateCurrentDeviceState();
|
||||
}
|
||||
|
||||
RGBController_LenovoK510::~RGBController_LenovoK510()
|
||||
{
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void RGBController_LenovoK510::SetupZones()
|
||||
{
|
||||
zone default_zone;
|
||||
default_zone.name = "Keyboard";
|
||||
default_zone.type = ZONE_TYPE_SINGLE;
|
||||
default_zone.leds_min = 1;
|
||||
default_zone.leds_max = 1;
|
||||
default_zone.leds_count = 1;
|
||||
default_zone.matrix_map = nullptr;
|
||||
zones.emplace_back(default_zone);
|
||||
|
||||
leds.resize(1);
|
||||
leds[0].name = "Keyboard";
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_LenovoK510::ReadAndUpdateCurrentDeviceState()
|
||||
{
|
||||
mode current_active_mode = controller->GetCurrentState();
|
||||
|
||||
for(std::vector<mode>::size_type i = 0; i < modes.size(); ++i)
|
||||
{
|
||||
if(modes[i].value == current_active_mode.value)
|
||||
{
|
||||
// override the default config of the mode with the current one
|
||||
modes[i].brightness = current_active_mode.brightness;
|
||||
modes[i].speed = current_active_mode.speed;
|
||||
modes[i].color_mode = current_active_mode.color_mode;
|
||||
zones[0].colors[0] = current_active_mode.colors[0];
|
||||
|
||||
if(modes[i].flags & MODE_FLAG_HAS_DIRECTION_LR)
|
||||
{
|
||||
current_active_mode.direction = current_active_mode.direction ? MODE_DIRECTION_LEFT : MODE_DIRECTION_RIGHT;
|
||||
}
|
||||
else if(modes[i].flags & MODE_FLAG_HAS_DIRECTION_UD)
|
||||
{
|
||||
current_active_mode.direction = current_active_mode.direction ? MODE_DIRECTION_UP : MODE_DIRECTION_DOWN;
|
||||
}
|
||||
|
||||
active_mode = (int)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RGBController_LenovoK510::ResizeZone(int /*zone*/, int /*new_size*/)
|
||||
{
|
||||
// Not Supported
|
||||
}
|
||||
|
||||
void RGBController_LenovoK510::DeviceUpdateLEDs()
|
||||
{
|
||||
// Not Supported
|
||||
}
|
||||
|
||||
void RGBController_LenovoK510::UpdateZoneLEDs(int /*zone*/)
|
||||
{
|
||||
// Not Supported
|
||||
}
|
||||
|
||||
void RGBController_LenovoK510::UpdateSingleLED(int /*led*/)
|
||||
{
|
||||
// Not Supported
|
||||
}
|
||||
|
||||
void RGBController_LenovoK510::DeviceUpdateMode()
|
||||
{
|
||||
const mode& active = modes[active_mode];
|
||||
RGBColor color = active.colors.size() > 0 ? active.colors[0] : 0x00;
|
||||
controller->SetMode(active.color_mode, color, active.value, active.brightness, active.speed, active.direction);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_LenovoK510.h |
|
||||
| |
|
||||
| RGBController for Lenovo Legion K510 keyboard |
|
||||
| |
|
||||
| Bnyro 27 Oct 2025 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RGBController.h"
|
||||
#include "LenovoK510Controller.h"
|
||||
|
||||
class RGBController_LenovoK510 : public RGBController
|
||||
{
|
||||
public:
|
||||
RGBController_LenovoK510(LenovoK510Controller* controller_ptr);
|
||||
~RGBController_LenovoK510();
|
||||
|
||||
void SetupZones();
|
||||
void ResizeZone(int zone, int new_size);
|
||||
|
||||
void DeviceUpdateLEDs();
|
||||
void UpdateZoneLEDs(int zone);
|
||||
void UpdateSingleLED(int led);
|
||||
|
||||
void DeviceUpdateMode();
|
||||
|
||||
private:
|
||||
LenovoK510Controller* controller;
|
||||
|
||||
void ReadAndUpdateCurrentDeviceState();
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoM300Controller.cpp |
|
||||
| |
|
||||
| Driver for Lenovo Legion M300 mouse |
|
||||
| |
|
||||
| Wayne Riordan 09 Jan 2024 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <cstring>
|
||||
#include "LenovoM300Controller.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
LenovoM300Controller::LenovoM300Controller(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
|
||||
{
|
||||
device = dev_handle;
|
||||
location = info.path;
|
||||
name = dev_name;
|
||||
}
|
||||
|
||||
LenovoM300Controller::~LenovoM300Controller()
|
||||
{
|
||||
hid_close(device);
|
||||
}
|
||||
|
||||
std::string LenovoM300Controller::GetDeviceLocation()
|
||||
{
|
||||
return("HID: " + location);
|
||||
}
|
||||
|
||||
std::string LenovoM300Controller::GetDeviceName()
|
||||
{
|
||||
return(name);
|
||||
}
|
||||
|
||||
void LenovoM300Controller::SetMode(std::vector<RGBColor> colors, unsigned char mode_value, unsigned int brigthness)
|
||||
{
|
||||
unsigned char usb_buf[M300_DATA_SIZE];
|
||||
memset(usb_buf, 0x00, M300_DATA_SIZE);
|
||||
|
||||
usb_buf[0x01] = 0x25;
|
||||
usb_buf[0x03] = 0x01;
|
||||
usb_buf[0x04] = 0x01;
|
||||
usb_buf[0x05] = 0x0C;
|
||||
|
||||
switch(mode_value)
|
||||
{
|
||||
case M300_MODE_RAINBOW:
|
||||
usb_buf[0x06] = 0x01;
|
||||
usb_buf[0x07] = 0x64;
|
||||
usb_buf[0x09] = 0x0A;
|
||||
usb_buf[0x40] = CalculateFinalByte(usb_buf, 0x0A);
|
||||
break;
|
||||
case M300_MODE_BREATHING:
|
||||
usb_buf[0x06] = 0x02;
|
||||
usb_buf[0x07] = 0x64;
|
||||
usb_buf[0x09] = 0x02;
|
||||
usb_buf[0x0A] = 0x03;
|
||||
usb_buf[0x0C] = RGBGetRValue(colors[0]);
|
||||
usb_buf[0x0D] = RGBGetGValue(colors[0]);
|
||||
usb_buf[0x0E] = RGBGetBValue(colors[0]);
|
||||
usb_buf[0x0F] = RGBGetRValue(colors[1]);
|
||||
usb_buf[0x10] = RGBGetGValue(colors[1]);
|
||||
usb_buf[0x11] = RGBGetBValue(colors[1]);
|
||||
usb_buf[0x40] = CalculateFinalByte(usb_buf, 0x12);
|
||||
break;
|
||||
case M300_MODE_STATIC:
|
||||
usb_buf[0x06] = 0x03;
|
||||
usb_buf[0x07] = brigthness;
|
||||
usb_buf[0x09] = RGBGetRValue(colors[0]);
|
||||
usb_buf[0x0A] = RGBGetGValue(colors[0]);
|
||||
usb_buf[0x0B] = RGBGetBValue(colors[0]);
|
||||
usb_buf[0x40] = CalculateFinalByte(usb_buf, 0x0C);
|
||||
break;
|
||||
case M300_MODE_OFF:
|
||||
default:
|
||||
usb_buf[0x06] = 0x03;
|
||||
usb_buf[0x40] = 0x36;
|
||||
}
|
||||
hid_write(device, usb_buf, M300_DATA_SIZE);
|
||||
}
|
||||
|
||||
unsigned char LenovoM300Controller::CalculateFinalByte(unsigned char* ptr, int count)
|
||||
{
|
||||
unsigned char final_byte = 0;
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
final_byte += ptr[i];
|
||||
}
|
||||
return final_byte;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoM300Controller.h |
|
||||
| |
|
||||
| Driver for Lenovo Legion M300 mouse |
|
||||
| |
|
||||
| Wayne Riordan 09 Jan 2024 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
|
||||
#define M300_DATA_SIZE 0x41
|
||||
#define M300_MAX_BRIGTH 0x64
|
||||
#define M300_MIN_BRIGHT 0x01
|
||||
|
||||
enum
|
||||
{
|
||||
M300_MODE_OFF = 0x00,
|
||||
M300_MODE_RAINBOW = 0x01,
|
||||
M300_MODE_BREATHING = 0x02,
|
||||
M300_MODE_STATIC = 0X03
|
||||
};
|
||||
|
||||
class LenovoM300Controller
|
||||
{
|
||||
public:
|
||||
LenovoM300Controller(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
|
||||
~LenovoM300Controller();
|
||||
|
||||
std::string GetDeviceLocation();
|
||||
std::string GetDeviceName();
|
||||
|
||||
void SetMode(std::vector<RGBColor> colors, unsigned char mode_value, unsigned int brightness);
|
||||
|
||||
protected:
|
||||
hid_device* device;
|
||||
|
||||
private:
|
||||
std::string location;
|
||||
std::string name;
|
||||
|
||||
unsigned char CalculateFinalByte(unsigned char* ptr, int count);
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoM300ControllerDetect.cpp |
|
||||
| |
|
||||
| Detector for Lenovo Legion M300 mouse |
|
||||
| |
|
||||
| Wayne Riordan 09 Jan 2024 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "Detector.h"
|
||||
#include "RGBController_LenovoM300.h"
|
||||
#include "LenovoM300Controller.h"
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Lenovo vendor, product, usage and page IDs |
|
||||
\*---------------------------------------------------------*/
|
||||
#define LENOVO_VID 0x17EF
|
||||
#define LEGION_M300_PID 0x60E4
|
||||
#define LENOVO_USAGE 0X01
|
||||
#define LENOVO_PAGE 0XFF01
|
||||
|
||||
void DetectLenovoLegionM300Controllers(hid_device_info* info, const std::string& name)
|
||||
{
|
||||
hid_device* dev = hid_open_path(info->path);
|
||||
|
||||
if(dev)
|
||||
{
|
||||
LenovoM300Controller* controller = new LenovoM300Controller(dev, *info, name);
|
||||
RGBController_LenovoM300* rgb_controller = new RGBController_LenovoM300(controller);
|
||||
|
||||
ResourceManager::get()->RegisterRGBController(rgb_controller);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion M300", DetectLenovoLegionM300Controllers, LENOVO_VID, LEGION_M300_PID, LENOVO_PAGE, LENOVO_USAGE);
|
||||
@@ -0,0 +1,120 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_LenovoM300.cpp |
|
||||
| |
|
||||
| RGBController for Lenovo Legion M300 mouse |
|
||||
| |
|
||||
| Wayne Riordan 09 Jan 2024 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "RGBController_LenovoM300.h"
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name Lenovo Legion M300
|
||||
@category Mouse
|
||||
@type USB
|
||||
@save :robot:
|
||||
@direct :x:
|
||||
@effects :white_check_mark:
|
||||
@detectors DetectLenovoLegionM300Controllers
|
||||
@comment
|
||||
\*-------------------------------------------------------------------*/
|
||||
|
||||
RGBController_LenovoM300::RGBController_LenovoM300(LenovoM300Controller* controller_ptr)
|
||||
{
|
||||
controller = controller_ptr;
|
||||
|
||||
name = controller->GetDeviceName();
|
||||
vendor = "Lenovo";
|
||||
type = DEVICE_TYPE_MOUSE;
|
||||
description = "Lenovo M300 Device";
|
||||
location = controller->GetDeviceLocation();
|
||||
|
||||
mode Static;
|
||||
Static.name = "Static";
|
||||
Static.value = M300_MODE_STATIC;
|
||||
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Static.brightness_max = M300_MAX_BRIGTH;
|
||||
Static.brightness_min = M300_MIN_BRIGHT;
|
||||
Static.brightness = M300_MAX_BRIGTH;
|
||||
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Static.colors.resize(1);
|
||||
modes.push_back(Static);
|
||||
|
||||
mode Off;
|
||||
Off.name = "Off";
|
||||
Off.value = M300_MODE_OFF;
|
||||
Off.flags = MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Off.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(Off);
|
||||
|
||||
mode Breathing;
|
||||
Breathing.name = "Breathing";
|
||||
Breathing.value = M300_MODE_BREATHING;
|
||||
Breathing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Breathing.brightness_max = M300_MAX_BRIGTH;
|
||||
Breathing.brightness_min = M300_MIN_BRIGHT;
|
||||
Breathing.brightness = M300_MAX_BRIGTH;
|
||||
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Breathing.colors.resize(2);
|
||||
modes.push_back(Breathing);
|
||||
|
||||
mode Spectrum;
|
||||
Spectrum.name = "Spectrum Cycle";
|
||||
Spectrum.value = M300_MODE_RAINBOW;
|
||||
Spectrum.flags = MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Spectrum.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(Spectrum);
|
||||
|
||||
SetupZones();
|
||||
}
|
||||
|
||||
RGBController_LenovoM300::~RGBController_LenovoM300()
|
||||
{
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void RGBController_LenovoM300::SetupZones()
|
||||
{
|
||||
zone default_zone;
|
||||
default_zone.name = "Mouse";
|
||||
default_zone.type = ZONE_TYPE_SINGLE;
|
||||
default_zone.leds_min = 1;
|
||||
default_zone.leds_max = 1;
|
||||
default_zone.leds_count = 1;
|
||||
default_zone.matrix_map = nullptr;
|
||||
zones.emplace_back(default_zone);
|
||||
|
||||
leds.resize(1);
|
||||
leds[0].name = "LED 1";
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_LenovoM300::ResizeZone(int /*zone*/, int /*new_size*/)
|
||||
{
|
||||
// Not Supported
|
||||
}
|
||||
|
||||
void RGBController_LenovoM300::DeviceUpdateLEDs()
|
||||
{
|
||||
const mode& active = modes[active_mode];
|
||||
controller->SetMode(active.colors, active.value, active.brightness);
|
||||
}
|
||||
|
||||
void RGBController_LenovoM300::UpdateZoneLEDs(int /*zone*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_LenovoM300::UpdateSingleLED(int /*led*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_LenovoM300::DeviceUpdateMode()
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_LenovoM300.h |
|
||||
| |
|
||||
| RGBController for Lenovo Legion M300 mouse |
|
||||
| |
|
||||
| Wayne Riordan 09 Jan 2024 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RGBController.h"
|
||||
#include "LenovoM300Controller.h"
|
||||
|
||||
class RGBController_LenovoM300 : public RGBController
|
||||
{
|
||||
public:
|
||||
RGBController_LenovoM300(LenovoM300Controller* controller_ptr);
|
||||
~RGBController_LenovoM300();
|
||||
|
||||
void SetupZones();
|
||||
void ResizeZone(int zone, int new_size);
|
||||
|
||||
void DeviceUpdateLEDs();
|
||||
void UpdateZoneLEDs(int zone);
|
||||
void UpdateSingleLED(int led);
|
||||
|
||||
void DeviceUpdateMode();
|
||||
|
||||
private:
|
||||
LenovoM300Controller* controller;
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoUSBController.cpp |
|
||||
| |
|
||||
| Driver for Lenovo USB devices |
|
||||
| |
|
||||
| Cooper Hall (geobot19) 17 Apr 2022 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "LenovoUSBController.h"
|
||||
#include "LogManager.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
LenovoUSBController::LenovoUSBController(hid_device* dev_handle, const char* path, uint16_t in_pid, std::string dev_name)
|
||||
{
|
||||
dev = dev_handle;
|
||||
location = path;
|
||||
pid = in_pid;
|
||||
name = dev_name;
|
||||
|
||||
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, (uint8_t) (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, (uint8_t) (LENOVO_ZONE_ID_0+zone_num), 1, 0, led_num, (uint8_t) (RGBGetRValue(color)), (uint8_t) (RGBGetGValue(color)), (uint8_t) (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);
|
||||
}
|
||||
|
||||
vector<uint8_t> LenovoUSBController::getInformation(uint8_t information_id)
|
||||
{
|
||||
uint8_t buffer[LENOVO_HID_PACKET_SIZE] = {LENOVO_INSTRUCTION_START, information_id};
|
||||
hid_send_feature_report(dev, buffer, LENOVO_HID_PACKET_SIZE);
|
||||
uint8_t read_buffer[LENOVO_HID_PACKET_SIZE] = {LENOVO_INSTRUCTION_START};
|
||||
int num_bytes = hid_get_feature_report(dev, read_buffer, LENOVO_HID_PACKET_SIZE);
|
||||
if(num_bytes > 0)
|
||||
{
|
||||
vector<uint8_t> response(&read_buffer[0], &read_buffer[num_bytes]);
|
||||
return response;
|
||||
}
|
||||
return vector<uint8_t>();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoUSBController.h |
|
||||
| |
|
||||
| Driver for Lenovo USB devices |
|
||||
| |
|
||||
| Cooper Hall (geobot19) 17 Apr 2022 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "LogManager.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, std::string dev_name);
|
||||
~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();
|
||||
std::vector<uint8_t> getInformation(uint8_t information_id);
|
||||
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
|
||||
@@ -0,0 +1,477 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_Lenovo_USB.cpp |
|
||||
| |
|
||||
| RGBController for Lenovo USB devices |
|
||||
| |
|
||||
| Cooper Hall (geobot19) 17 Apr 2022 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "LenovoDevices.h"
|
||||
#include "RGBController_LenovoUSB.h"
|
||||
#include "LogManager.h"
|
||||
|
||||
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
|
||||
|
||||
If you have other models beside the Legion 7 gen 6 and want to test if RGB can be added to OpenRGB,
|
||||
you can do so if you're on Windows by running
|
||||
[this Powershell script](https://gitlab.com/pvazny/legion7-rgb-ps) with the `-test` parameter:
|
||||
|
||||
```powershell
|
||||
legion7-rgb.ps1 -test -v 0x048D -p 0xC935 -up 0xFF89 -u 0x07 -c 0xa1 -start 0x15 -stop 0xa1
|
||||
```
|
||||
|
||||
This script will iterate through each LED one by one, in bank `$c = 0xa1`, between IDs
|
||||
`-start 0x15` and `-stop 0xa1`, on the HID device with VID `-v 0x048D` PID `-p 0xC935` usage page
|
||||
`-up 0xFF89` and usage `-u 0x07`. It will default to the Legion 7 Gen 6 description, however you can
|
||||
enter a new description for each LED and at the end it will generate the differences.
|
||||
|
||||
To check if you have an eligible HID device that could potentially be iterated by the script please
|
||||
open the powershell command prompt and executre the follow:
|
||||
|
||||
```powershell
|
||||
Get-PnpDevice -Class 'HIDClass' | ForEach-Object { [PSCustomObject]@{Name = $_.FriendlyName; InstanceId = $_.InstanceId; HardwareId = ($_.HardwareId | Where-Object {$_ -like 'HID_DEVICE_UP:*' })}} | Where-Object { $_.HardwareId -ne $null } | Sort-Object InstanceId
|
||||
```
|
||||
|
||||
If the script is successful please create a [new device issue](https://gitlab.com/CalcProgrammer1/OpenRGB/-/issues/new?issuable_template=New%20Device#)
|
||||
and attach the relevant details to request support for your device.
|
||||
\*-------------------------------------------------------------------*/
|
||||
|
||||
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";
|
||||
|
||||
if(LogManager::get()->getLoglevel() >= LL_TRACE)
|
||||
{
|
||||
DumpControllerInformation();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> response;
|
||||
|
||||
/*-----------------------*\
|
||||
|Default to ANSI keyboard |
|
||||
\*-----------------------*/
|
||||
keyboard_type = ANSI;
|
||||
|
||||
switch(controller->getPid())
|
||||
{
|
||||
case LEGION_Y740:
|
||||
response = controller->getInformation(0x01);
|
||||
if(response.size() > 4 && response[4] <= 100)
|
||||
{
|
||||
chasis_size = FIFTEEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
chasis_size = SEVENTEEN;
|
||||
}
|
||||
|
||||
response = controller->getInformation(0x04);
|
||||
if(response.size() > 4)
|
||||
{
|
||||
if(response[4] >= 16 && response[4] <=48)
|
||||
{
|
||||
keyboard_type = ISO;
|
||||
}
|
||||
}
|
||||
|
||||
description = "Lenovo Y740 " + sizeToString(chasis_size) + " " + keyboardToString(keyboard_type);
|
||||
|
||||
break;
|
||||
|
||||
case LEGION_Y750:
|
||||
response = controller->getInformation(0x04);
|
||||
if(response.size() > 4)
|
||||
{
|
||||
if(response[4] == 41)
|
||||
{
|
||||
keyboard_type = JAPAN;
|
||||
}
|
||||
else if(response[4] >= 16 && response[4] <=40)
|
||||
{
|
||||
keyboard_type = ISO;
|
||||
}
|
||||
}
|
||||
|
||||
description = "Lenovo Y750 " + keyboardToString(keyboard_type);
|
||||
|
||||
break;
|
||||
|
||||
case LEGION_Y750S:
|
||||
response = controller->getInformation(0x01);
|
||||
if(response.size() > 4)
|
||||
{
|
||||
if(response[4] == 0x97)
|
||||
{
|
||||
keyboard_type = JAPAN;
|
||||
}
|
||||
else if(response[4] == 0x91)
|
||||
{
|
||||
keyboard_type = ISO;
|
||||
}
|
||||
}
|
||||
|
||||
description = "Lenovo Y750S " + keyboardToString(keyboard_type);
|
||||
|
||||
break;
|
||||
|
||||
case LEGION_Y760:
|
||||
response = controller->getInformation(0x07);
|
||||
if(response.size() > 4)
|
||||
{
|
||||
if(response[4] == 41)
|
||||
{
|
||||
keyboard_type = JAPAN;
|
||||
}
|
||||
else if(response[4] >= 16 && response[4] <=40)
|
||||
{
|
||||
keyboard_type = ISO;
|
||||
}
|
||||
}
|
||||
|
||||
description = "Lenovo Y760 " + keyboardToString(keyboard_type);
|
||||
|
||||
break;
|
||||
|
||||
case LEGION_Y760S:
|
||||
response = controller->getInformation(0x01);
|
||||
if(response.size() > 4)
|
||||
{
|
||||
if(response[4] == 0x97)
|
||||
{
|
||||
keyboard_type = JAPAN;
|
||||
}
|
||||
else if(response[4] == 0x8F)
|
||||
{
|
||||
keyboard_type = ISO;
|
||||
}
|
||||
}
|
||||
|
||||
description = "Lenovo Y760S " + keyboardToString(keyboard_type);
|
||||
}
|
||||
|
||||
LOG_DEBUG("[Lenovo Controller] detected: %s", description.c_str());
|
||||
|
||||
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_Y740:
|
||||
switch(chasis_size)
|
||||
{
|
||||
case FIFTEEN:
|
||||
switch(keyboard_type)
|
||||
{
|
||||
case ISO:
|
||||
lenovo_zones.push_back(lenovo_legion_Y740_15_kbd_iso);
|
||||
break;
|
||||
|
||||
default:
|
||||
lenovo_zones.push_back(lenovo_legion_Y740_15_kbd_ansi);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEVENTEEN:
|
||||
default:
|
||||
switch(keyboard_type)
|
||||
{
|
||||
case ISO:
|
||||
lenovo_zones.push_back(lenovo_legion_Y740_17_kbd_iso);
|
||||
break;
|
||||
|
||||
default:
|
||||
lenovo_zones.push_back(lenovo_legion_Y740_17_kbd_ansi);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
lenovo_zones.push_back(lenovo_legion_Y740_logo);
|
||||
lenovo_zones.push_back(lenovo_legion_Y740_pwrbtn);
|
||||
lenovo_zones.push_back(lenovo_legion_Y740_vents);
|
||||
lenovo_zones.push_back(lenovo_legion_Y740_ports);
|
||||
break;
|
||||
|
||||
case LEGION_Y750:
|
||||
switch(keyboard_type)
|
||||
{
|
||||
case JAPAN:
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_kbd_jp);
|
||||
break;
|
||||
|
||||
case ISO:
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_kbd_iso);
|
||||
break;
|
||||
|
||||
default:
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_kbd_ansi);
|
||||
break;
|
||||
}
|
||||
lenovo_zones.push_back(lenovo_legion_Y750_logo);
|
||||
lenovo_zones.push_back(lenovo_legion_Y750_vents);
|
||||
lenovo_zones.push_back(lenovo_legion_Y750_neon);
|
||||
break;
|
||||
case LEGION_Y750S:
|
||||
case LEGION_Y760S:
|
||||
switch(keyboard_type)
|
||||
{
|
||||
case JAPAN:
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_kbd_jp);
|
||||
break;
|
||||
|
||||
case ISO:
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_kbd_iso);
|
||||
break;
|
||||
|
||||
default:
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_kbd_ansi);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LEGION_Y760:
|
||||
switch(keyboard_type)
|
||||
{
|
||||
case JAPAN:
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_kbd_jp);
|
||||
break;
|
||||
|
||||
case ISO:
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_kbd_iso);
|
||||
break;
|
||||
|
||||
default:
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_kbd_ansi);
|
||||
break;
|
||||
}
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_logo);
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_vent_left);
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_vent_right);
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_vent_back_right);
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_vent_back_left);
|
||||
lenovo_zones.push_back(lenovo_legion_Y760_neon);
|
||||
break;
|
||||
case LEGION_S7GEN7:
|
||||
lenovo_zones.push_back(legion7_gen7and8_kbd_ansi);
|
||||
break;
|
||||
case LEGION_7GEN7:
|
||||
lenovo_zones.push_back(legion7_gen7and8_kbd_ansi);
|
||||
lenovo_zones.push_back(lenovo_legion_7gen7_logo);
|
||||
lenovo_zones.push_back(lenovo_legion_7gen7_vents);
|
||||
lenovo_zones.push_back(legion7_gen7and8_neon);
|
||||
break;
|
||||
case LEGION_7GEN8:
|
||||
case LEGION_7GEN9:
|
||||
case LEGION_7GEN9_H:
|
||||
lenovo_zones.push_back(legion7_gen7and8_kbd_ansi);
|
||||
lenovo_zones.push_back(legion7_gen7and8_neon);
|
||||
break;
|
||||
case LEGION_S7GEN8:
|
||||
lenovo_zones.push_back(legion7_gen7and8_kbd_ansi);
|
||||
break;
|
||||
}
|
||||
|
||||
for(unsigned 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;
|
||||
|
||||
LOG_DEBUG("[Lenovo Controller] adding zone: %s with %u LEDs", new_zone.name.c_str(), 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 = (unsigned int *) lenovo_zones[i].matrix_map;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_zone.matrix_map = NULL;
|
||||
}
|
||||
|
||||
zones.push_back(new_zone);
|
||||
|
||||
for(unsigned int led_idx = lenovo_zones[i].start; led_idx <= lenovo_zones[i].end; led_idx++ )
|
||||
{
|
||||
led new_led;
|
||||
new_led.name = lenovo_zones[i].leds[led_idx].name;
|
||||
new_led.value = ( lenovo_zones[i].id << 8 ) + lenovo_zones[i].leds[led_idx].led_num;
|
||||
leds.push_back(new_led);
|
||||
}
|
||||
}
|
||||
|
||||
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 != (int)NA)
|
||||
{
|
||||
controller->setSingleLED(leds[led].value >> 8, leds[led].value & 0xFF, colors[led]);
|
||||
}
|
||||
}
|
||||
|
||||
void RGBController_LenovoUSB::UpdateZoneLEDs(int zone)
|
||||
{
|
||||
uint8_t zone_id = zones[zone].leds_count > 0 ? leds[zones[zone].start_idx].value >> 8 : 0;
|
||||
vector<pair<uint8_t, RGBColor>> color_map;
|
||||
|
||||
for(unsigned int i = 0; i < zones[zone].leds_count; i++)
|
||||
{
|
||||
int index = zones[zone].start_idx+i;
|
||||
|
||||
color_map.push_back({(uint8_t)leds[index].value & 0xFF, colors[index]});
|
||||
}
|
||||
|
||||
color_map.shrink_to_fit();
|
||||
|
||||
controller->setZoneLeds(zone_id, color_map);
|
||||
}
|
||||
|
||||
void RGBController_LenovoUSB::DeviceUpdateLEDs()
|
||||
{
|
||||
uint8_t zone_id = 0;
|
||||
uint8_t prev_zone_id = 0;
|
||||
vector<pair<uint8_t, RGBColor>> curr_color_map;
|
||||
|
||||
for(unsigned int i = 0; i < leds.size(); i++)
|
||||
{
|
||||
zone_id = leds[i].value >> 8;
|
||||
|
||||
if((zone_id != prev_zone_id) && (prev_zone_id != 0))
|
||||
{
|
||||
controller->setZoneLeds(prev_zone_id, curr_color_map);
|
||||
curr_color_map.clear();
|
||||
}
|
||||
|
||||
prev_zone_id = zone_id;
|
||||
|
||||
curr_color_map.push_back({(uint8_t)(leds[i].value & 0xFF), colors[i]});
|
||||
}
|
||||
|
||||
if(curr_color_map.size() > 0)
|
||||
{
|
||||
controller->setZoneLeds(prev_zone_id, curr_color_map);
|
||||
}
|
||||
}
|
||||
|
||||
void RGBController_LenovoUSB::DeviceUpdateMode()
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| This device does not support multiple modes |
|
||||
\*---------------------------------------------------------*/
|
||||
}
|
||||
|
||||
void RGBController_LenovoUSB::DeviceSaveMode()
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| This device does not support saving or multiple modes |
|
||||
\*---------------------------------------------------------*/
|
||||
}
|
||||
|
||||
std::string RGBController_LenovoUSB::ConvertBytesToHex(const std::vector<uint8_t> &input)
|
||||
{
|
||||
std::ostringstream temp_stream;
|
||||
for(const uint8_t &oneInputByte : input)
|
||||
{
|
||||
temp_stream << (temp_stream.tellp()==0 ? "" : " ") << std::setw(2) << std::setfill('0') << std::hex << (int)oneInputByte;
|
||||
}
|
||||
return temp_stream.str();
|
||||
}
|
||||
|
||||
std::string RGBController_LenovoUSB::keyboardToString(LENOVO_KEYBOARD kb)
|
||||
{
|
||||
switch(kb)
|
||||
{
|
||||
case LENOVO_KEYBOARD::ANSI:
|
||||
return "ANSI";
|
||||
case LENOVO_KEYBOARD::ISO:
|
||||
return "ISO";
|
||||
case LENOVO_KEYBOARD::JAPAN:
|
||||
return "JAPAN";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string RGBController_LenovoUSB::sizeToString(LENOVO_SIZE size)
|
||||
{
|
||||
switch(size)
|
||||
{
|
||||
case LENOVO_SIZE::FIFTEEN:
|
||||
return "15\"";
|
||||
case LENOVO_SIZE::SEVENTEEN:
|
||||
return "17\"";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void RGBController_LenovoUSB::DumpControllerInformation()
|
||||
{
|
||||
for(uint8_t i=1;i<=7;i++)
|
||||
{
|
||||
std::vector<uint8_t> response = controller->getInformation(i);
|
||||
LOG_TRACE("[Lenovo Controller] Read values [%02x]: %s", i, ConvertBytesToHex(response).c_str());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_Lenovo_USB.h |
|
||||
| |
|
||||
| RGBController for Lenovo USB devices |
|
||||
| |
|
||||
| Cooper Hall (geobot19) 17 Apr 2022 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "LenovoDevices.h"
|
||||
#include "LenovoUSBController.h"
|
||||
#include "RGBController.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 DeviceUpdateMode();
|
||||
void DeviceSaveMode();
|
||||
|
||||
private:
|
||||
std::string ConvertBytesToHex(const std::vector<uint8_t> &input);
|
||||
std::string keyboardToString(LENOVO_KEYBOARD kb);
|
||||
std::string sizeToString(LENOVO_SIZE size);
|
||||
void DumpControllerInformation();
|
||||
|
||||
LENOVO_KEYBOARD keyboard_type;
|
||||
LENOVO_SIZE chasis_size;
|
||||
|
||||
LenovoUSBController *controller;
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoUSBControllerDetect.cpp |
|
||||
| |
|
||||
| Detector for Lenovo USB devices |
|
||||
| |
|
||||
| Cooper Hall (geobot19) 17 Apr 2022 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <hidapi.h>
|
||||
#include "Detector.h"
|
||||
#include "LenovoDevices.h"
|
||||
#include "RGBController_LenovoUSB.h"
|
||||
#include "RGBController_Lenovo_Gen7_8.h"
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| vendor IDs |
|
||||
\*-----------------------------------------------------*/
|
||||
#define ITE_VID 0x048D
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Interface, Usage, and Usage Page |
|
||||
\*-----------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
LENOVO_PAGE = 0xFF89,
|
||||
LENOVO_USAGE = 0x07
|
||||
};
|
||||
|
||||
void DetectLenovoLegionUSBControllers(hid_device_info* info, const std::string& name)
|
||||
{
|
||||
hid_device* dev = hid_open_path(info->path);
|
||||
|
||||
if(dev)
|
||||
{
|
||||
LenovoUSBController* controller = new LenovoUSBController(dev, info->path, info->product_id, name);
|
||||
RGBController_LenovoUSB* rgb_controller = new RGBController_LenovoUSB(controller);
|
||||
|
||||
ResourceManager::get()->RegisterRGBController(rgb_controller);
|
||||
}
|
||||
}
|
||||
|
||||
void DetectLenovoLegionUSBControllersGen7And8(hid_device_info* info, const std::string& name)
|
||||
{
|
||||
hid_device* dev = hid_open_path(info->path);
|
||||
|
||||
if(dev)
|
||||
{
|
||||
LenovoGen7And8USBController* controller = new LenovoGen7And8USBController(dev, info->path, info->product_id, name);
|
||||
LenovoRGBController_Gen7_8* rgb_controller = new LenovoRGBController_Gen7_8(controller);
|
||||
|
||||
ResourceManager::get()->RegisterRGBController(rgb_controller);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion Y740", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y740, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 5", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y750, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7S Gen 5", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y750S, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 6", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y760, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7S Gen 6", DetectLenovoLegionUSBControllers, ITE_VID, LEGION_Y760S, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7S Gen 7", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_S7GEN7, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 7", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_7GEN7, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 8", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_7GEN8, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7S Gen 8", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_S7GEN8, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 9", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_7GEN9, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 9", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_7GEN9_H, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 7 Gen 10", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_7GEN10, LENOVO_PAGE, LENOVO_USAGE);
|
||||
REGISTER_HID_DETECTOR_PU("Lenovo Legion 5 Gen 10", DetectLenovoLegionUSBControllersGen7And8, ITE_VID, LEGION_5GEN10, LENOVO_PAGE, LENOVO_USAGE);
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoUSBController_Gen7_8.cpp |
|
||||
| |
|
||||
| Driver for Lenovo Gen7 and Gen8 devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include "LenovoDevices.h"
|
||||
#include "LenovoUSBController_Gen7_8.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void SetGen10PayloadLength(uint16_t pid, uint8_t* buffer, uint16_t payload_length)
|
||||
{
|
||||
if(pid != LEGION_7GEN10 && pid != LEGION_5GEN10)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
buffer[2] = payload_length & 0xFF;
|
||||
buffer[3] = (payload_length >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
static bool UsesGen10PacketFormat(uint16_t pid)
|
||||
{
|
||||
return pid == LEGION_7GEN10 || pid == LEGION_5GEN10;
|
||||
}
|
||||
|
||||
LenovoGen7And8USBController::LenovoGen7And8USBController(hid_device* dev_handle, const char* path, uint16_t in_pid, std::string dev_name)
|
||||
{
|
||||
dev = dev_handle;
|
||||
location = path;
|
||||
pid = in_pid;
|
||||
name = dev_name;
|
||||
}
|
||||
|
||||
LenovoGen7And8USBController::~LenovoGen7And8USBController()
|
||||
{
|
||||
hid_close(dev);
|
||||
}
|
||||
|
||||
uint16_t LenovoGen7And8USBController::getPid()
|
||||
{
|
||||
return pid;
|
||||
}
|
||||
|
||||
string LenovoGen7And8USBController::getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
string LenovoGen7And8USBController::getLocation()
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
void LenovoGen7And8USBController::setLedsByGroup(uint8_t profile_id, vector<led_group> led_groups)
|
||||
{
|
||||
if(led_groups.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Some devices require many groups for per-key updates. |
|
||||
| Send as many groups as fit in one report, then continue |
|
||||
| in additional reports. |
|
||||
\*---------------------------------------------------------*/
|
||||
size_t group = 0;
|
||||
while(group < led_groups.size())
|
||||
{
|
||||
uint8_t buffer[PACKET_SIZE];
|
||||
memset(buffer, 0x00, PACKET_SIZE);
|
||||
|
||||
size_t i = 0;
|
||||
buffer[i++] = REPORT_ID;
|
||||
buffer[i++] = SAVE_PROFILE;
|
||||
buffer[i++] = 0xC0;
|
||||
buffer[i++] = 0x03;
|
||||
buffer[i++] = profile_id;
|
||||
buffer[i++] = 0x01;
|
||||
buffer[i++] = 0x01;
|
||||
|
||||
for(; group < led_groups.size() && i < PACKET_SIZE - 21; group++)
|
||||
{
|
||||
buffer[i++] = (uint8_t)group + 1; //Group index
|
||||
buffer[i++] = 0x06;
|
||||
buffer[i++] = 0x01;
|
||||
buffer[i++] = led_groups[group].mode;
|
||||
buffer[i++] = 0x02;
|
||||
buffer[i++] = led_groups[group].speed;
|
||||
buffer[i++] = 0x03;
|
||||
buffer[i++] = led_groups[group].spin;
|
||||
buffer[i++] = 0x04;
|
||||
buffer[i++] = led_groups[group].direction;
|
||||
buffer[i++] = 0x05;
|
||||
buffer[i++] = led_groups[group].color_mode;
|
||||
buffer[i++] = 0x06;
|
||||
buffer[i++] = 0x00;
|
||||
|
||||
buffer[i++] = (uint8_t)led_groups[group].colors.size();
|
||||
for(RGBColor c : led_groups[group].colors)
|
||||
{
|
||||
buffer[i++] = RGBGetRValue(c);
|
||||
buffer[i++] = RGBGetGValue(c);
|
||||
buffer[i++] = RGBGetBValue(c);
|
||||
}
|
||||
|
||||
vector<uint16_t> leds = led_groups[group].leds;
|
||||
size_t led_count = min(leds.size(), (PACKET_SIZE - i)/2);
|
||||
buffer[i++] = (uint8_t)led_count;
|
||||
uint8_t* byte_ptr = reinterpret_cast<uint8_t*>(leds.data());
|
||||
std::copy(byte_ptr, byte_ptr + led_count * sizeof(uint16_t), buffer + i);
|
||||
i+= led_count * sizeof(uint16_t);
|
||||
}
|
||||
|
||||
if(UsesGen10PacketFormat(pid))
|
||||
{
|
||||
SetGen10PayloadLength(pid, buffer, static_cast<uint16_t>(i - 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[2] = (uint8_t)i;
|
||||
}
|
||||
sendFeatureReport(buffer, PACKET_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void LenovoGen7And8USBController::setLedsDirectOn(uint8_t profile_id)
|
||||
{
|
||||
uint8_t buffer[PACKET_SIZE];
|
||||
memset(buffer, 0x00, PACKET_SIZE);
|
||||
|
||||
size_t i = 0;
|
||||
buffer[i++] = REPORT_ID;
|
||||
buffer[i++] = SET_DIRECT_MODE;
|
||||
buffer[i++] = 0xC0;
|
||||
buffer[i++] = 0x03;
|
||||
buffer[i++] = 0x01;
|
||||
buffer[i++] = profile_id;
|
||||
|
||||
SetGen10PayloadLength(pid, buffer, 2);
|
||||
sendFeatureReport(buffer, PACKET_SIZE);
|
||||
}
|
||||
|
||||
void LenovoGen7And8USBController::setLedsDirectOff(uint8_t profile_id)
|
||||
{
|
||||
uint8_t buffer[PACKET_SIZE];
|
||||
memset(buffer, 0x00, PACKET_SIZE);
|
||||
|
||||
size_t i = 0;
|
||||
buffer[i++] = REPORT_ID;
|
||||
buffer[i++] = SET_DIRECT_MODE;
|
||||
buffer[i++] = 0xC0;
|
||||
buffer[i++] = 0x03;
|
||||
buffer[i++] = 0x02;
|
||||
buffer[i++] = profile_id;
|
||||
|
||||
SetGen10PayloadLength(pid, buffer, 2);
|
||||
sendFeatureReport(buffer, PACKET_SIZE);
|
||||
}
|
||||
|
||||
void LenovoGen7And8USBController::setLedsDirect(std::vector<led> &leds, std::vector<RGBColor> &colors)
|
||||
{
|
||||
if(UsesGen10PacketFormat(pid))
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| Gen10 uses 0x07/A1 direct updates, with payload length |
|
||||
| stored in bytes 2-3. |
|
||||
\*---------------------------------------------------------*/
|
||||
uint8_t buffer[PACKET_SIZE];
|
||||
memset(buffer, 0x00, PACKET_SIZE);
|
||||
|
||||
size_t i = 0;
|
||||
buffer[i++] = REPORT_ID;
|
||||
buffer[i++] = DIRECT_MODE;
|
||||
buffer[i++] = 0x00;
|
||||
buffer[i++] = 0x00;
|
||||
|
||||
size_t count = 0;
|
||||
for(size_t index = 0; index < leds.size() && index < colors.size() && i + 5 <= PACKET_SIZE; index++)
|
||||
{
|
||||
buffer[i++] = leds[index].value & 0xFF;
|
||||
buffer[i++] = leds[index].value >> 8 & 0xFF;
|
||||
buffer[i++] = RGBGetRValue(colors[index]);
|
||||
buffer[i++] = RGBGetGValue(colors[index]);
|
||||
buffer[i++] = RGBGetBValue(colors[index]);
|
||||
count++;
|
||||
}
|
||||
|
||||
SetGen10PayloadLength(pid, buffer, static_cast<uint16_t>(count * 5));
|
||||
sendFeatureReport(buffer, PACKET_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t buffer[PACKET_SIZE];
|
||||
memset(buffer, 0x00, PACKET_SIZE);
|
||||
|
||||
size_t i = 0;
|
||||
buffer[i++] = REPORT_ID;
|
||||
buffer[i++] = DIRECT_MODE;
|
||||
buffer[i++] = 0xC0;
|
||||
buffer[i++] = 0x03;
|
||||
|
||||
for(size_t index = 0; index < leds.size() && i < PACKET_SIZE; index++)
|
||||
{
|
||||
buffer[i++] = leds[index].value & 0xFF;
|
||||
buffer[i++] = leds[index].value >> 8 & 0xFF;
|
||||
buffer[i++] = RGBGetRValue(colors[index]);
|
||||
buffer[i++] = RGBGetGValue(colors[index]);
|
||||
buffer[i++] = RGBGetBValue(colors[index]);
|
||||
}
|
||||
|
||||
sendFeatureReport(buffer, PACKET_SIZE);
|
||||
}
|
||||
|
||||
void LenovoGen7And8USBController::setLedsAllOff(uint8_t profile_id)
|
||||
{
|
||||
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SAVE_PROFILE, 0xC0, 0x03, profile_id, 0x01, 0x01};
|
||||
|
||||
SetGen10PayloadLength(pid, buffer, 3);
|
||||
sendFeatureReport(buffer, PACKET_SIZE);
|
||||
}
|
||||
|
||||
uint8_t LenovoGen7And8USBController::getCurrentProfileId()
|
||||
{
|
||||
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_ACTIVE_PROFILE, 0xC0, 0x03};
|
||||
|
||||
SetGen10PayloadLength(pid, buffer, 1);
|
||||
vector<uint8_t> response = getFeatureReport(buffer, PACKET_SIZE);
|
||||
|
||||
return response.size()>4?response[4]:0x01;
|
||||
}
|
||||
|
||||
uint8_t LenovoGen7And8USBController::getCurrentBrightness()
|
||||
{
|
||||
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_BRIGHTNESS, 0xC0, 0x03};
|
||||
|
||||
SetGen10PayloadLength(pid, buffer, 1);
|
||||
vector<uint8_t> response = getFeatureReport(buffer, PACKET_SIZE);
|
||||
|
||||
return response.size()>4?response[4]:0x00;
|
||||
}
|
||||
|
||||
|
||||
void LenovoGen7And8USBController::setBrightness(uint8_t brightness)
|
||||
{
|
||||
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SET_BRIGHTNESS, 0xC0, 0x03, brightness};
|
||||
|
||||
SetGen10PayloadLength(pid, buffer, 1);
|
||||
sendFeatureReport(buffer, PACKET_SIZE);
|
||||
}
|
||||
|
||||
void LenovoGen7And8USBController::switchProfileTo(uint8_t profile_id)
|
||||
{
|
||||
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, SWITCH_PROFILE, 0xC0, 0x03, profile_id};
|
||||
|
||||
SetGen10PayloadLength(pid, buffer, 1);
|
||||
sendFeatureReport(buffer, PACKET_SIZE);
|
||||
}
|
||||
|
||||
std::vector<led_group> LenovoGen7And8USBController::getProfileSettings(uint8_t profile_id)
|
||||
{
|
||||
uint8_t buffer[PACKET_SIZE] = {REPORT_ID, GET_PROFILE, 0xC0, 0x03, profile_id};
|
||||
|
||||
SetGen10PayloadLength(pid, buffer, PACKET_SIZE - 4);
|
||||
vector<uint8_t> response = getFeatureReport(buffer, PACKET_SIZE);
|
||||
|
||||
vector<led_group> groups;
|
||||
|
||||
size_t i = 7;
|
||||
while(i < response.size() && response[i] != 0x00){
|
||||
i++;
|
||||
|
||||
led_group group;
|
||||
|
||||
/*-----------------*\
|
||||
|read group settings|
|
||||
\*-----------------*/
|
||||
|
||||
size_t cnt = response[i++];
|
||||
for(size_t j = 0; j < cnt && i < response.size(); j++, i+=2)
|
||||
{
|
||||
switch(response[i])
|
||||
{
|
||||
case 0x01:
|
||||
group.mode = response[i+1];
|
||||
break;
|
||||
case 0x02:
|
||||
group.speed = response[i+1];
|
||||
break;
|
||||
case 0x03:
|
||||
group.spin = response[i+1];
|
||||
break;
|
||||
case 0x04:
|
||||
group.direction = response[i+1];
|
||||
break;
|
||||
case 0x05:
|
||||
group.color_mode = response[i+1];
|
||||
break;
|
||||
case 0x06:
|
||||
//group.mode = response[i+1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------*\
|
||||
|read group colors |
|
||||
\*-----------------*/
|
||||
|
||||
cnt = response[i++];
|
||||
for(size_t j = 0; j < cnt && i < response.size(); j++, i+=3)
|
||||
{
|
||||
group.colors.push_back(ToRGBColor(response[i],response[i+1],response[i+2]));
|
||||
}
|
||||
|
||||
/*-----------------*\
|
||||
|read group LEDs |
|
||||
\*-----------------*/
|
||||
|
||||
cnt = response[i++];
|
||||
for(size_t j = 0; j < cnt && i < response.size(); j++, i+=2)
|
||||
{
|
||||
group.leds.push_back(response[i] | response[i+1] << 8);
|
||||
}
|
||||
|
||||
groups.push_back(group);
|
||||
}
|
||||
|
||||
return groups;
|
||||
|
||||
}
|
||||
|
||||
void LenovoGen7And8USBController::sendFeatureReport(uint8_t packet[], size_t packet_size)
|
||||
{
|
||||
hid_send_feature_report(dev, packet, packet_size);
|
||||
LOG_TRACE("[Lenovo Gen 7 Controller] Buffer: %s", ConvertBytesToHex(packet, packet_size).c_str());
|
||||
}
|
||||
|
||||
std::vector<uint8_t> LenovoGen7And8USBController::getFeatureReport(uint8_t packet[], size_t packet_size)
|
||||
{
|
||||
sendFeatureReport(packet, packet_size);
|
||||
|
||||
uint8_t read_buffer[PACKET_SIZE] = {REPORT_ID};
|
||||
int num_bytes = 0;
|
||||
num_bytes = hid_get_feature_report(dev, read_buffer, sizeof(read_buffer));
|
||||
|
||||
vector<uint8_t> response = {};
|
||||
if(num_bytes > 0)
|
||||
{
|
||||
response.insert(response.begin(), read_buffer, read_buffer + num_bytes);
|
||||
}
|
||||
|
||||
LOG_TRACE("[Lenovo Gen 7 Controller] Read Buffer: %s", ConvertBytesToHex(response).c_str());
|
||||
return response;
|
||||
}
|
||||
|
||||
std::string LenovoGen7And8USBController::ConvertBytesToHex(uint8_t packet[], size_t packet_size)
|
||||
{
|
||||
return ConvertBytesToHex(std::vector<uint8_t>(packet, packet + packet_size));
|
||||
}
|
||||
|
||||
std::string LenovoGen7And8USBController::ConvertBytesToHex(const std::vector<uint8_t> &input)
|
||||
{
|
||||
std::ostringstream temp_stream;
|
||||
for(const uint8_t &oneInputByte : input)
|
||||
{
|
||||
temp_stream << (temp_stream.tellp()==0 ? "" : " ") << std::setw(2) << std::setfill('0') << std::hex << (int)oneInputByte;
|
||||
}
|
||||
return temp_stream.str();
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| LenovoUSBController_Gen7_8.h |
|
||||
| |
|
||||
| Driver for Lenovo Gen7 and Gen8 devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
#include "LogManager.h"
|
||||
|
||||
#ifndef HID_MAX_STR
|
||||
#define HID_MAX_STR 255
|
||||
#endif
|
||||
|
||||
#define PACKET_SIZE 960
|
||||
#define REPORT_ID 0x07
|
||||
#define DIRECT_MODE 0xA1
|
||||
#define SWITCH_PROFILE 0xC8
|
||||
#define GET_ACTIVE_PROFILE 0xCA
|
||||
#define SAVE_PROFILE 0xCB
|
||||
#define GET_PROFILE 0xCC
|
||||
#define GET_BRIGHTNESS 0xCD
|
||||
#define SET_BRIGHTNESS 0xCE
|
||||
#define SET_DIRECT_MODE 0xD0
|
||||
#define GET_DIRECT_MODE_PROFILE 0xD1
|
||||
|
||||
struct led_group
|
||||
{
|
||||
uint8_t mode;
|
||||
uint8_t speed;
|
||||
uint8_t spin;
|
||||
uint8_t direction;
|
||||
uint8_t color_mode;
|
||||
std::vector<RGBColor> colors;
|
||||
std::vector<uint16_t> leds;
|
||||
};
|
||||
|
||||
class LenovoGen7And8USBController
|
||||
{
|
||||
|
||||
public:
|
||||
/*--------------*\
|
||||
|ctor(s) and dtor|
|
||||
\*--------------*/
|
||||
LenovoGen7And8USBController(hid_device* dev_handle, const char* path, uint16_t in_pid, std::string dev_name);
|
||||
~LenovoGen7And8USBController();
|
||||
|
||||
/*--------------*\
|
||||
|device functions|
|
||||
\*--------------*/
|
||||
void setLedsByGroup(uint8_t profile_id, std::vector<led_group> led_groups);
|
||||
void setLedsDirect(std::vector<led> &leds, std::vector<RGBColor> &colors);
|
||||
void setLedsAllOff(uint8_t profile_id);
|
||||
void setLedsDirectOn(uint8_t profile_id);
|
||||
void setLedsDirectOff(uint8_t profile_id);
|
||||
uint16_t getPid();
|
||||
std::string getName();
|
||||
std::string getLocation();
|
||||
uint8_t getCurrentProfileId();
|
||||
uint8_t getCurrentBrightness();
|
||||
void setBrightness(uint8_t brightness);
|
||||
uint8_t getKeyboardId();
|
||||
void switchProfileTo(uint8_t profile_id);
|
||||
std::vector<led_group> getProfileSettings(uint8_t profile_id);
|
||||
|
||||
|
||||
private:
|
||||
/*--------------*\
|
||||
|data members |
|
||||
\*--------------*/
|
||||
std::string name;
|
||||
hid_device *dev;
|
||||
std::string location;
|
||||
uint16_t pid;
|
||||
|
||||
/*--------------*\
|
||||
|device functions|
|
||||
\*--------------*/
|
||||
void sendFeatureReport(uint8_t packet[], size_t packet_size);
|
||||
std::vector<uint8_t> getFeatureReport(uint8_t packet[], size_t packet_size);
|
||||
std::string ConvertBytesToHex(uint8_t packet[], size_t packet_size);
|
||||
std::string ConvertBytesToHex(const std::vector<uint8_t> &input);
|
||||
};
|
||||
+820
@@ -0,0 +1,820 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_Lenovo_Gen7_8.cpp |
|
||||
| |
|
||||
| RGBController for Lenovo Gen7 and Gen8 devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <vector>
|
||||
#include "RGBController_Lenovo_Gen7_8.h"
|
||||
#include "LenovoDevices.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static bool UsesGen10PacketFormat(uint16_t pid)
|
||||
{
|
||||
return pid == LEGION_7GEN10 || pid == LEGION_5GEN10;
|
||||
}
|
||||
|
||||
static bool Is24ZoneDevice(uint16_t pid)
|
||||
{
|
||||
return pid == LEGION_5GEN10;
|
||||
}
|
||||
|
||||
static bool IsKeyboardOnlyDevice(uint16_t pid)
|
||||
{
|
||||
return pid == LEGION_5GEN10;
|
||||
}
|
||||
|
||||
static const lenovo_led legion_5gen10_24zone_leds[] =
|
||||
{
|
||||
{0x01, "Zone R1C1"},
|
||||
{0x02, "Zone R1C2"},
|
||||
{0x03, "Zone R1C3"},
|
||||
{0x04, "Zone R1C4"},
|
||||
{0x05, "Zone R1C5"},
|
||||
{0x06, "Zone R1C6"},
|
||||
{0x07, "Zone R2C1"},
|
||||
{0x08, "Zone R2C2"},
|
||||
{0x09, "Zone R2C3"},
|
||||
{0x0A, "Zone R2C4"},
|
||||
{0x0B, "Zone R2C5"},
|
||||
{0x0C, "Zone R2C6"},
|
||||
{0x0D, "Zone R3C1"},
|
||||
{0x0E, "Zone R3C2"},
|
||||
{0x0F, "Zone R3C3"},
|
||||
{0x10, "Zone R3C4"},
|
||||
{0x11, "Zone R3C5"},
|
||||
{0x12, "Zone R3C6"},
|
||||
{0x13, "Zone R4C1"},
|
||||
{0x14, "Zone R4C2"},
|
||||
{0x15, "Zone R4C3"},
|
||||
{0x16, "Zone R4C4"},
|
||||
{0x17, "Zone R4C5"},
|
||||
{0x18, "Zone R4C6"},
|
||||
};
|
||||
|
||||
static const unsigned int legion_5gen10_24zone_matrix_map[] =
|
||||
{
|
||||
0, 1, 2, 3, 4, 5,
|
||||
6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23,
|
||||
};
|
||||
|
||||
static const lenovo_zone legion_5gen10_kbd_24zone =
|
||||
{
|
||||
"Keyboard (24-zone)",
|
||||
ZONE_TYPE_MATRIX,
|
||||
0,
|
||||
4,
|
||||
6,
|
||||
legion_5gen10_24zone_matrix_map,
|
||||
legion_5gen10_24zone_leds,
|
||||
0,
|
||||
23,
|
||||
};
|
||||
|
||||
static const RGBColor legion_5gen10_zone_visualization_colors[24] =
|
||||
{
|
||||
0xFF0000, 0x00FFFF, 0xFFFF00, 0x0000FF, 0x00FF00, 0xFF00FF,
|
||||
0xFF7F00, 0x007FFF, 0x7FFF00, 0x7F00FF, 0xFF007F, 0x00FF7F,
|
||||
0xFFD700, 0x0055FF, 0x55FF00, 0xFF0055, 0x00BFFF, 0xBF00FF,
|
||||
0xFF3B00, 0x00FF3B, 0x3B00FF, 0xFF1493, 0x14FF93, 0x9314FF,
|
||||
};
|
||||
|
||||
LenovoRGBController_Gen7_8::LenovoRGBController_Gen7_8(LenovoGen7And8USBController* controller_ptr)
|
||||
{
|
||||
controller = controller_ptr;
|
||||
|
||||
mode Screw;
|
||||
Screw.name = "Screw Rainbow";
|
||||
Screw.value = LENOVO_LEGION_GEN7_8_MODE_SCREW_RAINBOW;
|
||||
Screw.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_DIRECTION_LR |
|
||||
MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Screw.speed_min = 0x01;
|
||||
Screw.speed_max = 0x03;
|
||||
Screw.speed = 2;
|
||||
Screw.color_mode = MODE_COLORS_NONE;
|
||||
Screw.brightness_min = 0;
|
||||
Screw.brightness_max = 9;
|
||||
Screw.brightness = brightness;
|
||||
Screw.direction = MODE_DIRECTION_RIGHT;
|
||||
modes.push_back(Screw);
|
||||
|
||||
mode Rainbow;
|
||||
Rainbow.name = "Rainbow Wave";
|
||||
Rainbow.value = LENOVO_LEGION_GEN7_8_MODE_RAINBOW_WAVE;
|
||||
Rainbow.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_DIRECTION_LR |
|
||||
MODE_FLAG_HAS_DIRECTION_UD |
|
||||
MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Rainbow.speed_min = 0x01;
|
||||
Rainbow.speed_max = 0x03;
|
||||
Rainbow.speed = 2;
|
||||
Rainbow.color_mode = MODE_COLORS_NONE;
|
||||
Rainbow.brightness_min = 0;
|
||||
Rainbow.brightness_max = 9;
|
||||
Rainbow.brightness = brightness;
|
||||
Rainbow.direction = MODE_DIRECTION_RIGHT;
|
||||
modes.push_back(Rainbow);
|
||||
|
||||
mode ColorChange;
|
||||
ColorChange.name = "Color Change";
|
||||
ColorChange.value = LENOVO_LEGION_GEN7_8_MODE_COLOR_CHANGE;
|
||||
ColorChange.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_RANDOM_COLOR |
|
||||
MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_AUTOMATIC_SAVE;
|
||||
ColorChange.speed_min = 0x01;
|
||||
ColorChange.speed_max = 0x03;
|
||||
ColorChange.speed = 2;
|
||||
ColorChange.colors_min = 1;
|
||||
ColorChange.colors_max = 4;
|
||||
ColorChange.colors.resize(4);
|
||||
ColorChange.colors[0] = 0xFFF500;
|
||||
ColorChange.color_mode = MODE_COLORS_RANDOM;
|
||||
ColorChange.brightness_min = 0;
|
||||
ColorChange.brightness_max = 9;
|
||||
ColorChange.brightness = brightness;
|
||||
modes.push_back(ColorChange);
|
||||
|
||||
mode ColorPulse;
|
||||
ColorPulse.name = "Color Pulse";
|
||||
ColorPulse.value = LENOVO_LEGION_GEN7_8_MODE_COLOR_PULSE;
|
||||
ColorPulse.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_RANDOM_COLOR |
|
||||
MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_AUTOMATIC_SAVE;
|
||||
ColorPulse.speed_min = 0x01;
|
||||
ColorPulse.speed_max = 0x03;
|
||||
ColorPulse.speed = 2;
|
||||
ColorPulse.colors_min = 1;
|
||||
ColorPulse.colors_max = 4;
|
||||
ColorPulse.colors.resize(4);
|
||||
ColorPulse.colors[0] = 0xFFF500;
|
||||
ColorPulse.color_mode = MODE_COLORS_RANDOM;
|
||||
ColorPulse.brightness_min = 0;
|
||||
ColorPulse.brightness_max = 9;
|
||||
ColorPulse.brightness = brightness;
|
||||
modes.push_back(ColorPulse);
|
||||
|
||||
mode ColorWave;
|
||||
ColorWave.name = "Color Wave";
|
||||
ColorWave.value = LENOVO_LEGION_GEN7_8_MODE_COLOR_WAVE;
|
||||
ColorWave.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_DIRECTION_LR |
|
||||
MODE_FLAG_HAS_DIRECTION_UD |
|
||||
MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_RANDOM_COLOR |
|
||||
MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_AUTOMATIC_SAVE;
|
||||
ColorWave.speed_min = 0x01;
|
||||
ColorWave.speed_max = 0x03;
|
||||
ColorWave.speed = 2;
|
||||
ColorWave.colors_min = 1;
|
||||
ColorWave.colors_max = 4;
|
||||
ColorWave.colors.resize(4);
|
||||
ColorWave.colors[0] = 0xFFF500;
|
||||
ColorWave.color_mode = MODE_COLORS_RANDOM;
|
||||
ColorWave.brightness_min = 0;
|
||||
ColorWave.brightness_max = 9;
|
||||
ColorWave.brightness = brightness;
|
||||
ColorWave.direction = MODE_DIRECTION_RIGHT;
|
||||
modes.push_back(ColorWave);
|
||||
|
||||
mode Smooth;
|
||||
Smooth.name = "Smooth";
|
||||
Smooth.value = LENOVO_LEGION_GEN7_8_MODE_SMOOTH;
|
||||
Smooth.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_RANDOM_COLOR |
|
||||
MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Smooth.speed_min = 0x01;
|
||||
Smooth.speed_max = 0x03;
|
||||
Smooth.speed = 2;
|
||||
Smooth.colors_min = 1;
|
||||
Smooth.colors_max = 4;
|
||||
Smooth.colors.resize(4);
|
||||
Smooth.colors[0] = 0xFFF500;
|
||||
Smooth.color_mode = MODE_COLORS_RANDOM;
|
||||
Smooth.brightness_min = 0;
|
||||
Smooth.brightness_max = 9;
|
||||
Smooth.brightness = brightness;
|
||||
modes.push_back(Smooth);
|
||||
|
||||
if(!Is24ZoneDevice(controller->getPid()))
|
||||
{
|
||||
mode Rain;
|
||||
Rain.name = "Rain";
|
||||
Rain.value = LENOVO_LEGION_GEN7_8_MODE_RAIN;
|
||||
Rain.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_RANDOM_COLOR |
|
||||
MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Rain.speed_min = 0x01;
|
||||
Rain.speed_max = 0x03;
|
||||
Rain.speed = 2;
|
||||
Rain.colors_min = 1;
|
||||
Rain.colors_max = 4;
|
||||
Rain.colors.resize(4);
|
||||
Rain.colors[0] = 0xFFF500;
|
||||
Rain.color_mode = MODE_COLORS_RANDOM;
|
||||
Rain.brightness_min = 0;
|
||||
Rain.brightness_max = 9;
|
||||
Rain.brightness = brightness;
|
||||
modes.push_back(Rain);
|
||||
}
|
||||
|
||||
if(!IsKeyboardOnlyDevice(controller->getPid()))
|
||||
{
|
||||
mode Ripple;
|
||||
Ripple.name = "Ripple";
|
||||
Ripple.value = LENOVO_LEGION_GEN7_8_MODE_RIPPLE;
|
||||
Ripple.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_RANDOM_COLOR |
|
||||
MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Ripple.speed_min = 0x01;
|
||||
Ripple.speed_max = 0x03;
|
||||
Ripple.speed = 2;
|
||||
Ripple.colors_min = 1;
|
||||
Ripple.colors_max = 4;
|
||||
Ripple.colors.resize(4);
|
||||
Ripple.colors[0] = 0xFFF500;
|
||||
Ripple.color_mode = MODE_COLORS_RANDOM;
|
||||
Ripple.brightness_min = 0;
|
||||
Ripple.brightness_max = 9;
|
||||
Ripple.brightness = brightness;
|
||||
modes.push_back(Ripple);
|
||||
|
||||
mode AudioBounce;
|
||||
AudioBounce.name = "Audio Bounce Lighting";
|
||||
AudioBounce.value = LENOVO_LEGION_GEN7_8_MODE_AUDIO_BOUNCE;
|
||||
AudioBounce.flags = MODE_FLAG_HAS_BRIGHTNESS;
|
||||
AudioBounce.color_mode = MODE_COLORS_NONE;
|
||||
AudioBounce.brightness_min = 0;
|
||||
AudioBounce.brightness_max = 9;
|
||||
AudioBounce.brightness = brightness;
|
||||
modes.push_back(AudioBounce);
|
||||
|
||||
mode AudioRipple;
|
||||
AudioRipple.name = "Audio Ripple Lighting";
|
||||
AudioRipple.value = LENOVO_LEGION_GEN7_8_MODE_AUDIO_RIPPLE;
|
||||
AudioRipple.flags = MODE_FLAG_HAS_BRIGHTNESS;
|
||||
AudioRipple.color_mode = MODE_COLORS_NONE;
|
||||
AudioRipple.brightness_min = 0;
|
||||
AudioRipple.brightness_max = 9;
|
||||
AudioRipple.brightness = brightness;
|
||||
modes.push_back(AudioRipple);
|
||||
}
|
||||
|
||||
mode Static;
|
||||
Static.name = "Static";
|
||||
Static.value = LENOVO_LEGION_GEN7_8_MODE_STATIC;
|
||||
Static.flags = MODE_FLAG_HAS_PER_LED_COLOR |
|
||||
MODE_FLAG_HAS_RANDOM_COLOR |
|
||||
MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Static.color_mode = MODE_COLORS_PER_LED;
|
||||
Static.brightness_min = 0;
|
||||
Static.brightness_max = 9;
|
||||
Static.brightness = brightness;
|
||||
modes.push_back(Static);
|
||||
|
||||
if(!Is24ZoneDevice(controller->getPid()))
|
||||
{
|
||||
mode Type;
|
||||
Type.name = "Type Lighting";
|
||||
Type.value = LENOVO_LEGION_GEN7_8_MODE_TYPE;
|
||||
Type.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_RANDOM_COLOR |
|
||||
MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_AUTOMATIC_SAVE;
|
||||
Type.speed_min = 0x01;
|
||||
Type.speed_max = 0x03;
|
||||
Type.speed = 2;
|
||||
Type.colors_min = 1;
|
||||
Type.colors_max = 4;
|
||||
Type.colors.resize(4);
|
||||
Type.colors[0] = 0xFFF500;
|
||||
Type.color_mode = MODE_COLORS_RANDOM;
|
||||
Type.brightness_min = 0;
|
||||
Type.brightness_max = 9;
|
||||
Type.brightness = brightness;
|
||||
modes.push_back(Type);
|
||||
}
|
||||
|
||||
if(!IsKeyboardOnlyDevice(controller->getPid()))
|
||||
{
|
||||
mode Direct;
|
||||
Direct.name = "Direct";
|
||||
Direct.value = LENOVO_LEGION_GEN7_8_MODE_DIRECT;
|
||||
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR |
|
||||
MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Direct.color_mode = MODE_COLORS_PER_LED;
|
||||
Direct.brightness_min = 0;
|
||||
Direct.brightness_max = 9;
|
||||
Direct.brightness = brightness;
|
||||
modes.push_back(Direct);
|
||||
}
|
||||
|
||||
name = controller->getName();
|
||||
type = DEVICE_TYPE_KEYBOARD;
|
||||
vendor = "Lenovo";
|
||||
|
||||
switch (controller->getPid())
|
||||
{
|
||||
case LEGION_S7GEN7:
|
||||
description = "Lenovo Legion 7 Slim Generation 7";
|
||||
break;
|
||||
|
||||
case LEGION_7GEN7:
|
||||
description = "Lenovo Legion 7 Generation 7";
|
||||
break;
|
||||
|
||||
case LEGION_S7GEN8:
|
||||
description = "Lenovo Legion 7 Slim Generation 8";
|
||||
break;
|
||||
|
||||
case LEGION_7GEN8:
|
||||
description = "Lenovo Legion 7 Generation 8";
|
||||
break;
|
||||
|
||||
case LEGION_7GEN9:
|
||||
case LEGION_7GEN9_H:
|
||||
description = "Lenovo Legion 7 Generation 9";
|
||||
break;
|
||||
|
||||
case LEGION_7GEN10:
|
||||
description = "Lenovo Legion 7 Generation 10";
|
||||
break;
|
||||
|
||||
case LEGION_5GEN10:
|
||||
description = "Lenovo Legion 5 Gen 10";
|
||||
break;
|
||||
}
|
||||
|
||||
brightness = controller->getCurrentBrightness();
|
||||
profile_id = controller->getCurrentProfileId();
|
||||
for(mode &m : modes)
|
||||
{
|
||||
m.brightness = brightness;
|
||||
}
|
||||
|
||||
SetupZones();
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Initiliaze Static |
|
||||
\*-----------------------------------------------------*/
|
||||
active_mode = 0;
|
||||
for(size_t i = 0; i < modes.size(); i++)
|
||||
{
|
||||
if(modes[i].value == LENOVO_LEGION_GEN7_8_MODE_STATIC)
|
||||
{
|
||||
active_mode = (int)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ReadDeviceSettings();
|
||||
last_mode = active_mode;
|
||||
}
|
||||
|
||||
LenovoRGBController_Gen7_8::~LenovoRGBController_Gen7_8()
|
||||
{
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void LenovoRGBController_Gen7_8::SetupZones()
|
||||
{
|
||||
vector<lenovo_zone> lenovo_zones;
|
||||
if(Is24ZoneDevice(controller->getPid()))
|
||||
{
|
||||
lenovo_zones.push_back(legion_5gen10_kbd_24zone);
|
||||
}
|
||||
else
|
||||
{
|
||||
lenovo_zones.push_back(legion7_gen7and8_kbd_ansi);
|
||||
}
|
||||
|
||||
if(!IsKeyboardOnlyDevice(controller->getPid()))
|
||||
{
|
||||
lenovo_zones.push_back(legion7_gen7and8_neon);
|
||||
}
|
||||
|
||||
if (controller->getPid() == LEGION_7GEN7)
|
||||
{
|
||||
lenovo_zones.push_back(lenovo_legion_7gen7_logo);
|
||||
lenovo_zones.push_back(lenovo_legion_7gen7_vents);
|
||||
}
|
||||
|
||||
if (controller->getPid() == LEGION_7GEN10)
|
||||
{
|
||||
lenovo_zones.push_back(lenovo_legion_7gen7_logo);
|
||||
lenovo_zones.push_back(lenovo_legion_7gen10_vents);
|
||||
}
|
||||
|
||||
for(unsigned 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;
|
||||
|
||||
LOG_DEBUG("[Lenovo Gen7/8 Controller] adding zone: %s with %u LEDs", new_zone.name.c_str(), 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];
|
||||
|
||||
if(lenovo_zones[i].matrix_map != NULL)
|
||||
{
|
||||
new_zone.matrix_map->map = (unsigned int *) lenovo_zones[i].matrix_map;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_zone.matrix_map = NULL;
|
||||
}
|
||||
|
||||
zones.push_back(new_zone);
|
||||
|
||||
for(unsigned int led_idx = lenovo_zones[i].start; led_idx <= lenovo_zones[i].end; led_idx++ )
|
||||
{
|
||||
led new_led;
|
||||
new_led.name = lenovo_zones[i].leds[led_idx].name;
|
||||
new_led.value = lenovo_zones[i].id << 8 | lenovo_zones[i].leds[led_idx].led_num ;
|
||||
leds.push_back(new_led);
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| create led id to index map for fast look up |
|
||||
\*---------------------------------------------*/
|
||||
led_id_to_index[new_led.value]=leds.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void LenovoRGBController_Gen7_8::ResizeZone(int /*zone*/, int /*new_size*/)
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| This device does not support resizing zones |
|
||||
\*---------------------------------------------------------*/
|
||||
}
|
||||
|
||||
void LenovoRGBController_Gen7_8::UpdateSingleLED(int /*led*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void LenovoRGBController_Gen7_8::UpdateZoneLEDs(int /*zone*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void LenovoRGBController_Gen7_8::DeviceUpdateMode()
|
||||
{
|
||||
uint8_t hw_profile_id = controller->getCurrentProfileId();
|
||||
if(hw_profile_id != profile_id)
|
||||
{
|
||||
profile_id = hw_profile_id;
|
||||
ReadDeviceSettings();
|
||||
last_mode = active_mode;
|
||||
direct_enabled = false;
|
||||
}
|
||||
|
||||
if(brightness != modes[active_mode].brightness)
|
||||
{
|
||||
brightness = modes[active_mode].brightness;
|
||||
controller->setBrightness(brightness);
|
||||
for(mode &m : modes)
|
||||
{
|
||||
m.brightness = brightness;
|
||||
}
|
||||
}
|
||||
|
||||
if(last_mode != active_mode)
|
||||
{
|
||||
if(modes[last_mode].value == LENOVO_LEGION_GEN7_8_MODE_DIRECT)
|
||||
{
|
||||
controller->setLedsDirectOff(profile_id);
|
||||
direct_enabled = false;
|
||||
}
|
||||
|
||||
if(modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_DIRECT)
|
||||
{
|
||||
controller->setLedsDirectOn(profile_id);
|
||||
direct_enabled = true;
|
||||
if(!UsesGen10PacketFormat(controller->getPid()))
|
||||
{
|
||||
controller->setLedsByGroup(profile_id, GetLedGroups());
|
||||
}
|
||||
}
|
||||
|
||||
last_mode = active_mode;
|
||||
}
|
||||
else if((modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_DIRECT) && !direct_enabled)
|
||||
{
|
||||
controller->setLedsDirectOn(profile_id);
|
||||
direct_enabled = true;
|
||||
}
|
||||
|
||||
if(modes[active_mode].value != LENOVO_LEGION_GEN7_8_MODE_DIRECT)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
}
|
||||
|
||||
void LenovoRGBController_Gen7_8::DeviceUpdateLEDs()
|
||||
{
|
||||
if(modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_DIRECT)
|
||||
{
|
||||
if(UsesGen10PacketFormat(controller->getPid()))
|
||||
{
|
||||
/*---------------------------------------------*\
|
||||
| Gen10 may ignore A1 updates unless D0 is |
|
||||
| reasserted. |
|
||||
\*---------------------------------------------*/
|
||||
controller->setLedsDirectOn(profile_id);
|
||||
direct_enabled = true;
|
||||
}
|
||||
else if(!direct_enabled)
|
||||
{
|
||||
controller->setLedsDirectOn(profile_id);
|
||||
direct_enabled = true;
|
||||
}
|
||||
controller->setLedsDirect(leds, colors);
|
||||
}
|
||||
else
|
||||
{
|
||||
controller->setLedsByGroup(profile_id, GetLedGroups());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LenovoRGBController_Gen7_8::ReadDeviceSettings()
|
||||
{
|
||||
vector<led_group> current_settings = controller->getProfileSettings(profile_id);
|
||||
if(current_settings.size() > 0)
|
||||
{
|
||||
for(unsigned int i = 0; i < modes.size(); i++)
|
||||
{
|
||||
if(modes[i].value == current_settings[0].mode)
|
||||
{
|
||||
switch(current_settings[0].color_mode)
|
||||
{
|
||||
case 0x02:
|
||||
if(modes[i].flags & MODE_FLAG_HAS_PER_LED_COLOR)
|
||||
{
|
||||
modes[i].color_mode = MODE_COLORS_PER_LED;
|
||||
}
|
||||
else
|
||||
{
|
||||
modes[i].color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
modes[i].color_mode = MODE_COLORS_RANDOM;
|
||||
break;
|
||||
|
||||
default:
|
||||
modes[i].color_mode = MODE_COLORS_NONE;
|
||||
}
|
||||
|
||||
switch(modes[i].color_mode)
|
||||
{
|
||||
case MODE_COLORS_PER_LED:
|
||||
for(size_t j=0; j < colors.size(); j++)
|
||||
{
|
||||
colors[j]=0x00;
|
||||
}
|
||||
for(const led_group &lg : current_settings)
|
||||
{
|
||||
if(lg.colors.size() > 0)
|
||||
{
|
||||
for(uint16_t led_id : lg.leds)
|
||||
{
|
||||
if(auto search = led_id_to_index.find(led_id); search != led_id_to_index.end())
|
||||
{
|
||||
colors[search->second] = lg.colors[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_COLORS_MODE_SPECIFIC:
|
||||
for(size_t j=0; j < modes[i].colors.size(); j++)
|
||||
{
|
||||
if(j < current_settings[0].colors.size())
|
||||
{
|
||||
modes[i].colors[j] = current_settings[0].colors[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
modes[i].colors[j] = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(current_settings[0].direction)
|
||||
{
|
||||
case 0x01:
|
||||
modes[i].direction = MODE_DIRECTION_UP;
|
||||
break;
|
||||
case 0x02:
|
||||
modes[i].direction = MODE_DIRECTION_DOWN;
|
||||
break;
|
||||
case 0x03:
|
||||
modes[i].direction = MODE_DIRECTION_LEFT;
|
||||
break;
|
||||
case 0x04:
|
||||
modes[i].direction = MODE_DIRECTION_RIGHT;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(current_settings[0].spin)
|
||||
{
|
||||
case 0x01:
|
||||
modes[i].direction = MODE_DIRECTION_RIGHT;
|
||||
break;
|
||||
case 0x02:
|
||||
modes[i].direction = MODE_DIRECTION_LEFT;
|
||||
break;
|
||||
}
|
||||
|
||||
active_mode = i;
|
||||
break; //stop for loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<led_group> LenovoRGBController_Gen7_8::GetLedGroups()
|
||||
{
|
||||
if(Is24ZoneDevice(controller->getPid()) &&
|
||||
modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_STATIC &&
|
||||
modes[active_mode].color_mode == MODE_COLORS_RANDOM)
|
||||
{
|
||||
vector<led_group> led_groups;
|
||||
led_groups.reserve(leds.size());
|
||||
|
||||
for(size_t i = 0; i < leds.size(); i++)
|
||||
{
|
||||
led_group group;
|
||||
group.mode = modes[active_mode].value;
|
||||
group.speed = modes[active_mode].speed;
|
||||
group.spin = 0x00;
|
||||
group.direction = 0x00;
|
||||
group.color_mode = 0x02;
|
||||
group.colors.push_back(legion_5gen10_zone_visualization_colors[i % 24]);
|
||||
group.leds.push_back(leds[i].value);
|
||||
led_groups.push_back(group);
|
||||
}
|
||||
|
||||
return led_groups;
|
||||
}
|
||||
|
||||
std::unordered_map<RGBColor, vector<uint16_t>> led_map;
|
||||
|
||||
if(modes[active_mode].color_mode == MODE_COLORS_PER_LED &&
|
||||
modes[active_mode].value != LENOVO_LEGION_GEN7_8_MODE_DIRECT)
|
||||
{
|
||||
for(size_t i = 0; i < leds.size(); i++)
|
||||
{
|
||||
led_map[colors[i]].push_back(leds[i].value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t start = 0;
|
||||
size_t end = leds.size();
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Riplle and Type only apply to keyboard |
|
||||
\*-------------------------------------------------*/
|
||||
if(modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_RIPPLE ||
|
||||
modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_TYPE)
|
||||
{
|
||||
for(const zone &z : zones)
|
||||
{
|
||||
if(z.name == "Keyboard")
|
||||
{
|
||||
start = z.start_idx;
|
||||
end = start + z.leds_count;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(size_t i = start; i < end; i++)
|
||||
{
|
||||
led_map[0x00].push_back(leds[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
vector<led_group> led_groups;
|
||||
for(const auto &pair : led_map)
|
||||
{
|
||||
if(pair.first == 0x00 && led_map.size() != 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
led_group group;
|
||||
group.mode = modes[active_mode].value;
|
||||
group.speed = modes[active_mode].speed;
|
||||
group.spin = 0x00;
|
||||
group.direction = 0x00;
|
||||
|
||||
switch(modes[active_mode].direction)
|
||||
{
|
||||
case MODE_DIRECTION_UP:
|
||||
group.direction = 0x01;
|
||||
break;
|
||||
|
||||
case MODE_DIRECTION_DOWN:
|
||||
group.direction = 0x02;
|
||||
break;
|
||||
|
||||
case MODE_DIRECTION_LEFT:
|
||||
if(modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_SCREW_RAINBOW)
|
||||
{
|
||||
group.spin = 0x02;
|
||||
}
|
||||
else
|
||||
{
|
||||
group.direction = 0x03;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_DIRECTION_RIGHT:
|
||||
if(modes[active_mode].value == LENOVO_LEGION_GEN7_8_MODE_SCREW_RAINBOW)
|
||||
{
|
||||
group.spin = 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
group.direction = 0x04;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch(modes[active_mode].color_mode)
|
||||
{
|
||||
default:
|
||||
case MODE_COLORS_NONE:
|
||||
group.color_mode = 0x00;
|
||||
break;
|
||||
|
||||
case MODE_COLORS_RANDOM:
|
||||
group.color_mode = 0x01;
|
||||
break;
|
||||
|
||||
case MODE_COLORS_MODE_SPECIFIC:
|
||||
group.color_mode = 0x02;
|
||||
for(RGBColor c : modes[active_mode].colors)
|
||||
{
|
||||
if(c)
|
||||
{
|
||||
group.colors.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
if(group.colors.size() == 0)
|
||||
{
|
||||
group.colors.push_back(0xFFF500);
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_COLORS_PER_LED:
|
||||
group.color_mode = 0x02;
|
||||
group.colors.push_back(pair.first);
|
||||
break;
|
||||
}
|
||||
|
||||
group.leds = pair.second;
|
||||
|
||||
led_groups.push_back(group);
|
||||
}
|
||||
|
||||
return led_groups;
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_Lenovo_Gen7_8.h |
|
||||
| |
|
||||
| RGBController for Lenovo Gen7 and Gen8 devices |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RGBController.h"
|
||||
#include "LenovoUSBController_Gen7_8.h"
|
||||
|
||||
enum
|
||||
{
|
||||
LENOVO_LEGION_GEN7_8_MODE_SCREW_RAINBOW = 0x01,
|
||||
LENOVO_LEGION_GEN7_8_MODE_RAINBOW_WAVE = 0x02,
|
||||
LENOVO_LEGION_GEN7_8_MODE_COLOR_CHANGE = 0x03,
|
||||
LENOVO_LEGION_GEN7_8_MODE_COLOR_PULSE = 0x04,
|
||||
LENOVO_LEGION_GEN7_8_MODE_COLOR_WAVE = 0x05,
|
||||
LENOVO_LEGION_GEN7_8_MODE_SMOOTH = 0x06,
|
||||
LENOVO_LEGION_GEN7_8_MODE_RAIN = 0x07,
|
||||
LENOVO_LEGION_GEN7_8_MODE_RIPPLE = 0x08,
|
||||
LENOVO_LEGION_GEN7_8_MODE_AUDIO_BOUNCE = 0x09,
|
||||
LENOVO_LEGION_GEN7_8_MODE_AUDIO_RIPPLE = 0x0A,
|
||||
LENOVO_LEGION_GEN7_8_MODE_STATIC = 0x0B,
|
||||
LENOVO_LEGION_GEN7_8_MODE_TYPE = 0x0C,
|
||||
LENOVO_LEGION_GEN7_8_MODE_DIRECT = 0x0D,
|
||||
};
|
||||
|
||||
class LenovoRGBController_Gen7_8 : public RGBController
|
||||
{
|
||||
public:
|
||||
LenovoRGBController_Gen7_8(LenovoGen7And8USBController* controller_ptr);
|
||||
~LenovoRGBController_Gen7_8();
|
||||
|
||||
void SetupZones();
|
||||
|
||||
void ResizeZone(int zone, int new_size);
|
||||
|
||||
void DeviceUpdateLEDs();
|
||||
void UpdateZoneLEDs(int zone);
|
||||
void UpdateSingleLED(int led);
|
||||
|
||||
void DeviceUpdateMode();
|
||||
|
||||
private:
|
||||
LenovoGen7And8USBController* controller;
|
||||
std::vector<led_group> GetLedGroups();
|
||||
void ReadDeviceSettings();
|
||||
std::unordered_map<unsigned int, size_t> led_id_to_index;
|
||||
int last_mode = 0;
|
||||
bool direct_enabled = false;
|
||||
uint8_t brightness = 0x00;
|
||||
uint8_t profile_id = 0x01;
|
||||
};
|
||||
Reference in New Issue
Block a user