Initial commit to add Lenovo Legion M300 RGB Mouse

Added support for Lenovo Legion M300 RGB Mouse.
Added all supported modes Static, Rainbow, Breathing and Off
Also Tested all modes to verify its working
This commit is contained in:
Wayne Riordan 2024-01-09 21:41:53 +00:00 committed by Adam Honse
parent 6243a66b0b
commit 568da43bb6
5 changed files with 314 additions and 0 deletions

View file

@ -0,0 +1,86 @@
/*-----------------------------------*\
| LenovoM300Controller.cpp |
| |
| Controller For Lenovo Legion M300 |
| Mouse |
| |
| Wayne Riordan 9 Jan 2024 |
\*-----------------------------------*/
#include "LenovoM300Controller.h"
#include <cstring>
using namespace std;
LenovoM300Controller::LenovoM300Controller(hid_device* dev_handle, const hid_device_info& info)
{
device = dev_handle;
location = info.path;
}
LenovoM300Controller::~LenovoM300Controller()
{
hid_close(device);
}
std::string LenovoM300Controller::GetDeviceLocation()
{
return("HID: " + location);
}
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;
}

View file

@ -0,0 +1,44 @@
/*-----------------------------------*\
| LenovoM300Controller.h |
| |
| Header file for Lenovo M300 Mouse |
| controller |
| |
| Wayne Riordan 9 Jan 2024 |
\*-----------------------------------*/
#pragma once
#include "RGBController.h"
#include <string>
#include <hidapi/hidapi.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);
~LenovoM300Controller();
std::string GetDeviceLocation();
void SetMode(std::vector<RGBColor> colors, unsigned char mode_value, unsigned int brightness);
protected:
hid_device* device;
private:
std::string location;
unsigned char CalculateFinalByte(unsigned char* ptr, int count);
};

View file

@ -0,0 +1,36 @@
/*-----------------------------------*\
| LenovoMouseDetect.h |
| |
| Detect Lenovo Mouse |
| |
| Wayne Riordan 9 Jan 2024 |
\*-----------------------------------*/
#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);
RGBController_LenovoM300* rgb_controller = new RGBController_LenovoM300(controller);
rgb_controller->name = name;
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
REGISTER_HID_DETECTOR_PU("Lenovo Legion M300", DetectLenovoLegionM300Controllers, LENOVO_VID, LEGION_M300_PID, LENOVO_PAGE, LENOVO_USAGE);

View file

@ -0,0 +1,116 @@
/*-----------------------------------*\
| RGBController_LenovoM300.cpp |
| |
| RGB Controller For Lenovo M300 |
| Mouse |
| |
| Wayne Riordan 9 Jan 2024 |
\*-----------------------------------*/
#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 = "Lenovo Legion M300";
vendor = "Lenovo";
type = DEVICE_TYPE_MOUSE;
description = name;
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();
}

View file

@ -0,0 +1,32 @@
/*-----------------------------------*\
| RGBController_LenovoM300.h |
| |
| Header file for Lenovo M300 Mouse |
| RGB Controller |
| |
| Wayne Riordan 9 Jan 2024 |
\*-----------------------------------*/
#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;
};