| # Copyright 2014 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Implementation of a USB HID mouse. |
| |
| Two classes are provided by this module. The MouseFeature class implements |
| the core functionality of a HID mouse and can be included in any HID gadget. |
| The MouseGadget class implements an example mouse gadget. |
| """ |
| |
| import struct |
| |
| import hid_constants |
| import hid_descriptors |
| import hid_gadget |
| import usb_constants |
| |
| |
| class MouseFeature(hid_gadget.HidFeature): |
| """HID feature implementation for a mouse. |
| |
| REPORT_DESC provides an example HID report descriptor for a device including |
| this functionality. |
| """ |
| |
| REPORT_DESC = hid_descriptors.ReportDescriptor( |
| hid_descriptors.UsagePage(0x01), # Generic Desktop |
| hid_descriptors.Usage(0x02), # Mouse |
| hid_descriptors.Collection( |
| hid_constants.CollectionType.APPLICATION, |
| hid_descriptors.Usage(0x01), # Pointer |
| hid_descriptors.Collection( |
| hid_constants.CollectionType.PHYSICAL, |
| hid_descriptors.UsagePage(0x09), # Buttons |
| hid_descriptors.UsageMinimum(1), |
| hid_descriptors.UsageMaximum(3), |
| hid_descriptors.LogicalMinimum(0, force_length=1), |
| hid_descriptors.LogicalMaximum(1), |
| hid_descriptors.ReportCount(3), |
| hid_descriptors.ReportSize(1), |
| hid_descriptors.Input(hid_descriptors.Data, |
| hid_descriptors.Variable, |
| hid_descriptors.Absolute), |
| hid_descriptors.ReportCount(1), |
| hid_descriptors.ReportSize(5), |
| hid_descriptors.Input(hid_descriptors.Constant), |
| hid_descriptors.UsagePage(0x01), # Generic Desktop |
| hid_descriptors.Usage(0x30), # X |
| hid_descriptors.Usage(0x31), # Y |
| hid_descriptors.LogicalMinimum(0x81), # -127 |
| hid_descriptors.LogicalMaximum(127), |
| hid_descriptors.ReportSize(8), |
| hid_descriptors.ReportCount(2), |
| hid_descriptors.Input(hid_descriptors.Data, |
| hid_descriptors.Variable, |
| hid_descriptors.Relative) |
| ) |
| ) |
| ) |
| |
| def __init__(self): |
| super(MouseFeature, self).__init__() |
| self._buttons = 0 |
| |
| def ButtonDown(self, button): |
| self._buttons |= button |
| if self.IsConnected(): |
| self.SendReport(self.EncodeInputReport()) |
| |
| def ButtonUp(self, button): |
| self._buttons &= ~button |
| if self.IsConnected(): |
| self.SendReport(self.EncodeInputReport()) |
| |
| def Move(self, x_displacement, y_displacement): |
| if self.IsConnected(): |
| self.SendReport(self.EncodeInputReport(x_displacement, y_displacement)) |
| |
| def EncodeInputReport(self, x_displacement=0, y_displacement=0): |
| return struct.pack('Bbb', self._buttons, x_displacement, y_displacement) |
| |
| def GetInputReport(self): |
| """Construct an input report. |
| |
| See Device Class Definition for Human Interface Devices (HID) Version 1.11 |
| Appendix B.2. |
| |
| Returns: |
| A packed input report. |
| """ |
| return self.EncodeInputReport() |
| |
| |
| class MouseGadget(hid_gadget.HidGadget): |
| """USB gadget implementation of a HID mouse.""" |
| |
| def __init__(self): |
| self._feature = MouseFeature() |
| super(MouseGadget, self).__init__( |
| report_desc=MouseFeature.REPORT_DESC, |
| features={0: self._feature}, |
| packet_size=8, |
| interval_ms=1, |
| out_endpoint=False, |
| vendor_id=usb_constants.VendorID.GOOGLE, |
| product_id=usb_constants.ProductID.GOOGLE_MOUSE_GADGET, |
| device_version=0x0100) |
| self.AddStringDescriptor(1, 'Google Inc.') |
| self.AddStringDescriptor(2, 'Mouse Gadget') |
| |
| def ButtonDown(self, button): |
| self._feature.ButtonDown(button) |
| |
| def ButtonUp(self, button): |
| self._feature.ButtonUp(button) |
| |
| def Move(self, x_displacement, y_displacement): |
| self._feature.Move(x_displacement, y_displacement) |
| |
| |
| def RegisterHandlers(): |
| """Registers web request handlers with the application server.""" |
| |
| from tornado import web |
| |
| class WebConfigureHandler(web.RequestHandler): |
| |
| def post(self): |
| gadget = MouseGadget() |
| server.SwitchGadget(gadget) |
| |
| class WebClickHandler(web.RequestHandler): |
| |
| def post(self): |
| BUTTONS = { |
| '1': hid_constants.Mouse.BUTTON_1, |
| '2': hid_constants.Mouse.BUTTON_2, |
| '3': hid_constants.Mouse.BUTTON_3, |
| } |
| |
| button = BUTTONS[self.get_argument('button')] |
| server.gadget.ButtonDown(button) |
| server.gadget.ButtonUp(button) |
| |
| class WebMoveHandler(web.RequestHandler): |
| |
| def post(self): |
| x = int(self.get_argument('x')) |
| y = int(self.get_argument('y')) |
| server.gadget.Move(x, y) |
| |
| import server |
| server.app.add_handlers('.*$', [ |
| (r'/mouse/configure', WebConfigureHandler), |
| (r'/mouse/move', WebMoveHandler), |
| (r'/mouse/click', WebClickHandler), |
| ]) |