Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / tools / usb_gadget / keyboard_gadget.py
blob8f1e3b023f69fa01c552d0528fb0bfc7f6db2087
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 keyboard.
7 Two classes are provided by this module. The KeyboardFeature class implements
8 the core functionality of a HID keyboard and can be included in any HID gadget.
9 The KeyboardGadget class implements an example keyboard gadget.
10 """
12 import struct
14 import hid_constants
15 import hid_descriptors
16 import hid_gadget
17 import usb_constants
20 class KeyboardFeature(hid_gadget.HidFeature):
21 """HID feature implementation for a keyboard.
23 REPORT_DESC provides an example HID report descriptor for a device including
24 this functionality.
25 """
27 REPORT_DESC = hid_descriptors.ReportDescriptor(
28 hid_descriptors.UsagePage(0x01), # Generic Desktop
29 hid_descriptors.Usage(0x06), # Keyboard
30 hid_descriptors.Collection(
31 hid_constants.CollectionType.APPLICATION,
32 hid_descriptors.UsagePage(0x07), # Key Codes
33 hid_descriptors.UsageMinimum(224),
34 hid_descriptors.UsageMaximum(231),
35 hid_descriptors.LogicalMinimum(0, force_length=1),
36 hid_descriptors.LogicalMaximum(1),
37 hid_descriptors.ReportSize(1),
38 hid_descriptors.ReportCount(8),
39 hid_descriptors.Input(hid_descriptors.Data,
40 hid_descriptors.Variable,
41 hid_descriptors.Absolute),
42 hid_descriptors.ReportCount(1),
43 hid_descriptors.ReportSize(8),
44 hid_descriptors.Input(hid_descriptors.Constant),
45 hid_descriptors.ReportCount(5),
46 hid_descriptors.ReportSize(1),
47 hid_descriptors.UsagePage(0x08), # LEDs
48 hid_descriptors.UsageMinimum(1),
49 hid_descriptors.UsageMaximum(5),
50 hid_descriptors.Output(hid_descriptors.Data,
51 hid_descriptors.Variable,
52 hid_descriptors.Absolute),
53 hid_descriptors.ReportCount(1),
54 hid_descriptors.ReportSize(3),
55 hid_descriptors.Output(hid_descriptors.Constant),
56 hid_descriptors.ReportCount(6),
57 hid_descriptors.ReportSize(8),
58 hid_descriptors.LogicalMinimum(0, force_length=1),
59 hid_descriptors.LogicalMaximum(101),
60 hid_descriptors.UsagePage(0x07), # Key Codes
61 hid_descriptors.UsageMinimum(0, force_length=1),
62 hid_descriptors.UsageMaximum(101),
63 hid_descriptors.Input(hid_descriptors.Data, hid_descriptors.Array)
67 def __init__(self):
68 super(KeyboardFeature, self).__init__()
69 self._modifiers = 0
70 self._keys = [0, 0, 0, 0, 0, 0]
71 self._leds = 0
73 def ModifierDown(self, modifier):
74 self._modifiers |= modifier
75 if self.IsConnected():
76 self.SendReport(self.GetInputReport())
78 def ModifierUp(self, modifier):
79 self._modifiers &= ~modifier
80 if self.IsConnected():
81 self.SendReport(self.GetInputReport())
83 def KeyDown(self, keycode):
84 free = self._keys.index(0)
85 self._keys[free] = keycode
86 if self.IsConnected():
87 self.SendReport(self.GetInputReport())
89 def KeyUp(self, keycode):
90 free = self._keys.index(keycode)
91 self._keys[free] = 0
92 if self.IsConnected():
93 self.SendReport(self.GetInputReport())
95 def GetInputReport(self):
96 """Construct an input report.
98 See Device Class Definition for Human Interface Devices (HID) Version 1.11
99 Appendix B.1.
101 Returns:
102 A packed input report.
104 return struct.pack('BBBBBBBB', self._modifiers, 0, *self._keys)
106 def GetOutputReport(self):
107 """Construct an output report.
109 See Device Class Definition for Human Interface Devices (HID) Version 1.11
110 Appendix B.1.
112 Returns:
113 A packed input report.
115 return struct.pack('B', self._leds)
117 def SetOutputReport(self, data):
118 """Handle an output report.
120 See Device Class Definition for Human Interface Devices (HID) Version 1.11
121 Appendix B.1.
123 Args:
124 data: Report data.
126 Returns:
127 True on success, None to stall the pipe.
129 if len(data) >= 1:
130 self._leds, = struct.unpack('B', data)
131 return True
134 class KeyboardGadget(hid_gadget.HidGadget):
135 """USB gadget implementation of a HID keyboard."""
137 def __init__(self, vendor_id=0x18D1, product_id=0xFF02):
138 self._feature = KeyboardFeature()
139 super(KeyboardGadget, self).__init__(
140 report_desc=KeyboardFeature.REPORT_DESC,
141 features={0: self._feature},
142 packet_size=8,
143 interval_ms=1,
144 out_endpoint=True,
145 vendor_id=usb_constants.VendorID.GOOGLE,
146 product_id=usb_constants.ProductID.GOOGLE_KEYBOARD_GADGET,
147 device_version=0x0100)
148 self.AddStringDescriptor(1, 'Google Inc.')
149 self.AddStringDescriptor(2, 'Keyboard Gadget')
151 def ModifierDown(self, modifier):
152 self._feature.ModifierDown(modifier)
154 def ModifierUp(self, modifier):
155 self._feature.ModifierUp(modifier)
157 def KeyDown(self, keycode):
158 self._feature.KeyDown(keycode)
160 def KeyUp(self, keycode):
161 self._feature.KeyUp(keycode)
164 def RegisterHandlers():
165 """Registers web request handlers with the application server."""
167 from tornado import web
169 class WebConfigureHandler(web.RequestHandler):
171 def post(self):
172 server.SwitchGadget(KeyboardGadget())
174 class WebTypeHandler(web.RequestHandler):
176 def post(self):
177 string = self.get_argument('string')
178 for char in string:
179 if char in hid_constants.KEY_CODES:
180 code = hid_constants.KEY_CODES[char]
181 server.gadget.KeyDown(code)
182 server.gadget.KeyUp(code)
183 elif char in hid_constants.SHIFT_KEY_CODES:
184 code = hid_constants.SHIFT_KEY_CODES[char]
185 server.gadget.ModifierDown(hid_constants.ModifierKey.L_SHIFT)
186 server.gadget.KeyDown(code)
187 server.gadget.KeyUp(code)
188 server.gadget.ModifierUp(hid_constants.ModifierKey.L_SHIFT)
190 class WebPressHandler(web.RequestHandler):
192 def post(self):
193 code = hid_constants.KEY_CODES[self.get_argument('key')]
194 server.gadget.KeyDown(code)
195 server.gadget.KeyUp(code)
197 import server
198 server.app.add_handlers('.*$', [
199 (r'/keyboard/configure', WebConfigureHandler),
200 (r'/keyboard/type', WebTypeHandler),
201 (r'/keyboard/press', WebPressHandler),