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