LenovoLegionToolkit

Форк
0
311 строк · 8.5 Кб
1
using System.Runtime.InteropServices;
2
using LenovoLegionToolkit.Lib.Extensions;
3
using LenovoLegionToolkit.Lib.System;
4
using Windows.Win32;
5

6
// ReSharper disable all
7

8
Console.WriteLine(@"How to use:
9
  1. Make sure Vantage and LLT is closed.
10
  2. Set the keyboard brightness to maximum.
11

12
When ready, press any key to continue...
13
");
14
Console.ReadKey();
15

16
var device = Devices.GetSpectrumRGBKeyboard();
17

18
Console.WriteLine("Finding Spectrum keyboard...");
19

20
if (device is null)
21
{
22
    Console.WriteLine("Spectrum not supported");
23
    Console.ReadKey();
24
    return;
25
}
26

27

28
Console.WriteLine("Spectrum keyboard found");
29
Console.WriteLine();
30

31
Console.WriteLine("Reading response for 0xD1...");
32
SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownD1, 0, 0));
33
GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resD1);
34
Print(resD1.Bytes);
35
Console.WriteLine();
36

37
Console.WriteLine("Reading response for 0xC6...");
38
SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC6, 0, 0));
39
GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC6);
40
Print(resC6.Bytes);
41
Console.WriteLine();
42

43
Console.WriteLine("Reading response for 0x04...");
44
SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.Unknown04, 0, 0));
45
GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE res04);
46
Print(res04.Bytes);
47
Console.WriteLine();
48

49
Console.WriteLine("Reading response for 0xC7...");
50
SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC7, 0, 0));
51
GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC7);
52
Print(resC7.Bytes);
53
Console.WriteLine();
54

55
Console.WriteLine("Reading response for 0xC4 7...");
56
SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC4, 7, 0));
57
GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC47);
58
Print(resC47.Bytes);
59
Console.WriteLine();
60

61
Console.WriteLine("Reading response for 0xC4 8...");
62
SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC4, 8, 0));
63
GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC48);
64
Print(resC48.Bytes);
65
Console.WriteLine();
66

67
for (var i = 0; i < 10; i++)
68
{
69
    Console.WriteLine($"Reading response for 0xC5 7 {i}...");
70
    SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC5, 7, (byte)i));
71
    GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC57);
72
    Print(resC57.Bytes);
73
    Console.WriteLine();
74
}
75

76
Console.WriteLine($"Reading response for 0xC5 8...");
77
SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.UnknownC5, 8, 0));
78
GetFeature(device, out LENOVO_SPECTRUM_GENERIC_RESPONSE resC58);
79
Print(resC58.Bytes);
80
Console.WriteLine();
81

82
Console.WriteLine(resD1.Bytes[4] == 0 ? "Keyboard is RGB." : "Not compatible.");
83

84
var spectrumLayout = (resC47.Bytes[6], resC47.Bytes[5]) switch
85
{
86
    (22, 9) => "Full",
87
    (20, 8) => "KeyboardAndFront",
88
    (20, 7) => "KeyboardOnly",
89
    _ => "Unknown"
90
};
91
Console.WriteLine($"Layout is {spectrumLayout}.");
92
Console.WriteLine("Reading config complete.");
93
Console.WriteLine();
94
Console.ReadKey();
95

96
Console.WriteLine(@"*** TEST 1***
97

98
This program will now try to control brightness of the keyboard. Keyboard should turn off and then gradually increase brightness and turn off at the end.
99

100
When ready, press any key to continue...
101
");
102

103
var brightnessLevels = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
104

105
foreach (var level in brightnessLevels)
106
{
107
    Console.WriteLine($"Setting brightness level to {level}...");
108
    SetFeature(device, new LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE.Brightness, level, 0));
109
    await Task.Delay(250);
110
}
111

112
Console.WriteLine("Test complete, press any key to continue...");
113
Console.WriteLine();
114
Console.ReadKey();
115

116
Console.WriteLine(@"***TEST 2***
117

118
How to find a keycode for a specific key:
119
  1. Open Vantage
120
  2. Select the key that you want to find keycode for
121
  3. Set the key to plain white (Hex: #FFFFFF, RGB: 255,255,255)
122
  4. Make sure all other keys don't have any effect set (are off)
123
  5. Set the keyboard brightness to maximum
124

125
When ready, press any key to continue...
126
");
127
Console.ReadKey();
128

129
Console.WriteLine("Reading white key keycodes...");
130
Console.WriteLine();
131

132
const int Iterations = 5;
133

134
for (var i = 0; i < Iterations; i++)
135
{
136
    GetFeature(device, out LENOVO_SPECTRUM_STATE state);
137

138
    var keys = state.Data
139
        .Where(kv => HasColor(kv.Color))
140
        .Select(kv => kv.Key)
141
        .Select(k => "0x" + k.ToString("X4"))
142
        .Split(8);
143

144
    await Task.Delay(1000);
145

146
    if (keys.SelectMany(k => k).IsEmpty())
147
    {
148
        Console.WriteLine($"[{i + 1}/{Iterations}] No keys found");
149
        continue;
150
    }
151

152
    Console.WriteLine($"[{i + 1}/{Iterations}] Keys with color found:");
153

154
    foreach (var line in keys)
155
        Console.WriteLine("    " + string.Join(", ", line));
156

157
}
158

159
Console.WriteLine();
160
Console.WriteLine("Test complete.");
161
Console.WriteLine("Press any key to exit...");
162
Console.ReadLine();
163

164
#region Methods
165

166
void Print(byte[] bytes)
167
{
168
    var length = bytes[2] + 4;
169
    foreach (var i in bytes.Take(length).Split(16))
170
        Console.WriteLine(string.Join(" ", i.Select(i => $"{i:X2}")));
171
}
172

173
bool HasColor(LENOVO_SPECTRUM_COLOR rgbColor) => rgbColor.Red == 255 && rgbColor.Green == 255 && rgbColor.Blue == 255;
174

175
unsafe void SetFeature<T>(SafeHandle handle, T str) where T : notnull
176
{
177
    var ptr = IntPtr.Zero;
178
    try
179
    {
180
        int size;
181
        if (str is byte[] bytes)
182
        {
183
            size = bytes.Length;
184
            ptr = Marshal.AllocHGlobal(size);
185
            Marshal.Copy(bytes, 0, ptr, size);
186
        }
187
        else
188
        {
189
            size = Marshal.SizeOf<T>();
190
            ptr = Marshal.AllocHGlobal(size);
191
            Marshal.StructureToPtr(str, ptr, false);
192
        }
193

194
        var result = PInvoke.HidD_SetFeature(handle, ptr.ToPointer(), (uint)size);
195
        if (!result)
196
            PInvokeExtensions.ThrowIfWin32Error(typeof(T).Name);
197
    }
198
    finally
199
    {
200
        Marshal.FreeHGlobal(ptr);
201
    }
202
}
203

204
unsafe void GetFeature<T>(SafeHandle handle, out T str) where T : struct
205
{
206
    var ptr = IntPtr.Zero;
207
    try
208
    {
209
        var size = Marshal.SizeOf<T>();
210
        ptr = Marshal.AllocHGlobal(size);
211
        Marshal.Copy(new byte[] { 7 }, 0, ptr, 1);
212

213
        var result = PInvoke.HidD_GetFeature(handle, ptr.ToPointer(), (uint)size);
214
        if (!result)
215
            PInvokeExtensions.ThrowIfWin32Error(typeof(T).Name);
216

217
        str = Marshal.PtrToStructure<T>(ptr);
218
    }
219
    finally
220
    {
221
        Marshal.FreeHGlobal(ptr);
222
    }
223
}
224

225
#endregion
226

227
#region Structs
228

229
[StructLayout(LayoutKind.Sequential)]
230
internal struct LENOVO_SPECTRUM_HEADER
231
{
232
    public byte Head = 7;
233
    public LENOVO_SPECTRUM_OPERATION_TYPE Type;
234
    public byte Size;
235
    public byte Tail = 3;
236

237
    public LENOVO_SPECTRUM_HEADER(LENOVO_SPECTRUM_OPERATION_TYPE type, int size)
238
    {
239
        Type = type;
240
        Size = (byte)(size % 256);
241
    }
242
}
243

244
[StructLayout(LayoutKind.Sequential, Size = 960)]
245
internal struct LENOVO_SPECTRUM_GENERIC_REQUEST
246
{
247
    public LENOVO_SPECTRUM_HEADER Header;
248
    public byte Value;
249
    public byte Value2;
250

251
    public LENOVO_SPECTRUM_GENERIC_REQUEST(LENOVO_SPECTRUM_OPERATION_TYPE operation, byte value, byte value2)
252
    {
253
        Header = new LENOVO_SPECTRUM_HEADER(operation, 0xC0);
254
        Value = value;
255
        Value2 = value2;
256
    }
257
}
258

259
[StructLayout(LayoutKind.Sequential, Size = 960)]
260
internal struct LENOVO_SPECTRUM_GENERIC_RESPONSE
261
{
262
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 960)]
263
    public byte[] Bytes;
264
}
265

266
internal enum LENOVO_SPECTRUM_OPERATION_TYPE : byte
267
{
268
    ProfileSet1 = 0xC8,
269
    GetProfile = 0xCA,
270
    EffectChange = 0xCB,
271
    ProfileSet2 = 0xCC,
272
    GetBrightness = 0xCD,
273
    Brightness = 0xCE,
274
    AuroraSendBitmap = 0xA1,
275
    State = 0x03,
276
    Unknown04 = 0x04,
277
    UnknownC4 = 0xC4,
278
    UnknownC5 = 0xC5,
279
    UnknownC6 = 0xC6,
280
    UnknownC7 = 0xC7,
281
    UnknownD1 = 0xD1,
282
}
283

284
[StructLayout(LayoutKind.Sequential)]
285
internal struct LENOVO_SPECTRUM_COLOR
286
{
287
    public byte Red;
288
    public byte Green;
289
    public byte Blue;
290
}
291

292
[StructLayout(LayoutKind.Sequential, Pack = 1)]
293
internal struct LENOVO_SPECTRUM_KEY_STATE
294
{
295
    public ushort Key;
296
    public LENOVO_SPECTRUM_COLOR Color;
297
}
298

299
[StructLayout(LayoutKind.Sequential, Size = 960)]
300
internal struct LENOVO_SPECTRUM_STATE
301
{
302
    public byte ReportId;
303
    public LENOVO_SPECTRUM_OPERATION_TYPE Type;
304
    public byte Unknown2;
305
    public byte Unknown3;
306
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 191)]
307
    public LENOVO_SPECTRUM_KEY_STATE[] Data;
308
    public byte Unknown4;
309
}
310

311
#endregion
312

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.