# 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), ])