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