Skip to content

Commit e69cb3b

Browse files
TitanHZZCalcProgrammer1
authored andcommitted
Add support for 4-zone HP Omen laptops on Windows
Commits squashed and cleaned up by Adam Honse <calcprogrammer1@gmail.com>
1 parent c58ae26 commit e69cb3b

5 files changed

Lines changed: 594 additions & 0 deletions
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
/*---------------------------------------------------------*\
2+
| HPOmenLaptopController_Windows.cpp |
3+
| |
4+
| Driver for HP Omen laptop |
5+
| |
6+
| This file is part of the OpenRGB project |
7+
| SPDX-License-Identifier: GPL-2.0-or-later |
8+
\*---------------------------------------------------------*/
9+
10+
#include "HPOmenLaptopController_Windows.h"
11+
#include <Wbemidl.h>
12+
#include <comdef.h>
13+
14+
#define RESULT_STEP 5
15+
#define PARAM_STEP 4
16+
#define OBJ_STEP 3
17+
#define SERVICE_STEP 2
18+
#define LOCATE_STEP 1
19+
#define INIT_STEP 0
20+
21+
HPOmenLaptopController_Windows::HPOmenLaptopController_Windows()
22+
{
23+
24+
}
25+
26+
HPOmenLaptopController_Windows::~HPOmenLaptopController_Windows()
27+
{
28+
29+
}
30+
31+
void HPOmenLaptopController_Windows::cleanup(int fail_level)
32+
{
33+
/*-----------------------------------------------------*\
34+
| Cleanup for the execute method |
35+
\*-----------------------------------------------------*/
36+
37+
switch(fail_level)
38+
{
39+
case RESULT_STEP:
40+
if (callResult)
41+
{
42+
callResult->Release();
43+
}
44+
case PARAM_STEP:
45+
methodParameters->Release();
46+
case OBJ_STEP:
47+
classObject->Release();
48+
case SERVICE_STEP:
49+
pSvc->Release();
50+
case LOCATE_STEP:
51+
pLoc->Release();
52+
case INIT_STEP:
53+
CoUninitialize();
54+
}
55+
}
56+
57+
int HPOmenLaptopController_Windows::execute(int command, int commandType, int inputDataSize, BYTE* inputData, int* returnDataSize, BYTE** returnData)
58+
{
59+
/*-----------------------------------------------------*\
60+
| Talk to WMI |
61+
\*-----------------------------------------------------*/
62+
// magic constant
63+
static const BYTE Sign[4] = { 83, 69, 67, 85 };
64+
65+
// will hold the return codes from all the calls to WMI
66+
HRESULT hres;
67+
68+
// initialize COM interface
69+
hres = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
70+
if(FAILED(hres))
71+
{
72+
return 1;
73+
}
74+
75+
// obtain the initial locator to the Windows Management Instrumentation
76+
pLoc = nullptr;
77+
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*) &pLoc );
78+
if(FAILED(hres))
79+
{
80+
cleanup(INIT_STEP);
81+
return 1;
82+
}
83+
84+
pSvc = nullptr;
85+
hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\WMI"), NULL, NULL, 0, NULL, 0, 0, &pSvc);
86+
if(FAILED(hres))
87+
{
88+
cleanup(LOCATE_STEP);
89+
return 1;
90+
}
91+
92+
hres = CoSetProxyBlanket(
93+
pSvc, // Indicates the proxy to set
94+
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
95+
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
96+
NULL, // Server principal name
97+
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
98+
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
99+
NULL, // client identity
100+
EOAC_NONE // proxy capabilities
101+
);
102+
103+
if(FAILED(hres))
104+
{
105+
cleanup(SERVICE_STEP);
106+
return 1;
107+
}
108+
109+
/*-----------------------------------------------------*\
110+
| Get all the required custom hp wmi obejcts |
111+
\*-----------------------------------------------------*/
112+
classObject = nullptr;
113+
hres = pSvc->GetObject(_bstr_t(L"hpqBIntM"), 0, NULL, &classObject, NULL);
114+
if(FAILED(hres))
115+
{
116+
cleanup(SERVICE_STEP);
117+
return 1;
118+
}
119+
120+
methodParameters = nullptr;
121+
hres = classObject->GetMethod(L"hpqBIOSInt128", 0, &methodParameters, NULL);
122+
if(FAILED(hres))
123+
{
124+
cleanup(OBJ_STEP);
125+
return 1;
126+
}
127+
128+
dataInClass = nullptr;
129+
hres = pSvc->GetObject(_bstr_t(L"hpqBDataIn"), 0, NULL, &dataInClass, NULL);
130+
if(FAILED(hres))
131+
{
132+
cleanup(PARAM_STEP);
133+
return 1;
134+
}
135+
136+
callResult = nullptr;
137+
hres = pSvc->GetObject(_bstr_t(L"hpqBDataOut128"), 0, NULL, NULL, &callResult);
138+
if(FAILED(hres))
139+
{
140+
dataInClass->Release();
141+
cleanup(PARAM_STEP);
142+
return 1;
143+
}
144+
145+
/*-----------------------------------------------------*\
146+
| Populate the input parameters |
147+
\*-----------------------------------------------------*/
148+
// Sign
149+
VARIANT signVar;
150+
VariantInit(&signVar);
151+
signVar.vt = VT_UI1 | VT_ARRAY;
152+
SAFEARRAYBOUND safeArrayBound = { 4, 0 };
153+
signVar.parray = SafeArrayCreate(VT_UI1, 1, &safeArrayBound);
154+
SafeArrayLock(signVar.parray);
155+
memcpy(signVar.parray->pvData, Sign, sizeof(Sign));
156+
SafeArrayUnlock(signVar.parray);
157+
dataInClass->Put(L"Sign", 0, &signVar, 0);
158+
VariantClear(&signVar);
159+
160+
// Command
161+
VARIANT commandVar;
162+
VariantInit(&commandVar);
163+
commandVar.vt = VT_I4;
164+
commandVar.lVal = command;
165+
dataInClass->Put(L"Command", 0, &commandVar, 0);
166+
VariantClear(&commandVar);
167+
168+
// CommandType
169+
VARIANT commandTypeVar;
170+
VariantInit(&commandTypeVar);
171+
commandTypeVar.vt = VT_I4;
172+
commandTypeVar.lVal = commandType;
173+
dataInClass->Put(L"CommandType", 0, &commandTypeVar, 0);
174+
VariantClear(&commandTypeVar);
175+
176+
// Size
177+
VARIANT sizeVar;
178+
VariantInit(&sizeVar);
179+
sizeVar.vt = VT_I4;
180+
sizeVar.lVal = inputDataSize;
181+
dataInClass->Put(L"Size", 0, &sizeVar, 0);
182+
183+
// hpqBData
184+
VARIANT hpqBDataVar;
185+
VariantInit(&hpqBDataVar);
186+
hpqBDataVar.vt = VT_UI1 | VT_ARRAY;
187+
SAFEARRAYBOUND safeArrayBoundData = { static_cast<ULONG>(inputDataSize), 0 };
188+
hpqBDataVar.parray = SafeArrayCreate(VT_UI1, 1, &safeArrayBoundData);
189+
SafeArrayLock(hpqBDataVar.parray);
190+
memcpy(hpqBDataVar.parray->pvData, inputData, inputDataSize);
191+
SafeArrayUnlock(hpqBDataVar.parray);
192+
dataInClass->Put(L"hpqBData", 0, &hpqBDataVar, 0);
193+
VariantClear(&hpqBDataVar);
194+
195+
/*-----------------------------------------------------------*\
196+
| Fill the 'InData' parameter from the 'hpqBIOSInt128' method |
197+
\*-----------------------------------------------------------*/
198+
199+
// InData
200+
VARIANT inDataVar;
201+
VariantInit(&inDataVar);
202+
inDataVar.vt = VT_UNKNOWN;
203+
inDataVar.punkVal = dataInClass;
204+
methodParameters->Put(L"InData", 0, &inDataVar, 0);
205+
VariantClear(&inDataVar);
206+
207+
/*-----------------------------------------------------------*\
208+
| Call the 'hpqBIOSInt128' method from the 'hpqBIntM' class |
209+
\*-----------------------------------------------------------*/
210+
211+
hres = pSvc->ExecMethod(_bstr_t(L"hpqBIntM.InstanceName='ACPI\\PNP0C14\\0_0'"), _bstr_t(L"hpqBIOSInt128"), 0, NULL, methodParameters, NULL, &callResult);
212+
if(FAILED(hres))
213+
{
214+
cleanup(RESULT_STEP);
215+
return 1;
216+
}
217+
218+
/*-------------------------------------------------------*\
219+
| Get the returned data |
220+
\*-------------------------------------------------------*/
221+
if(returnDataSize != NULL && returnData != NULL)
222+
{
223+
IWbemClassObject* ppResultObject = nullptr;
224+
callResult->GetResultObject(WBEM_INFINITE, &ppResultObject);
225+
226+
// get OutData from object returned (is an object of type hpqBDataOut128)
227+
VARIANT outDataVar;
228+
VariantInit(&outDataVar);
229+
ppResultObject->Get(L"OutData", 0, &outDataVar, NULL, NULL);
230+
231+
// get 'Data' property from the object returned
232+
IWbemClassObject* retData = (IWbemClassObject*)outDataVar.punkVal;
233+
retData->Get(L"Data", 0, &outDataVar, NULL, NULL);
234+
235+
// extract the byte array from the result VARIANT
236+
long lower, upper;
237+
SAFEARRAY* safeArray = outDataVar.parray;
238+
SafeArrayGetLBound(safeArray, 1, &lower);
239+
SafeArrayGetUBound(safeArray, 1, &upper);
240+
long length = upper - lower + 1;
241+
*returnData = new BYTE[length];
242+
*returnDataSize = length;
243+
SafeArrayLock(safeArray);
244+
memcpy(*returnData, safeArray->pvData, length);
245+
SafeArrayUnlock(safeArray);
246+
247+
// cleanup
248+
retData->Release();
249+
VariantClear(&outDataVar);
250+
ppResultObject->Release();
251+
}
252+
253+
// cleanup
254+
cleanup(RESULT_STEP);
255+
return 0;
256+
}
257+
258+
void HPOmenLaptopController_Windows::setColors(std::vector<RGBColor>& colors)
259+
{
260+
/*-----------------------------------------------------*\
261+
| Set the new colors |
262+
\*-----------------------------------------------------*/
263+
int returnDataSize = 0;
264+
BYTE* returnData = nullptr;
265+
int num = execute(131081, 2, 0, nullptr, &returnDataSize, &returnData);
266+
267+
if(num == 0 && returnData != nullptr)
268+
{
269+
// prepare the data byte array to be sent to WMI
270+
for (int i = 0; i < 4; i++)
271+
{
272+
returnData[25 + i * 3] = RGBGetRValue(colors[3 - i]);
273+
returnData[25 + i * 3 + 1] = RGBGetGValue(colors[3 - i]);
274+
returnData[25 + i * 3 + 2] = RGBGetBValue(colors[3 - i]);
275+
}
276+
277+
// make the WMI call to set the colors
278+
execute(131081, 3, returnDataSize, returnData, NULL, NULL);
279+
delete[] returnData;
280+
}
281+
}
282+
283+
bool HPOmenLaptopController_Windows::isLightingSupported()
284+
{
285+
/*-----------------------------------------------------*\
286+
| Check if the laptop supports rgb lighting |
287+
\*-----------------------------------------------------*/
288+
289+
BYTE b = 0;
290+
int returnDataSize = 0;
291+
BYTE* returnData = nullptr;
292+
if(execute(131081, 1, 0, nullptr, &returnDataSize, &returnData) == 0)
293+
{
294+
b = (BYTE)(returnData[0] & 1u);
295+
}
296+
297+
delete[] returnData;
298+
return b == 1;
299+
}
300+
301+
KeyboardType HPOmenLaptopController_Windows::getKeyboardType()
302+
{
303+
/*-----------------------------------------------------*\
304+
| Get keyboard type |
305+
\*-----------------------------------------------------*/
306+
int returnDataSize = 0;
307+
BYTE* returnData = nullptr;
308+
if(execute(131080, 43, 0, nullptr, &returnDataSize, &returnData) == 0)
309+
{
310+
int result = returnData[0];
311+
delete[] returnData;
312+
return (KeyboardType)(result + 1);
313+
}
314+
315+
return KeyboardType::INVALID;
316+
}
317+
318+
void HPOmenLaptopController_Windows::changeMode(KeyboardMode mode)
319+
{
320+
/*-----------------------------------------------------*\
321+
| Change keyboard rgb mode |
322+
\*-----------------------------------------------------*/
323+
switch(mode)
324+
{
325+
case KeyboardMode::OFF:
326+
{
327+
BYTE array[4] = { 100, 0, 0, 0 };
328+
execute(131081, 5, sizeof(array), array, NULL, NULL);
329+
break;
330+
}
331+
case KeyboardMode::DIRECT:
332+
{
333+
BYTE array[4] = { 228, 0, 0, 0 };
334+
execute(131081, 5, sizeof(array), array, NULL, NULL);
335+
break;
336+
}
337+
default:
338+
break;
339+
}
340+
}

0 commit comments

Comments
 (0)