1 //Simplified BSD License (BSD-2-Clause) 2 // 3 //Copyright (c) 2020-2021, Marc Riera, The OpenBVE Project 4 // 5 //Redistribution and use in source and binary forms, with or without 6 //modification, are permitted provided that the following conditions are met: 7 // 8 //1. Redistributions of source code must retain the above copyright notice, this 9 // list of conditions and the following disclaimer. 10 //2. Redistributions in binary form must reproduce the above copyright notice, 11 // this list of conditions and the following disclaimer in the documentation 12 // and/or other materials provided with the distribution. 13 // 14 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 //DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 //ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 //(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 //ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 25 using System; 26 using System.Collections.Generic; 27 using OpenTK.Input; 28 29 namespace DenshaDeGoInput 30 { 31 /// <summary> 32 /// Class representing a Zuiki controller 33 /// </summary> 34 internal class ZuikiController : Controller 35 { 36 /// <summary>A cached list of supported connected controllers.</summary> 37 private static Dictionary<Guid, Controller> cachedControllers = new Dictionary<Guid, Controller>(); 38 39 /// <summary>The OpenTK joystick index for this controller.</summary> 40 private int joystickIndex; 41 42 /// <summary>The min/max byte for each brake notch, from Released to Emergency. Each notch consists of two bytes.</summary> 43 private readonly byte[] brakeBytes; 44 45 /// <summary>The min/max byte for each power notch, from Released to maximum. Each notch consists of two bytes.</summary> 46 private readonly byte[] powerBytes; 47 48 /// <summary>The index for each button. Follows order in InputTranslator.</summary> 49 private readonly int[] buttonIndex; 50 51 /// <summary> 52 /// Initializes a Zuiki controller. 53 /// </summary> ZuikiController(ControllerButtons buttons, int[] buttonIndices, byte[] brake, byte[] power)54 internal ZuikiController(ControllerButtons buttons, int[] buttonIndices, byte[] brake, byte[] power) 55 { 56 ControllerName = string.Empty; 57 IsConnected = false; 58 RequiresCalibration = false; 59 BrakeNotches = brake.Length / 2 - 2; 60 PowerNotches = power.Length / 2 - 1; 61 brakeBytes = brake; 62 powerBytes = power; 63 Buttons = buttons; 64 buttonIndex = buttonIndices; 65 } 66 67 /// <summary> 68 /// Reads the input from the controller. 69 /// </summary> ReadInput()70 internal override void ReadInput() 71 { 72 JoystickState joystick = Joystick.GetState(joystickIndex); 73 double handleAxis = Math.Round(joystick.GetAxis(1),4); 74 for (int i = 0; i < brakeBytes.Length; i+=2) 75 { 76 // Each notch uses two bytes, minimum value and maximum value 77 if (handleAxis >= GetAxisValue(brakeBytes[i]) && handleAxis <= GetAxisValue(brakeBytes[i + 1])) 78 { 79 if (brakeBytes.Length == i + 2) 80 { 81 // Last notch should be Emergency 82 InputTranslator.BrakeNotch = InputTranslator.BrakeNotches.Emergency; 83 } 84 else 85 { 86 // Regular brake notch 87 InputTranslator.BrakeNotch = (InputTranslator.BrakeNotches)(i / 2); 88 } 89 break; 90 } 91 InputTranslator.BrakeNotch = InputTranslator.BrakeNotches.Released; 92 } 93 for (int i = 0; i < powerBytes.Length; i+=2) 94 { 95 // Each notch uses two bytes, minimum value and maximum value 96 if (handleAxis >= GetAxisValue(powerBytes[i]) && handleAxis <= GetAxisValue(powerBytes[i + 1])) 97 { 98 InputTranslator.PowerNotch = (InputTranslator.PowerNotches)(i / 2); 99 break; 100 } 101 InputTranslator.PowerNotch = InputTranslator.PowerNotches.N; 102 } 103 104 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Select] = joystick.GetButton(buttonIndex[(int)InputTranslator.ControllerButton.Select]); 105 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Start] = joystick.GetButton(buttonIndex[(int)InputTranslator.ControllerButton.Start]); 106 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.A] = joystick.GetButton(buttonIndex[(int)InputTranslator.ControllerButton.A]); 107 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.B] = joystick.GetButton(buttonIndex[(int)InputTranslator.ControllerButton.B]); 108 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.C] = joystick.GetButton(buttonIndex[(int)InputTranslator.ControllerButton.C]); 109 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.D] = joystick.GetButton(buttonIndex[(int)InputTranslator.ControllerButton.D]); 110 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.LDoor] = joystick.GetButton(buttonIndex[(int)InputTranslator.ControllerButton.LDoor]); 111 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.RDoor] = joystick.GetButton(buttonIndex[(int)InputTranslator.ControllerButton.RDoor]); 112 113 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Up] = (ButtonState)(joystick.GetHat(JoystickHat.Hat0).IsUp ? 1 : 0); 114 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Down] = (ButtonState)(joystick.GetHat(JoystickHat.Hat0).IsDown ? 1 : 0); 115 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Left] = (ButtonState)(joystick.GetHat(JoystickHat.Hat0).IsLeft ? 1 : 0); 116 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Right] = (ButtonState)(joystick.GetHat(JoystickHat.Hat0).IsRight ? 1 : 0); 117 } 118 119 /// <summary> 120 /// Gets the list of connected controllers 121 /// </summary> 122 /// <returns>The list of controllers handled by this class.</returns> GetControllers()123 internal static Dictionary<Guid, Controller> GetControllers() 124 { 125 for (int i = 0; i < 10; i++) 126 { 127 Guid guid = Joystick.GetGuid(i); 128 string id = GetControllerID(guid); 129 string name = Joystick.GetName(i); 130 131 if (!cachedControllers.ContainsKey(guid)) 132 { 133 // ZKNS-001 134 if (id == "0f0d:00c1") 135 { 136 ControllerButtons buttons = ControllerButtons.Select | ControllerButtons.Start | ControllerButtons.A | ControllerButtons.B | ControllerButtons.C | ControllerButtons.D | ControllerButtons.LDoor | ControllerButtons.RDoor | ControllerButtons.DPad; 137 int[] buttonIndices = { 8, 9, 0, 1, 2, 3, 4, 5 }; 138 byte[] brakeBytes = { 0x7F, 0x81, 0x64, 0x66, 0x56, 0x58, 0x48, 0x4A, 0x3B, 0x3D, 0x2D, 0x2F, 0x1F, 0x21, 0x12, 0x14, 0x04, 0x06, 0x0, 0x1 }; 139 byte[] powerBytes = { 0x7F, 0x81, 0x9E, 0xA0, 0xB6, 0xB8, 0xCD, 0xCF, 0xE5, 0xE7, 0xFE, 0xFF }; 140 ZuikiController newcontroller = new ZuikiController(buttons, buttonIndices, brakeBytes, powerBytes) 141 { 142 Guid = guid, 143 Id = id, 144 joystickIndex = i, 145 ControllerName = name, 146 IsConnected = true 147 }; 148 cachedControllers.Add(guid, newcontroller); 149 } 150 } 151 else 152 { 153 // Cached controller, update it 154 ((ZuikiController)cachedControllers[guid]).joystickIndex = i; 155 // HACK: IsConnected is broken, we check the capabilities instead to know if the controller is connected or not 156 cachedControllers[guid].IsConnected = Joystick.GetCapabilities(i).ButtonCount > 0; 157 } 158 } 159 160 return cachedControllers; 161 } 162 163 /// <summary>Gets the equivalent axis value for a notch byte.</summary> 164 /// <param name="notch">A notch byte.</param> 165 /// <returns>The axis value for a notch byte.</returns> GetAxisValue(byte notch)166 private static double GetAxisValue(byte notch) 167 { 168 double value = Math.Round(notch * (2.0 / 255) - 1, 4); 169 return value; 170 } 171 } 172 } 173