1 //
2 // Copyright (c) 2010-2018 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Linq;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Peripherals.Input;
12 using Antmicro.Renode.Utilities;
13 using Antmicro.Renode.Core;
14 using Antmicro.Renode.Core.USB;
15 using Antmicro.Renode.Core.USB.HID;
16 using Antmicro.Renode.Exceptions;
17 using Antmicro.Renode.Core.Structure;
18 using Antmicro.Renode.Extensions.Utilities.USBIP;
19 
20 namespace Antmicro.Renode.Peripherals.USB
21 {
22     public static class USBMouseExtensions
23     {
24         //
25         // DISCLAIMER:
26         //
27         // Those are helper methods needed because `host` object (part of which `USBIPServer` is)
28         // is not fully supported in monitor/repl.
29         //
AttachUSBMouse(this USBIPServer usbController, int? port = null)30         public static void AttachUSBMouse(this USBIPServer usbController, int? port = null)
31         {
32             if(usbController.Children.Where(m => m.Peripheral.GetType() == typeof(USBMouse)).Count() != 0)
33             {
34                 throw new RecoverableException("There is already a USB mouse connected to the USB/IP server");
35             }
36 
37             usbController.Register(new USBMouse(), port);
38         }
39 
MoveMouse(this USBIPServer usbController, int x, int y)40         public static void MoveMouse(this USBIPServer usbController, int x, int y)
41         {
42             var mouse = usbController.Children.Where(m => m.Peripheral.GetType() == typeof(USBMouse)).Select(m => m.Peripheral).Cast<USBMouse>().FirstOrDefault();
43             if(mouse == null)
44             {
45                 throw new RecoverableException("No USB mouse attached to the host. Did you forget to call 'host AttachUSBMouse'?");
46             }
47 
48             mouse.MoveBy(x, y);
49         }
50     }
51 
52     public class USBMouse : IUSBDevice, IRelativePositionPointerInput
53     {
USBMouse()54         public USBMouse()
55         {
56             USBCore = new USBDeviceCore(this)
57                 .WithConfiguration(configure: c =>
58                     c.WithInterface(new Core.USB.HID.Interface(this, 0,
59                         subClassCode: (byte)Core.USB.HID.SubclassCode.BootInterfaceSubclass,
60                         protocol: (byte)Core.USB.HID.Protocol.Mouse,
61                         reportDescriptor: new Core.USB.HID.ReportDescriptor(ReportHidDescriptor)),
62                         configure: i =>
63                             i.WithEndpoint(
64                                 Direction.DeviceToHost,
65                                 EndpointTransferType.Interrupt,
66                                 maximumPacketSize: 0x4,
67                                 interval: 0xa,
68                                 createdEndpoint: out endpoint)));
69         }
70 
Reset()71         public void Reset()
72         {
73             buttonState = 0;
74             USBCore.Reset();
75         }
76 
MoveBy(int x, int y)77         public void MoveBy(int x, int y)
78         {
79             using(var p = endpoint.PreparePacket())
80             {
81                 p.Add((byte)buttonState);
82                 p.Add((byte)x.Clamp(-127, 127));
83                 p.Add((byte)y.Clamp(-127, 127));
84                 p.Add(0);
85             }
86         }
87 
Press(MouseButton button = MouseButton.Left)88         public void Press(MouseButton button = MouseButton.Left)
89         {
90             buttonState = button;
91             SendButtonState();
92         }
93 
Release(MouseButton button = MouseButton.Left)94         public void Release(MouseButton button = MouseButton.Left)
95         {
96             buttonState = 0;
97             SendButtonState();
98         }
99 
SendButtonState()100         private void SendButtonState()
101         {
102             using(var p = endpoint.PreparePacket())
103             {
104                 p.Add((byte)buttonState);
105                 p.Add(0);
106                 p.Add(0);
107                 p.Add(0);
108             }
109         }
110 
111         public USBDeviceCore USBCore { get; }
112 
113         private MouseButton buttonState;
114 
115         private USBEndpoint endpoint;
116 
117         private readonly byte[] ReportHidDescriptor = new byte[]
118         {
119             0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01,
120             0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
121             0x15, 0x00, 0x25, 0x01, 0x95, 0x08, 0x75, 0x01,
122             0x81, 0x02, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31,
123             0x09, 0x38, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08,
124             0x95, 0x03, 0x81, 0x06, 0xC0, 0xC0
125         };
126     }
127 }
128 
129