kvm-guest-drivers-windows

Форк
0
546 строк · 18.1 Кб
1
/*
2
 * Keyboard specific HID functionality
3
 *
4
 * Copyright (c) 2016-2017 Red Hat, Inc.
5
 *
6
 * Author(s):
7
 *  Ladi Prosek <lprosek@redhat.com>
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met :
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and / or other materials provided with the distribution.
17
 * 3. Neither the names of the copyright holders nor the names of their contributors
18
 *    may be used to endorse or promote products derived from this software
19
 *    without specific prior written permission.
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32

33
#include "precomp.h"
34
#include "vioinput.h"
35
#include "Hid.h"
36

37
#if defined(EVENT_TRACING)
38
#include "HidKeyboard.tmh"
39
#endif
40

41
typedef struct _tagInputClassKeyboard
42
{
43
    INPUT_CLASS_COMMON Common;
44

45
#define HID_KEYBOARD_KEY_SLOTS 6
46
    // the keyboard HID report is laid out as follows:
47
    // offset 0
48
    // * report ID
49
    // offset 1
50
    // * 8 modifiers; one bit per modifier
51
    // offset 2
52
    // * padding
53
    // offset 3
54
    // * key array of length HID_KEYBOARD_KEY_SLOTS; one byte per key
55

56
    // bitmap of currently pressed keys
57
    PUCHAR pKeysPressed;
58
    // length of the pKeysPressed bitmap in bytes
59
    SIZE_T cbKeysPressedLen;
60
    // number of keys currently pressed
61
    SIZE_T nKeysPressed;
62
    // size of the output (host -> device) report
63
    SIZE_T cbOutputReport;
64
    // last seen output (host -> device) report
65
    PUCHAR pLastOutputReport;
66
} INPUT_CLASS_KEYBOARD, *PINPUT_CLASS_KEYBOARD;
67

68
static UCHAR
69
HIDLEDEventCodeToUsageCode(
70
    USHORT uEventCode)
71
{
72
    switch (uEventCode)
73
    {
74
    case LED_NUML:     return HID_USAGE_LED_NUM_LOCK;
75
    case LED_CAPSL:    return HID_USAGE_LED_CAPS_LOCK;
76
    case LED_SCROLLL:  return HID_USAGE_LED_SCROLL_LOCK;
77
    case LED_COMPOSE:  return HID_USAGE_LED_COMPOSE;
78
    case LED_KANA:     return HID_USAGE_LED_KANA;
79
    case LED_SLEEP:    return HID_USAGE_LED_STAND_BY;
80
    case LED_SUSPEND:  return HID_USAGE_LED_SYSTEM_SUSPEND;
81
    case LED_MUTE:     return HID_USAGE_LED_MUTE;
82
    case LED_MISC:     return HID_USAGE_LED_GENERIC_INDICATOR;
83
    case LED_MAIL:     return HID_USAGE_LED_MESSAGE_WAITING;
84
    case LED_CHARGING: return HID_USAGE_LED_EXTERNAL_POWER_CONNECTED;
85
    }
86
    return 0;
87
}
88

89
static USHORT
90
HIDLEDUsageCodeToEventCode(
91
    ULONG uCode)
92
{
93
    switch (uCode)
94
    {
95
    case HID_USAGE_LED_NUM_LOCK:                 return LED_NUML;
96
    case HID_USAGE_LED_CAPS_LOCK:                return LED_CAPSL;
97
    case HID_USAGE_LED_SCROLL_LOCK:              return LED_SCROLLL;
98
    case HID_USAGE_LED_COMPOSE:                  return LED_COMPOSE;
99
    case HID_USAGE_LED_KANA:                     return LED_KANA;
100
    case HID_USAGE_LED_STAND_BY:                 return LED_SLEEP;
101
    case HID_USAGE_LED_SYSTEM_SUSPEND:           return LED_SUSPEND;
102
    case HID_USAGE_LED_MUTE:                     return LED_MUTE;
103
    case HID_USAGE_LED_GENERIC_INDICATOR:        return LED_MISC;
104
    case HID_USAGE_LED_MESSAGE_WAITING:          return LED_MAIL;
105
    case HID_USAGE_LED_EXTERNAL_POWER_CONNECTED: return LED_CHARGING;
106
    }
107
    return 0xFF;
108
}
109

110
static VOID
111
HIDKeyboardEventKeyToReportKey(
112
    PINPUT_CLASS_KEYBOARD pKeyboardDesc,
113
    UCHAR uCode,
114
    ULONG uValue)
115
{
116
    PUCHAR pKeyArray = pKeyboardDesc->Common.pHidReport + HID_REPORT_DATA_OFFSET + 2;
117
    BOOLEAN bPressed = FALSE, bReleased = FALSE;
118
    UCHAR uMask, uByte, uBit;
119
    SIZE_T i, iIndex;
120

121
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "--> %s\n", __FUNCTION__);
122

123
    // figure out the bitmap index and mask
124
    iIndex = uCode / 8;
125
    uMask = 1 << (uCode % 8);
126

127
    // set or clear the corresponding bitmap bit
128
    if (uValue)
129
    {
130
        if (!(pKeyboardDesc->pKeysPressed[iIndex] & uMask))
131
        {
132
            pKeyboardDesc->nKeysPressed++;
133
            pKeyboardDesc->pKeysPressed[iIndex] |= uMask;
134
            bPressed = TRUE;
135
        }
136
    }
137
    else
138
    {
139
        if (pKeyboardDesc->pKeysPressed[iIndex] & uMask)
140
        {
141
            pKeyboardDesc->nKeysPressed--;
142
            pKeyboardDesc->pKeysPressed[iIndex] &= ~uMask;
143
            bReleased = TRUE;
144
        }
145
    }
146

147
    // update the HID report key array
148
    if (bPressed)
149
    {
150
        if (pKeyboardDesc->nKeysPressed <= HID_KEYBOARD_KEY_SLOTS)
151
        {
152
            PUCHAR pSlot = memchr(pKeyArray, 0, HID_KEYBOARD_KEY_SLOTS);
153
            ASSERT(pSlot);
154
            if (pSlot)
155
            {
156
                *pSlot = uCode;
157
            }
158
        }
159
        else if (pKeyboardDesc->nKeysPressed == HID_KEYBOARD_KEY_SLOTS + 1)
160
        {
161
            // we just got into the "rolled over" state
162
#pragma warning (push)
163
#pragma warning (disable:28625) // C28625 heuristic triggered by "key" in the variable name
164
            RtlFillMemory(pKeyArray, HID_KEYBOARD_KEY_SLOTS, HID_USAGE_KEYBOARD_ROLLOVER);
165
#pragma warning (pop)
166
        }
167
    }
168
    else if (bReleased)
169
    {
170
        if (pKeyboardDesc->nKeysPressed < HID_KEYBOARD_KEY_SLOTS)
171
        {
172
            PUCHAR pSlot = memchr(pKeyArray, uCode, HID_KEYBOARD_KEY_SLOTS);
173
            ASSERT(pSlot);
174
            if (pSlot)
175
            {
176
                *pSlot = 0;
177
            }
178
        }
179
        else if (pKeyboardDesc->nKeysPressed == HID_KEYBOARD_KEY_SLOTS)
180
        {
181
            // we just got out of the "rolled over" state
182
            i = 0;
183
            for (iIndex = 0; iIndex < pKeyboardDesc->cbKeysPressedLen; iIndex++)
184
            {
185
                uByte = pKeyboardDesc->pKeysPressed[iIndex];
186
                while (DecodeNextBit(&uByte, &uBit))
187
                {
188
                    ASSERT(i < HID_KEYBOARD_KEY_SLOTS);
189
                    if (i < HID_KEYBOARD_KEY_SLOTS)
190
                    {
191
                        pKeyArray[i++] = (UCHAR)(8 * iIndex + uBit);
192
                    }
193
                }
194
            }
195
        }
196
    }
197

198
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- %s\n", __FUNCTION__);
199
}
200

201
static NTSTATUS
202
HIDKeyboardEventToReport(
203
    PINPUT_CLASS_COMMON pClass,
204
    PVIRTIO_INPUT_EVENT pEvent)
205
{
206
    PUCHAR pReport = pClass->pHidReport;
207
    PINPUT_CLASS_KEYBOARD pKeyboardDesc = (PINPUT_CLASS_KEYBOARD)pClass;
208

209
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "--> %s\n", __FUNCTION__);
210

211
    pReport[HID_REPORT_ID_OFFSET] = pClass->uReportID;
212
    if (pEvent->type == EV_KEY)
213
    {
214
        ULONG uCode = HIDKeyboardEventCodeToUsageCode(pEvent->code);
215
        if (uCode >= 0xE0 && uCode <= 0xE7)
216
        {
217
            // one bit per modifier, all in one byte
218
            unsigned char uMask = 1 << (uCode - 0xE0);
219
            if (pEvent->value)
220
            {
221
                pReport[HID_REPORT_DATA_OFFSET] |= uMask;
222
            }
223
            else
224
            {
225
                pReport[HID_REPORT_DATA_OFFSET] &= ~uMask;
226
            }
227
            pClass->bDirty = TRUE;
228
        }
229
        else if (uCode != 0)
230
        {
231
            HIDKeyboardEventKeyToReportKey(pKeyboardDesc, (UCHAR)uCode, pEvent->value);
232
            pClass->bDirty = TRUE;
233
        }
234
    }
235

236
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- %s\n", __FUNCTION__);
237
    return STATUS_SUCCESS;
238
}
239

240
static NTSTATUS
241
HIDKeyboardSendStatus(
242
    PINPUT_DEVICE pContext,
243
    USHORT uType,
244
    USHORT uCode,
245
    ULONG uValue,
246
    WDFREQUEST Request)
247
{
248
    PVIRTIO_INPUT_EVENT_WITH_REQUEST pEvent;
249
    NTSTATUS status;
250
    PHYSICAL_ADDRESS pa;
251

252
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> %s\n", __FUNCTION__);
253

254
    pEvent = pContext->StatusQMemBlock->get_slice(pContext->StatusQMemBlock, &pa);
255
    if (pEvent == NULL)
256
    {
257
        status = STATUS_INSUFFICIENT_RESOURCES;
258
    }
259
    else
260
    {
261
        pEvent->Event.type = uType;
262
        pEvent->Event.code = uCode;
263
        pEvent->Event.value = uValue;
264
        pEvent->Request = Request;
265

266
        WdfSpinLockAcquire(pContext->StatusQLock);
267
        status = VIOInputAddOutBuf(pContext->StatusQ, &pEvent->Event, pa);
268
        WdfSpinLockRelease(pContext->StatusQLock);
269
        if (!NT_SUCCESS(status))
270
        {
271
            pContext->StatusQMemBlock->return_slice(pContext->StatusQMemBlock, pEvent);
272
        }
273
    }
274

275
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- %s\n", __FUNCTION__);
276
    return status;
277
}
278

279
static NTSTATUS
280
HIDKeyboardReportToEvent(
281
    PINPUT_CLASS_COMMON pClass,
282
    PINPUT_DEVICE pContext,
283
    WDFREQUEST Request,
284
    PUCHAR pReport,
285
    ULONG cbReport)
286
{
287
    PINPUT_CLASS_KEYBOARD pKeyboardDesc = (PINPUT_CLASS_KEYBOARD)pClass;
288
    USHORT uPendingLedCode = 0xFF;
289
    USHORT uShortPendingLedValue = 0;
290
    NTSTATUS status = STATUS_SUCCESS;
291
    SIZE_T i;
292

293
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> %s\n", __FUNCTION__);
294

295
    if (cbReport < pKeyboardDesc->cbOutputReport)
296
    {
297
        // unexpected output report size
298
        return STATUS_BUFFER_TOO_SMALL;
299
    }
300
    if (pReport[HID_REPORT_ID_OFFSET] != pClass->uReportID)
301
    {
302
        // unexpected output report ID
303
        return STATUS_INVALID_PARAMETER;
304
    }
305

306
    // diff this report with the last one we've seen
307
    for (i = HID_REPORT_DATA_OFFSET; i < pKeyboardDesc->cbOutputReport; i++)
308
    {
309
        UCHAR uDiff = pKeyboardDesc->pLastOutputReport[i] ^ pReport[i];
310
        UCHAR uValue;
311
        while (DecodeNextBit(&uDiff, &uValue))
312
        {
313
            ULONG uCode = uValue + 8 * (ULONG)(i - HID_REPORT_DATA_OFFSET);
314

315
            // LED codes are 1-based
316
            USHORT uLedCode = HIDLEDUsageCodeToEventCode(uCode + 1);
317
            if (uLedCode != 0xFF)
318
            {
319
                if (uPendingLedCode != 0xFF)
320
                {
321
                    // send the pending LED change to the host
322
                    status = HIDKeyboardSendStatus(pContext, EV_LED, uPendingLedCode,
323
                                                   uShortPendingLedValue, NULL);
324
                    if (!NT_SUCCESS(status))
325
                    {
326
                        return status;
327
                    }
328
                }
329
                uPendingLedCode = uLedCode;
330
                uShortPendingLedValue = !!(pReport[i] & (1 << uValue));
331
            }
332
        }
333
    }
334

335
    // send the last pending LED change; this one will complete the request
336
    if (uPendingLedCode != 0xFF)
337
    {
338
        status = HIDKeyboardSendStatus(pContext, EV_LED, uPendingLedCode,
339
                                       uShortPendingLedValue, Request);
340
    }
341

342
    if (NT_SUCCESS(status))
343
    {
344
        // save this report
345
        RtlCopyMemory(pKeyboardDesc->pLastOutputReport, pReport,
346
                      pKeyboardDesc->cbOutputReport);
347
    }
348
    if (uPendingLedCode == 0xFF)
349
    {
350
        // nothing was sent up, complete the request now
351
        WdfRequestComplete(Request, status);
352
    }
353

354
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- %s\n", __FUNCTION__);
355
    return status;
356
}
357

358
static VOID
359
HIDKeyboardCleanup(
360
    PINPUT_CLASS_COMMON pClass)
361
{
362
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__);
363

364
    PINPUT_CLASS_KEYBOARD pKeyboardDesc = (PINPUT_CLASS_KEYBOARD)pClass;
365
    VIOInputFree(&pKeyboardDesc->pLastOutputReport);
366
    VIOInputFree(&pKeyboardDesc->pKeysPressed);
367

368
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__);
369
}
370

371
NTSTATUS
372
HIDKeyboardProbe(
373
    PINPUT_DEVICE pContext,
374
    PDYNAMIC_ARRAY pHidDesc,
375
    PVIRTIO_INPUT_CFG_DATA pKeys,
376
    PVIRTIO_INPUT_CFG_DATA pLeds)
377
{
378
    PINPUT_CLASS_KEYBOARD pKeyboardDesc = NULL;
379
    NTSTATUS status = STATUS_SUCCESS;
380
    UCHAR i, uValue, uMaxKey, uMaxLed;
381
    BOOLEAN bGotKey, bGotLed;
382

383
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__);
384

385
    uMaxKey = 0;
386
    bGotKey = FALSE;
387
    for (i = 0; i < pKeys->size; i++)
388
    {
389
        UCHAR uNonKeys = 0;
390
        while (DecodeNextBit(&pKeys->u.bitmap[i], &uValue))
391
        {
392
            USHORT uKeyCode = uValue + 8 * i;
393
            ULONG uCode = HIDKeyboardEventCodeToUsageCode(uKeyCode);
394
            if (uCode != 0 && (uCode & KEY_TYPE_MASK) == KEY_TYPE_KEYBOARD)
395
            {
396
                bGotKey = TRUE;
397
                if (uCode < 0xE0 || uCode > 0xE7)
398
                {
399
                    uMaxKey = max(uMaxKey, (UCHAR)uCode);
400
                }
401
            }
402
            else
403
            {
404
                // we have not recognized this EV_KEY code as a keyboard key
405
                uNonKeys |= (1 << uValue);
406
            }
407
        }
408
        pKeys->u.bitmap[i] = uNonKeys;
409
    }
410

411
    if (!bGotKey)
412
    {
413
        // no keys in the array means that we're done
414
        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "No keyboard key found\n");
415
        goto Exit;
416
    }
417

418
    // allocate and initialize pKeyboardDesc
419
    pKeyboardDesc = VIOInputAlloc(sizeof(INPUT_CLASS_KEYBOARD));
420
    if (pKeyboardDesc == NULL)
421
    {
422
        status = STATUS_INSUFFICIENT_RESOURCES;
423
        goto Exit;
424
    }
425
    pKeyboardDesc->Common.EventToReportFunc = HIDKeyboardEventToReport;
426
    pKeyboardDesc->Common.ReportToEventFunc = HIDKeyboardReportToEvent;
427
    pKeyboardDesc->Common.CleanupFunc = HIDKeyboardCleanup;
428
    pKeyboardDesc->Common.uReportID = (UCHAR)(pContext->uNumOfClasses + 1);
429

430
    HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_GENERIC);
431
    HIDAppend2(pHidDesc, HID_TAG_USAGE, HID_USAGE_GENERIC_KEYBOARD);
432
    HIDAppend2(pHidDesc, HID_TAG_COLLECTION, HID_COLLECTION_APPLICATION);
433

434
    HIDAppend2(pHidDesc, HID_TAG_REPORT_ID, pKeyboardDesc->Common.uReportID);
435

436
    // one bit per modifier
437
    HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_KEYBOARD);
438
    HIDAppend2(pHidDesc, HID_TAG_USAGE_MINIMUM, 0xE0);
439
    HIDAppend2(pHidDesc, HID_TAG_USAGE_MAXIMUM, 0xE7);
440
    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MINIMUM, 0x00);
441
    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MAXIMUM, 0x01);
442
    HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x01);
443
    HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, 0x08);
444
    HIDAppend2(pHidDesc, HID_TAG_INPUT, HID_DATA_FLAG_VARIABLE);
445

446
    // reserved byte
447
    HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x01);
448
    HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, 0x08);
449
    HIDAppend2(pHidDesc, HID_TAG_INPUT, HID_DATA_FLAG_CONSTANT);
450

451
    // LEDs
452
    uMaxLed = 0;
453
    bGotLed = FALSE;
454
    for (i = 0; i < pLeds->size; i++)
455
    {
456
        while (DecodeNextBit(&pLeds->u.bitmap[i], &uValue))
457
        {
458
            USHORT uLedCode = uValue + 8 * i;
459
            UCHAR uCode = HIDLEDEventCodeToUsageCode(uLedCode);
460
            if (uCode != 0)
461
            {
462
                TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got LED %d\n", uLedCode);
463
                uMaxLed = max(uMaxLed, uCode);
464
                bGotLed = TRUE;
465
            }
466
        }
467
    }
468
    if (bGotLed)
469
    {
470
        ULONG uNumOfLEDs = uMaxLed + 1;
471
        pKeyboardDesc->cbOutputReport = (SIZE_T)HID_REPORT_DATA_OFFSET + (uNumOfLEDs + 7) / 8;
472

473
        // one bit per LED as usual in a keyboard device
474
        HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x01);
475
        HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, uMaxLed + 1);
476
        HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_LED);
477
        HIDAppend2(pHidDesc, HID_TAG_USAGE_MINIMUM, 1);
478
        HIDAppend2(pHidDesc, HID_TAG_USAGE_MAXIMUM, uMaxLed + 1);
479
        HIDAppend2(pHidDesc, HID_TAG_OUTPUT, HID_DATA_FLAG_VARIABLE);
480

481
        // pad to the nearest whole byte
482
        if (uNumOfLEDs % 8)
483
        {
484
            HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, 0x01);
485
            HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE,
486
                       (ULONG)(pKeyboardDesc->cbOutputReport * 8) - uNumOfLEDs);
487
            HIDAppend2(pHidDesc, HID_TAG_OUTPUT, HID_DATA_FLAG_CONSTANT);
488
        }
489

490
        // allocate and initialize a buffer holding the last seen output report
491
        pKeyboardDesc->pLastOutputReport = ExAllocatePoolUninitialized(
492
            NonPagedPool,
493
            pKeyboardDesc->cbOutputReport,
494
            VIOINPUT_DRIVER_MEMORY_TAG);
495
        if (pKeyboardDesc->pLastOutputReport == NULL)
496
        {
497
            return STATUS_INSUFFICIENT_RESOURCES;
498
        }
499
        RtlZeroMemory(pKeyboardDesc->pLastOutputReport, pKeyboardDesc->cbOutputReport);
500
    }
501

502
    // keys
503
    HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x08);
504
    HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, HID_KEYBOARD_KEY_SLOTS);
505
    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MINIMUM, 0x00);
506
    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MAXIMUM, uMaxKey);
507
    HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_KEYBOARD);
508
    HIDAppend2(pHidDesc, HID_TAG_USAGE_MINIMUM, 0x00);
509
    HIDAppend2(pHidDesc, HID_TAG_USAGE_MAXIMUM, uMaxKey);
510
    HIDAppend2(pHidDesc, HID_TAG_INPUT, 0);
511

512
    HIDAppend1(pHidDesc, HID_TAG_END_COLLECTION);
513

514
    // allocate and initialize the bitmap of currently pressed keys
515
    pKeyboardDesc->cbKeysPressedLen = ((uMaxKey + 1) + 7) / 8;
516
    pKeyboardDesc->pKeysPressed = VIOInputAlloc(pKeyboardDesc->cbKeysPressedLen);
517
    if (pKeyboardDesc->pKeysPressed == NULL)
518
    {
519
        status = STATUS_INSUFFICIENT_RESOURCES;
520
        goto Exit;
521
    }
522

523
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
524
                "Created HID keyboard report descriptor with %d keys and %d LEDs\n",
525
                uMaxKey + 1,
526
                bGotLed ? (uMaxLed + 1) : 0);
527

528
    // calculate the keyboard HID report size
529
    pKeyboardDesc->Common.cbHidReportSize =
530
        HID_REPORT_DATA_OFFSET +
531
        2 + // modifiers and padding
532
        HID_KEYBOARD_KEY_SLOTS;
533

534
    // register the keyboard class
535
    status = RegisterClass(pContext, &pKeyboardDesc->Common);
536

537
Exit:
538
    if (!NT_SUCCESS(status) && pKeyboardDesc != NULL)
539
    {
540
        pKeyboardDesc->Common.CleanupFunc(&pKeyboardDesc->Common);
541
        VIOInputFree(&pKeyboardDesc);
542
    }
543

544
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s (%08x)\n", __FUNCTION__, status);
545
    return status;
546
}
547

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

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

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

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