Home | History | Annotate | Download | only in usb_gadget
      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.
      4 
      5 """Implementation of a USB HID mouse.
      6 
      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.
     10 """
     11 
     12 import struct
     13 
     14 import hid_constants
     15 import hid_descriptors
     16 import hid_gadget
     17 import usb_constants
     18 
     19 
     20 class MouseFeature(hid_gadget.HidFeature):
     21   """HID feature implementation for a mouse.
     22 
     23   REPORT_DESC provides an example HID report descriptor for a device including
     24   this functionality.
     25   """
     26 
     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)
     58           )
     59       )
     60   )
     61 
     62   def __init__(self):
     63     super(MouseFeature, self).__init__()
     64     self._buttons = 0
     65 
     66   def ButtonDown(self, button):
     67     self._buttons |= button
     68     if self.IsConnected():
     69       self.SendReport(self.EncodeInputReport())
     70 
     71   def ButtonUp(self, button):
     72     self._buttons &= ~button
     73     if self.IsConnected():
     74       self.SendReport(self.EncodeInputReport())
     75 
     76   def Move(self, x_displacement, y_displacement):
     77     if self.IsConnected():
     78       self.SendReport(self.EncodeInputReport(x_displacement, y_displacement))
     79 
     80   def EncodeInputReport(self, x_displacement=0, y_displacement=0):
     81     return struct.pack('Bbb', self._buttons, x_displacement, y_displacement)
     82 
     83   def GetInputReport(self):
     84     """Construct an input report.
     85 
     86     See Device Class Definition for Human Interface Devices (HID) Version 1.11
     87     Appendix B.2.
     88 
     89     Returns:
     90       A packed input report.
     91     """
     92     return self.EncodeInputReport()
     93 
     94 
     95 class MouseGadget(hid_gadget.HidGadget):
     96   """USB gadget implementation of a HID mouse."""
     97 
     98   def __init__(self):
     99     self._feature = MouseFeature()
    100     super(MouseGadget, self).__init__(
    101         report_desc=MouseFeature.REPORT_DESC,
    102         features={0: self._feature},
    103         packet_size=8,
    104         interval_ms=1,
    105         out_endpoint=False,
    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')
    111 
    112   def ButtonDown(self, button):
    113     self._feature.ButtonDown(button)
    114 
    115   def ButtonUp(self, button):
    116     self._feature.ButtonUp(button)
    117 
    118   def Move(self, x_displacement, y_displacement):
    119     self._feature.Move(x_displacement, y_displacement)
    120 
    121 
    122 def RegisterHandlers():
    123   """Registers web request handlers with the application server."""
    124 
    125   from tornado import web
    126 
    127   class WebConfigureHandler(web.RequestHandler):
    128 
    129     def post(self):
    130       gadget = MouseGadget()
    131       server.SwitchGadget(gadget)
    132 
    133   class WebClickHandler(web.RequestHandler):
    134 
    135     def post(self):
    136       BUTTONS = {
    137           '1': hid_constants.Mouse.BUTTON_1,
    138           '2': hid_constants.Mouse.BUTTON_2,
    139           '3': hid_constants.Mouse.BUTTON_3,
    140       }
    141 
    142       button = BUTTONS[self.get_argument('button')]
    143       server.gadget.ButtonDown(button)
    144       server.gadget.ButtonUp(button)
    145 
    146   class WebMoveHandler(web.RequestHandler):
    147 
    148     def post(self):
    149       x = int(self.get_argument('x'))
    150       y = int(self.get_argument('y'))
    151       server.gadget.Move(x, y)
    152 
    153   import server
    154   server.app.add_handlers('.*$', [
    155       (r'/mouse/configure', WebConfigureHandler),
    156       (r'/mouse/move', WebMoveHandler),
    157       (r'/mouse/click', WebClickHandler),
    158   ])
    159