kvm-guest-drivers-windows

Форк
0
563 строки · 21.6 Кб
1
/*
2
 * Mouse 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 "HidMouse.tmh"
39
#endif
40

41
// initial length of the axis map (will grow as needed)
42
#define AXIS_MAP_INITIAL_LENGTH 4
43

44
typedef struct _tagInputClassMouse
45
{
46
    INPUT_CLASS_COMMON Common;
47

48
    // the mouse HID report is laid out as follows:
49
    // offset 0
50
    // * report ID
51
    // offset 1
52
    // * buttons; one bit per button followed by padding to the nearest whole byte
53
    // offset cbAxisOffset
54
    // * axes; one byte per axis, mapping in pAxisMap
55
    // offset cbAxisOffset + cbAxisLen
56
    // * vertical wheel; one byte, if uFlags & CLASS_MOUSE_HAS_V_WHEEL
57
    // * horizontal wheel; one byte, if uFlags & CLASS_MOUSE_HAS_H_WHEEL
58

59
    // number of buttons supported by the HID report
60
    ULONG  uNumOfButtons;
61
    // offset of axis data within the HID report
62
    SIZE_T cbAxisOffset;
63
    // length of axis data
64
    SIZE_T cbAxisLen;
65
    // mapping from EVDEV axis codes to HID axis offsets
66
    PULONG pAxisMap;
67
    // flags
68
#define CLASS_MOUSE_HAS_V_WHEEL         0x01
69
#define CLASS_MOUSE_HAS_H_WHEEL         0x02
70
#define CLASS_MOUSE_SUPPORTS_REL_WHEEL  0x04
71
#define CLASS_MOUSE_SUPPORTS_REL_HWHEEL 0x08
72
#define CLASS_MOUSE_SUPPORTS_REL_DIAL   0x10
73
    ULONG  uFlags;
74
} INPUT_CLASS_MOUSE, *PINPUT_CLASS_MOUSE;
75

76
static UCHAR FORCEINLINE TrimRelative(long val)
77
{
78
    if (val < -127) {
79
        return (UCHAR)(-127);
80
    } else if (val > 127) {
81
        return 127;
82
    }
83
    return (UCHAR)val;
84
}
85

86
static NTSTATUS
87
HIDMouseEventToReport(
88
    PINPUT_CLASS_COMMON pClass,
89
    PVIRTIO_INPUT_EVENT pEvent)
90
{
91
    PUCHAR pReport = pClass->pHidReport;
92
    PINPUT_CLASS_MOUSE pMouseDesc = (PINPUT_CLASS_MOUSE)pClass;
93
    PULONG pMap;
94

95
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> %s\n", __FUNCTION__);
96

97
    pReport[HID_REPORT_ID_OFFSET] = pClass->uReportID;
98
    switch (pEvent->type)
99
    {
100
#ifdef EXPOSE_ABS_AXES_WITH_BUTTONS_AS_MOUSE
101
    case EV_ABS:
102
#endif // EXPOSE_ABS_AXES_WITH_BUTTONS_AS_MOUSE
103
    case EV_REL:
104
        if (pMouseDesc->pAxisMap)
105
        {
106
            for (pMap = pMouseDesc->pAxisMap; pMap[0] != (ULONG)-1; pMap += 2)
107
            {
108
                // axis map handles regular relative axes as well as wheels
109
                if (pMap[0] == ((pEvent->type << 16) | pEvent->code))
110
                {
111
#ifdef EXPOSE_ABS_AXES_WITH_BUTTONS_AS_MOUSE
112
                    if (pEvent->type == EV_ABS)
113
                    {
114
                        // 2 bytes per absolute axis
115
                        PUSHORT pAxisPtr = (PUSHORT)&pReport[pMouseDesc->cbAxisOffset + pMap[1]];
116
                        *pAxisPtr = (USHORT)pEvent->value;
117
                    }
118
                    else
119
#endif // EXPOSE_ABS_AXES_WITH_BUTTONS_AS_MOUSE
120
                    {
121
                        pReport[pMouseDesc->cbAxisOffset + pMap[1]] = TrimRelative((long)pEvent->value);
122
                    }
123
                    pClass->bDirty = TRUE;
124
                    break;
125
                }
126
            }
127
        }
128
        break;
129

130
    case EV_KEY:
131
        if (pEvent->code == BTN_GEAR_DOWN || pEvent->code == BTN_GEAR_UP)
132
        {
133
            if (pEvent->value && (pMouseDesc->uFlags & CLASS_MOUSE_HAS_V_WHEEL))
134
            {
135
                // increment/decrement the vertical wheel field
136
                CHAR delta = (pEvent->code == BTN_GEAR_DOWN ? -1 : 1);
137
                pReport[pMouseDesc->cbAxisOffset + pMouseDesc->cbAxisLen] += delta;
138
                pClass->bDirty = TRUE;
139
            }
140
        }
141
        else if (pEvent->code >= BTN_MOUSE && pEvent->code < BTN_JOYSTICK)
142
        {
143
            USHORT uButton = pEvent->code - BTN_MOUSE;
144
            if (uButton < pMouseDesc->uNumOfButtons)
145
            {
146
                USHORT uOffset = uButton / 8;
147
                UCHAR uBit = 1 << (uButton % 8);
148
                if (pEvent->value)
149
                {
150
                    pReport[HID_REPORT_DATA_OFFSET + uOffset] |= uBit;
151
                }
152
                else
153
                {
154
                    pReport[HID_REPORT_DATA_OFFSET + uOffset] &= ~uBit;
155
                }
156
                pClass->bDirty = TRUE;
157
            }
158
        }
159
        break;
160

161
    case EV_SYN:
162
        // reset all relative axes and wheel to 0, buttons stay unchanged
163
        for (pMap = pMouseDesc->pAxisMap; pMap[0] != (ULONG)-1; pMap += 2)
164
        {
165
            if ((pMap[0] >> 16) == EV_REL)
166
            {
167
                pReport[pMouseDesc->cbAxisOffset + pMap[1]] = 0;
168
            }
169
        }
170
        if ((pMouseDesc->uFlags & (CLASS_MOUSE_HAS_V_WHEEL | CLASS_MOUSE_SUPPORTS_REL_WHEEL))
171
            == CLASS_MOUSE_HAS_V_WHEEL)
172
        {
173
            // button-based vertical wheel
174
            pReport[pMouseDesc->cbAxisOffset + pMouseDesc->cbAxisLen] = 0;
175
        }
176
        break;
177
    }
178

179
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- %s\n", __FUNCTION__);
180
    return STATUS_SUCCESS;
181
}
182

183
static VOID
184
HIDMouseCleanup(
185
    PINPUT_CLASS_COMMON pClass)
186
{
187
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__);
188

189
    PINPUT_CLASS_MOUSE pMouseDesc = (PINPUT_CLASS_MOUSE)pClass;
190
    VIOInputFree(&pMouseDesc->pAxisMap);
191

192
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__);
193
}
194

195
static VOID
196
HIDMouseAxisMapAppend(
197
    PDYNAMIC_ARRAY pAxisMap,
198
    ULONG uCode,
199
    SIZE_T uAxisIndex)
200
{
201
    DynamicArrayAppend(pAxisMap, &uCode, sizeof(ULONG));
202
    DynamicArrayAppend(pAxisMap, &uAxisIndex, sizeof(ULONG));
203
}
204

205
static VOID
206
HIDMouseDescribeWheel(
207
    PDYNAMIC_ARRAY pHidDesc,
208
    ULONG uUsagePage,
209
    ULONG uWheelType)
210
{
211
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__);
212

213
    HIDAppend2(pHidDesc, HID_TAG_COLLECTION, HID_COLLECTION_LOGICAL);
214

215
    // resolution multiplier feature (appears to be mandatory for wheel support)
216
    HIDAppend2(pHidDesc, HID_TAG_USAGE, HID_USAGE_GENERIC_RESOLUTION_MULTIPLIER);
217
    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MINIMUM, 0x00);
218
    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MAXIMUM, 0x01);
219
    HIDAppend2(pHidDesc, HID_TAG_PHYSICAL_MINIMUM, 0x01);
220
    HIDAppend2(pHidDesc, HID_TAG_PHYSICAL_MAXIMUM, 0x04);
221
    HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x02);
222
    HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, 0x01);
223
    HIDAppend2(pHidDesc, HID_TAG_FEATURE, HID_DATA_FLAG_VARIABLE);
224

225
    // the wheel itself
226
    if (uUsagePage != 0)
227
    {
228
        HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, uUsagePage);
229
    }
230
    HIDAppend2(pHidDesc, HID_TAG_USAGE, uWheelType);
231
    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MINIMUM, -127);
232
    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MAXIMUM, 127);
233
    HIDAppend2(pHidDesc, HID_TAG_PHYSICAL_MINIMUM, 0x00);
234
    HIDAppend2(pHidDesc, HID_TAG_PHYSICAL_MAXIMUM, 0x00);
235
    HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x08);
236
    HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, 0x01);
237
    HIDAppend2(pHidDesc, HID_TAG_INPUT, HID_DATA_FLAG_VARIABLE | HID_DATA_FLAG_RELATIVE);
238

239
    HIDAppend1(pHidDesc, HID_TAG_END_COLLECTION);
240

241
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__);
242
}
243

244
NTSTATUS
245
HIDMouseProbe(
246
    PINPUT_DEVICE pContext,
247
    PDYNAMIC_ARRAY pHidDesc,
248
    PVIRTIO_INPUT_CFG_DATA pRelAxes,
249
    PVIRTIO_INPUT_CFG_DATA pAbsAxes,
250
    PVIRTIO_INPUT_CFG_DATA pButtons)
251
{
252
    PINPUT_CLASS_MOUSE pMouseDesc = NULL;
253
    NTSTATUS status = STATUS_SUCCESS;
254
    UCHAR i, uValue;
255
    ULONG uFeatureBitsUsed = 0, uNumOfRelAxes = 0, uNumOfAbsAxes = 0;
256
    BOOLEAN bHasRelXY;
257
    SIZE_T cbFeatureBytes = 0, cbButtonBytes;
258
    SIZE_T cbInitialHidSize = pHidDesc->Size;
259
    DYNAMIC_ARRAY AxisMap = { NULL };
260

261
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__);
262

263
    // allocate and initialize pMouseDesc
264
    pMouseDesc = VIOInputAlloc(sizeof(INPUT_CLASS_MOUSE));
265
    if (pMouseDesc == NULL)
266
    {
267
        status = STATUS_INSUFFICIENT_RESOURCES;
268
        goto Exit;
269
    }
270
    pMouseDesc->Common.EventToReportFunc = HIDMouseEventToReport;
271
    pMouseDesc->Common.CleanupFunc = HIDMouseCleanup;
272
    pMouseDesc->Common.uReportID = (UCHAR)(pContext->uNumOfClasses + 1);
273

274
    HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_GENERIC);
275
    HIDAppend2(pHidDesc, HID_TAG_USAGE, HID_USAGE_GENERIC_MOUSE);
276
    HIDAppend2(pHidDesc, HID_TAG_COLLECTION, HID_COLLECTION_APPLICATION);
277
    HIDAppend2(pHidDesc, HID_TAG_USAGE, HID_USAGE_GENERIC_POINTER);
278
    HIDAppend2(pHidDesc, HID_TAG_COLLECTION, HID_COLLECTION_PHYSICAL);
279

280
    HIDAppend2(pHidDesc, HID_TAG_REPORT_ID, pMouseDesc->Common.uReportID);
281

282
    for (i = 0; i < pButtons->size; i++)
283
    {
284
        unsigned char non_buttons = 0;
285
        while (DecodeNextBit(&pButtons->u.bitmap[i], &uValue))
286
        {
287
            ULONG uButtonCode = uValue + 8 * i;
288
            if (uButtonCode >= BTN_MOUSE && uButtonCode < BTN_JOYSTICK)
289
            {
290
                // individual mouse button functions are not specified in the HID report,
291
                // only their count is; the max button code we find will determine the count
292
                TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got button %d\n", uButtonCode);
293
                pMouseDesc->uNumOfButtons = max(pMouseDesc->uNumOfButtons, uButtonCode - BTN_MOUSE + 1);
294
            }
295
            else if (uButtonCode == BTN_GEAR_DOWN || uButtonCode == BTN_GEAR_UP) 
296
            {
297
                // wheel is modeled as a pair of buttons in evdev but it's an axis in HID
298
                TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got button-based vertical wheel\n");
299
                pMouseDesc->uFlags |= CLASS_MOUSE_HAS_V_WHEEL;
300
            }
301
            else
302
            {
303
                // not a mouse button, put it back and let other devices claim it
304
                TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got non-button key %d\n", uButtonCode);
305
                non_buttons |= (1 << uValue);
306
            }
307
        }
308
        pButtons->u.bitmap[i] = non_buttons;
309
    }
310

311
    cbButtonBytes = (pMouseDesc->uNumOfButtons + 7) / 8;
312
    pMouseDesc->cbAxisOffset = HID_REPORT_DATA_OFFSET + cbButtonBytes;
313
    if (pMouseDesc->uNumOfButtons > 0)
314
    {
315
        // one bit per button as usual in a mouse device
316
        HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_BUTTON);
317
        HIDAppend2(pHidDesc, HID_TAG_USAGE_MINIMUM, 0x01);
318
        HIDAppend2(pHidDesc, HID_TAG_USAGE_MAXIMUM, pMouseDesc->uNumOfButtons);
319
        HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MINIMUM, 0x00);
320
        HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MAXIMUM, 0x01);
321
        HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, pMouseDesc->uNumOfButtons);
322
        HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x01);
323
        HIDAppend2(pHidDesc, HID_TAG_INPUT, HID_DATA_FLAG_VARIABLE);
324

325
        // pad to the nearest whole byte
326
        if (pMouseDesc->uNumOfButtons % 8)
327
        {
328
            HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, 0x01);
329
            HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, (ULONG)(cbButtonBytes * 8) - pMouseDesc->uNumOfButtons);
330
            HIDAppend2(pHidDesc, HID_TAG_INPUT, HID_DATA_FLAG_VARIABLE | HID_DATA_FLAG_CONSTANT);
331
        }
332
    }
333

334
    // describe axes
335
    HIDAppend2(pHidDesc, HID_TAG_USAGE_PAGE, HID_USAGE_PAGE_GENERIC);
336
    DynamicArrayReserve(&AxisMap, AXIS_MAP_INITIAL_LENGTH * 2 * sizeof(ULONG));
337

338
    bHasRelXY = InputCfgDataHasBit(pRelAxes, REL_X) && InputCfgDataHasBit(pRelAxes, REL_Y);
339
    // Windows won't drive a mouse without at least the X and Y relative axes
340
    if (bHasRelXY
341
#ifdef EXPOSE_ABS_AXES_WITH_BUTTONS_AS_MOUSE
342
        || (pMouseDesc->uNumOfButtons > 0 && InputCfgDataHasBit(pAbsAxes, ABS_X) && InputCfgDataHasBit(pAbsAxes, ABS_Y))
343
#endif // EXPOSE_ABS_AXES_WITH_BUTTONS_AS_MOUSE
344
        )
345
    {
346
        for (i = 0; i < pRelAxes->size; i++)
347
        {
348
            while (DecodeNextBit(&pRelAxes->u.bitmap[i], &uValue))
349
            {
350
                ULONG uRelCode = uValue + 8 * i;
351
                ULONG uAxisCode = 0;
352
                switch (uRelCode)
353
                {
354
                case REL_X: uAxisCode = bHasRelXY ? HID_USAGE_GENERIC_X : 0; break;
355
                case REL_Y: uAxisCode = bHasRelXY ? HID_USAGE_GENERIC_Y : 0; break;
356
                case REL_Z: uAxisCode = HID_USAGE_GENERIC_Z; break;
357
                case REL_RX: uAxisCode = HID_USAGE_GENERIC_RX; break;
358
                case REL_RY: uAxisCode = HID_USAGE_GENERIC_RY; break;
359
                case REL_RZ: uAxisCode = HID_USAGE_GENERIC_RZ; break;
360
                case REL_WHEEL:
361
                {
362
                    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got axis-based vertical wheel\n");
363
                    pMouseDesc->uFlags |= CLASS_MOUSE_SUPPORTS_REL_WHEEL;
364
                    pMouseDesc->uFlags |= CLASS_MOUSE_HAS_V_WHEEL;
365
                    break;
366
                }
367
                case REL_DIAL:
368
                {
369
                    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got axis-based horizontal wheel (REL_DIAL)\n");
370
                    pMouseDesc->uFlags |= CLASS_MOUSE_SUPPORTS_REL_DIAL;
371
                    pMouseDesc->uFlags |= CLASS_MOUSE_HAS_H_WHEEL;
372
                    break;
373
                }
374
                case REL_HWHEEL:
375
                {
376
                    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got axis-based horizontal wheel (REL_HWHEEL)\n");
377
                    pMouseDesc->uFlags |= CLASS_MOUSE_SUPPORTS_REL_HWHEEL;
378
                    pMouseDesc->uFlags |= CLASS_MOUSE_HAS_H_WHEEL;
379
                    break;
380
                }
381
                default: uAxisCode = HID_USAGE_GENERIC_SLIDER; break;
382
                }
383

384
                if (uAxisCode != 0)
385
                {
386
                    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got rel axis %d\n", uAxisCode);
387
                    HIDAppend2(pHidDesc, HID_TAG_USAGE, uAxisCode);
388

389
                    // add mapping for this axis
390
                    HIDMouseAxisMapAppend(&AxisMap, (EV_REL << 16) | uRelCode, pMouseDesc->cbAxisLen);
391
                    pMouseDesc->cbAxisLen++;
392
                    uNumOfRelAxes++;
393
                }
394
            }
395
        }
396
    }
397
    if (uNumOfRelAxes > 0)
398
    {
399
        // the range is -127 to 127 (one byte) on all axes
400
        HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MINIMUM, -127);
401
        HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MAXIMUM, 127);
402

403
        HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x08);
404
        HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, uNumOfRelAxes);
405

406
        HIDAppend2(pHidDesc, HID_TAG_INPUT, HID_DATA_FLAG_VARIABLE | HID_DATA_FLAG_RELATIVE);
407
    }
408

409
#ifdef EXPOSE_ABS_AXES_WITH_BUTTONS_AS_MOUSE
410
    if (!bHasRelXY &&
411
        pMouseDesc->uNumOfButtons > 0 &&
412
        InputCfgDataHasBit(pAbsAxes, ABS_X) && InputCfgDataHasBit(pAbsAxes, ABS_Y))
413
    {
414
        for (i = 0; i < pAbsAxes->size; i++)
415
        {
416
            while (DecodeNextBit(&pAbsAxes->u.bitmap[i], &uValue))
417
            {
418
                ULONG uAbsCode = uValue + 8 * i;
419
                ULONG uAxisCode = 0;
420
                switch (uAbsCode)
421
                {
422
                case ABS_X: uAxisCode = HID_USAGE_GENERIC_X; break;
423
                case ABS_Y: uAxisCode = HID_USAGE_GENERIC_Y; break;
424
                case ABS_Z: uAxisCode = HID_USAGE_GENERIC_Z; break;
425
                case ABS_RX: uAxisCode = HID_USAGE_GENERIC_RX; break;
426
                case ABS_RY: uAxisCode = HID_USAGE_GENERIC_RY; break;
427
                case ABS_RZ: uAxisCode = HID_USAGE_GENERIC_RZ; break;
428
                case ABS_WHEEL: uAxisCode = HID_USAGE_GENERIC_WHEEL; break;
429
                }
430

431
                if (uAxisCode != 0)
432
                {
433
                    struct virtio_input_absinfo AbsInfo;
434
                    GetAbsAxisInfo(pContext, uAbsCode, &AbsInfo);
435

436
                    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Got abs axis %d, min %d, max %d\n",
437
                                uAxisCode, AbsInfo.min, AbsInfo.max);
438
                    HIDAppend2(pHidDesc, HID_TAG_USAGE, uAxisCode);
439

440
                    // we specify the minimum and maximum per-axis
441
                    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MINIMUM, AbsInfo.min);
442
                    HIDAppend2(pHidDesc, HID_TAG_LOGICAL_MAXIMUM, AbsInfo.max);
443
                    if (AbsInfo.min != 0 || AbsInfo.max != MAXSHORT)
444
                    {
445
                        HIDAppend2(pHidDesc, HID_TAG_PHYSICAL_MINIMUM, 0);
446
                        HIDAppend2(pHidDesc, HID_TAG_PHYSICAL_MAXIMUM, 0x7fff);
447
                    }
448

449
                    HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, 0x10); // 2 bytes
450
                    HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, 0x01);
451

452
                    HIDAppend2(pHidDesc, HID_TAG_INPUT, HID_DATA_FLAG_VARIABLE);
453

454
                    // add mapping for this axis
455
                    HIDMouseAxisMapAppend(&AxisMap, (EV_ABS << 16) | uAbsCode, pMouseDesc->cbAxisLen);
456
                    pMouseDesc->cbAxisLen += 2;
457
                    uNumOfAbsAxes++;
458
                }
459
            }
460
        }
461
    }
462
#endif // EXPOSE_ABS_AXES_WITH_BUTTONS_AS_MOUSE
463

464
    if (uNumOfRelAxes == 0 && uNumOfAbsAxes == 0)
465
    {
466
        // this is not a mouse
467
        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "No mouse axis found\n");
468
        VIOInputFree(&pMouseDesc);
469
        pHidDesc->Size = cbInitialHidSize;
470
        goto Exit;
471
    }
472

473
    // if we have detected axis-based wheel support, add mapping for those too
474
    if (pMouseDesc->uFlags & CLASS_MOUSE_SUPPORTS_REL_WHEEL)
475
    {
476
        HIDMouseAxisMapAppend(&AxisMap, (EV_REL << 16) | REL_WHEEL, pMouseDesc->cbAxisLen);
477
    }
478
    if ((pMouseDesc->uFlags & CLASS_MOUSE_SUPPORTS_REL_HWHEEL) ||
479
        (pMouseDesc->uFlags & CLASS_MOUSE_SUPPORTS_REL_DIAL))
480
    {
481
        SIZE_T cbOffset = pMouseDesc->cbAxisLen;
482
        if (pMouseDesc->uFlags & CLASS_MOUSE_HAS_V_WHEEL)
483
        {
484
            // horizontal wheel field follows the vertical wheel field
485
            cbOffset++;
486
        }
487
        if (pMouseDesc->uFlags & CLASS_MOUSE_SUPPORTS_REL_HWHEEL)
488
        {
489
            HIDMouseAxisMapAppend(&AxisMap, (EV_REL << 16) | REL_HWHEEL, cbOffset);
490
        }
491
        if (pMouseDesc->uFlags & CLASS_MOUSE_SUPPORTS_REL_DIAL)
492
        {
493
            HIDMouseAxisMapAppend(&AxisMap, (EV_REL << 16) | REL_DIAL, cbOffset);
494
        }
495
    }
496

497
    // finalize the axis map
498
    HIDMouseAxisMapAppend(&AxisMap, (ULONG)-1, (ULONG)-1);
499
    pMouseDesc->pAxisMap = DynamicArrayGet(&AxisMap, NULL);
500
    if (pMouseDesc->pAxisMap == NULL)
501
    {
502
        status = STATUS_INSUFFICIENT_RESOURCES;
503
        goto Exit;
504
    }
505

506
    if (pMouseDesc->uFlags & CLASS_MOUSE_HAS_V_WHEEL)
507
    {
508
        // vertical mouse wheel
509
        HIDMouseDescribeWheel(pHidDesc, 0, HID_USAGE_GENERIC_WHEEL);
510
        uFeatureBitsUsed += 2;
511
    }
512

513
    if (pMouseDesc->uFlags & CLASS_MOUSE_HAS_H_WHEEL)
514
    {
515
        // horizontal mouse wheel
516
        HIDMouseDescribeWheel(pHidDesc, HID_USAGE_PAGE_CONSUMER, HID_USAGE_CONSUMER_AC_PAN);
517
        uFeatureBitsUsed += 2;
518
    }
519

520
    // feature padding
521
    if (uFeatureBitsUsed % 8)
522
    {
523
        cbFeatureBytes = (uFeatureBitsUsed + 7) / 8;
524
        HIDAppend2(pHidDesc, HID_TAG_PHYSICAL_MINIMUM, 0x00);
525
        HIDAppend2(pHidDesc, HID_TAG_PHYSICAL_MAXIMUM, 0x00);
526
        HIDAppend2(pHidDesc, HID_TAG_REPORT_SIZE, (ULONG)(cbFeatureBytes * 8) - uFeatureBitsUsed);
527
        HIDAppend2(pHidDesc, HID_TAG_REPORT_COUNT, 0x01);
528
        HIDAppend2(pHidDesc, HID_TAG_FEATURE, HID_DATA_FLAG_VARIABLE | HID_DATA_FLAG_CONSTANT);
529
    }
530

531
    // close all collections
532
    HIDAppend1(pHidDesc, HID_TAG_END_COLLECTION);
533
    HIDAppend1(pHidDesc, HID_TAG_END_COLLECTION);
534

535
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
536
                "Created HID mouse report descriptor with %d buttons, %d rel axes, %d abs axes, vwheel %s, hwheel %s\n",
537
                pMouseDesc->uNumOfButtons,
538
                uNumOfRelAxes,
539
                uNumOfAbsAxes,
540
                (pMouseDesc->uFlags & CLASS_MOUSE_HAS_V_WHEEL) ? "YES" : "NO",
541
                (pMouseDesc->uFlags & CLASS_MOUSE_HAS_H_WHEEL) ? "YES" : "NO");
542

543
    // calculate the mouse HID report size
544
    pMouseDesc->Common.cbHidReportSize =
545
        pMouseDesc->cbAxisOffset +
546
        pMouseDesc->cbAxisLen +
547
        ((pMouseDesc->uFlags & CLASS_MOUSE_HAS_V_WHEEL) ? 1 : 0) +
548
        ((pMouseDesc->uFlags & CLASS_MOUSE_HAS_H_WHEEL) ? 1 : 0);
549

550
    // register the joystick class
551
    status = RegisterClass(pContext, &pMouseDesc->Common);
552

553
Exit:
554
    DynamicArrayDestroy(&AxisMap);
555
    if (!NT_SUCCESS(status) && pMouseDesc != NULL)
556
    {
557
        pMouseDesc->Common.CleanupFunc(&pMouseDesc->Common);
558
        VIOInputFree(&pMouseDesc);
559
    }
560

561
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s (%08x)\n", __FUNCTION__, status);
562
    return status;
563
}
564

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

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

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

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