1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Implementation of a USB HID mouse.
7 Two classes are provided by this module. The MouseFeature class implements
8 the core functionality of a HID mouse and can be included in any HID gadget.
9 The MouseGadget class implements an example mouse gadget.
15 import hid_descriptors
20 class MouseFeature(hid_gadget
.HidFeature
):
21 """HID feature implementation for a mouse.
23 REPORT_DESC provides an example HID report descriptor for a device including
27 REPORT_DESC
= hid_descriptors
.ReportDescriptor(
28 hid_descriptors
.UsagePage(0x01), # Generic Desktop
29 hid_descriptors
.Usage(0x02), # Mouse
30 hid_descriptors
.Collection(
31 hid_constants
.CollectionType
.APPLICATION
,
32 hid_descriptors
.Usage(0x01), # Pointer
33 hid_descriptors
.Collection(
34 hid_constants
.CollectionType
.PHYSICAL
,
35 hid_descriptors
.UsagePage(0x09), # Buttons
36 hid_descriptors
.UsageMinimum(1),
37 hid_descriptors
.UsageMaximum(3),
38 hid_descriptors
.LogicalMinimum(0, force_length
=1),
39 hid_descriptors
.LogicalMaximum(1),
40 hid_descriptors
.ReportCount(3),
41 hid_descriptors
.ReportSize(1),
42 hid_descriptors
.Input(hid_descriptors
.Data
,
43 hid_descriptors
.Variable
,
44 hid_descriptors
.Absolute
),
45 hid_descriptors
.ReportCount(1),
46 hid_descriptors
.ReportSize(5),
47 hid_descriptors
.Input(hid_descriptors
.Constant
),
48 hid_descriptors
.UsagePage(0x01), # Generic Desktop
49 hid_descriptors
.Usage(0x30), # X
50 hid_descriptors
.Usage(0x31), # Y
51 hid_descriptors
.LogicalMinimum(0x81), # -127
52 hid_descriptors
.LogicalMaximum(127),
53 hid_descriptors
.ReportSize(8),
54 hid_descriptors
.ReportCount(2),
55 hid_descriptors
.Input(hid_descriptors
.Data
,
56 hid_descriptors
.Variable
,
57 hid_descriptors
.Relative
)
63 super(MouseFeature
, self
).__init
__()
66 def ButtonDown(self
, button
):
67 self
._buttons |
= button
68 if self
.IsConnected():
69 self
.SendReport(self
.EncodeInputReport())
71 def ButtonUp(self
, button
):
72 self
._buttons
&= ~button
73 if self
.IsConnected():
74 self
.SendReport(self
.EncodeInputReport())
76 def Move(self
, x_displacement
, y_displacement
):
77 if self
.IsConnected():
78 self
.SendReport(self
.EncodeInputReport(x_displacement
, y_displacement
))
80 def EncodeInputReport(self
, x_displacement
=0, y_displacement
=0):
81 return struct
.pack('Bbb', self
._buttons
, x_displacement
, y_displacement
)
83 def GetInputReport(self
):
84 """Construct an input report.
86 See Device Class Definition for Human Interface Devices (HID) Version 1.11
90 A packed input report.
92 return self
.EncodeInputReport()
95 class MouseGadget(hid_gadget
.HidGadget
):
96 """USB gadget implementation of a HID mouse."""
99 self
._feature
= MouseFeature()
100 super(MouseGadget
, self
).__init
__(
101 report_desc
=MouseFeature
.REPORT_DESC
,
102 features
={0: self
._feature
},
106 vendor_id
=usb_constants
.VendorID
.GOOGLE
,
107 product_id
=usb_constants
.ProductID
.GOOGLE_MOUSE_GADGET
,
108 device_version
=0x0100)
109 self
.AddStringDescriptor(1, 'Google Inc.')
110 self
.AddStringDescriptor(2, 'Mouse Gadget')
112 def ButtonDown(self
, button
):
113 self
._feature
.ButtonDown(button
)
115 def ButtonUp(self
, button
):
116 self
._feature
.ButtonUp(button
)
118 def Move(self
, x_displacement
, y_displacement
):
119 self
._feature
.Move(x_displacement
, y_displacement
)
122 def RegisterHandlers():
123 """Registers web request handlers with the application server."""
125 from tornado
import web
127 class WebConfigureHandler(web
.RequestHandler
):
130 gadget
= MouseGadget()
131 server
.SwitchGadget(gadget
)
133 class WebClickHandler(web
.RequestHandler
):
137 '1': hid_constants
.Mouse
.BUTTON_1
,
138 '2': hid_constants
.Mouse
.BUTTON_2
,
139 '3': hid_constants
.Mouse
.BUTTON_3
,
142 button
= BUTTONS
[self
.get_argument('button')]
143 server
.gadget
.ButtonDown(button
)
144 server
.gadget
.ButtonUp(button
)
146 class WebMoveHandler(web
.RequestHandler
):
149 x
= int(self
.get_argument('x'))
150 y
= int(self
.get_argument('y'))
151 server
.gadget
.Move(x
, y
)
154 server
.app
.add_handlers('.*$', [
155 (r
'/mouse/configure', WebConfigureHandler
),
156 (r
'/mouse/move', WebMoveHandler
),
157 (r
'/mouse/click', WebClickHandler
),