Init
20
RailWorks_Joystick_API.sln
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 2012
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RailWorks_Joystick_API", "RailWorks_Joystick_API\RailWorks_Joystick_API.csproj", "{5420C2F8-42A0-4A9C-9DFF-5AC66FF19B49}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{5420C2F8-42A0-4A9C-9DFF-5AC66FF19B49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5420C2F8-42A0-4A9C-9DFF-5AC66FF19B49}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5420C2F8-42A0-4A9C-9DFF-5AC66FF19B49}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5420C2F8-42A0-4A9C-9DFF-5AC66FF19B49}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
61
RailWorks_Joystick_API/Globals.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace RailWorks_Joystick_API {
|
||||||
|
class Globals {
|
||||||
|
|
||||||
|
public static Joystick JoyDevices;
|
||||||
|
|
||||||
|
public static List<String> DeviceNames;
|
||||||
|
|
||||||
|
public static InputHandler IHandler;
|
||||||
|
|
||||||
|
public static TextBox DevStatus;
|
||||||
|
|
||||||
|
public static int DevStatusID = -1;
|
||||||
|
|
||||||
|
public static frmManageControls ControlManager = new frmManageControls();
|
||||||
|
|
||||||
|
public static frmControls ControlsWindow = new frmControls();
|
||||||
|
|
||||||
|
public static frmSpeedo SpeedoWindow = new frmSpeedo();
|
||||||
|
|
||||||
|
public delegate void UpdateDeviceDebugDelegate(int DeviceID);
|
||||||
|
|
||||||
|
public static float Clamp(float Value, float MinValue, float MaxValue) {
|
||||||
|
return Math.Max(MinValue, Math.Min(MaxValue, Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Clamp(int Value, int MinValue, int MaxValue) {
|
||||||
|
return Math.Max(MinValue, Math.Min(MaxValue, Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AxisChanged(string DeviceName, int DeviceID, string AxisName, int NewValue, int Delta) {
|
||||||
|
IHandler.UpdateAxis(DeviceID, AxisName, NewValue, Delta);
|
||||||
|
UpdateDeviceDebugDelegate Del = (zahl) => UpdateDeviceDebug(DeviceID);
|
||||||
|
DevStatus.Invoke(Del, DeviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ButtonChanged(string DeviceName, int DeviceID, string ButtonName, int NewValue, int Delta) {
|
||||||
|
IHandler.UpdateButton(DeviceID, ButtonName, NewValue, Delta);
|
||||||
|
UpdateDeviceDebugDelegate Del = (zahl) => UpdateDeviceDebug(DeviceID);
|
||||||
|
DevStatus.Invoke(Del, DeviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateDeviceDebug(int DeviceID) {
|
||||||
|
if((DevStatusID == -1)) {
|
||||||
|
DevStatus.Text = IHandler.Devices[DeviceID].ToString();
|
||||||
|
} else if((DevStatusID == DeviceID)) {
|
||||||
|
DevStatus.Text = IHandler.Devices[DeviceID].ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string IntToStr(int Int) {
|
||||||
|
return Int.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
RailWorks_Joystick_API/Images/Background.png
Normal file
After Width: | Height: | Size: 154 KiB |
BIN
RailWorks_Joystick_API/Images/BrakeKnob.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
RailWorks_Joystick_API/Images/BtnAWSActive1.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
RailWorks_Joystick_API/Images/BtnAWSActive2.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
RailWorks_Joystick_API/Images/BtnAWSInactive.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
RailWorks_Joystick_API/Images/BtnAlternateActive.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
RailWorks_Joystick_API/Images/BtnBellActive.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
RailWorks_Joystick_API/Images/BtnBlank.png
Normal file
After Width: | Height: | Size: 149 B |
BIN
RailWorks_Joystick_API/Images/BtnCabActive.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
RailWorks_Joystick_API/Images/BtnCouplingActive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnCylinderCocksActive.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
RailWorks_Joystick_API/Images/BtnDriverGuideActive.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
RailWorks_Joystick_API/Images/BtnDriverGuideInactive.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
RailWorks_Joystick_API/Images/BtnEBrakeActive.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
RailWorks_Joystick_API/Images/BtnEBrakeInactive.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
RailWorks_Joystick_API/Images/BtnExternalFrontActive.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
RailWorks_Joystick_API/Images/BtnExternalRearActive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnFreeRoamActive.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
RailWorks_Joystick_API/Images/BtnHeadOutLeftActive.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
RailWorks_Joystick_API/Images/BtnHeadOutRightActive.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
RailWorks_Joystick_API/Images/BtnHornActive.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
RailWorks_Joystick_API/Images/BtnJunctionAheadActive.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
RailWorks_Joystick_API/Images/BtnJunctionAheadInactive.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
RailWorks_Joystick_API/Images/BtnJunctionBehindActive.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
RailWorks_Joystick_API/Images/BtnJunctionBehindInactive.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
RailWorks_Joystick_API/Images/BtnLightsActive1.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
RailWorks_Joystick_API/Images/BtnLightsActive2.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
RailWorks_Joystick_API/Images/BtnLoadUnloadActive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnManualCouplingActive.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
RailWorks_Joystick_API/Images/BtnManualCouplingInactive.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
RailWorks_Joystick_API/Images/BtnMapActive.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
RailWorks_Joystick_API/Images/BtnMapInactive.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
RailWorks_Joystick_API/Images/BtnNextCabActive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnPADAheadActive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnPADAheadInactive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnPADBehindActive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnPADBehindInactive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnPantographActive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnPassengerActive.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
RailWorks_Joystick_API/Images/BtnPreviousCabActive.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
RailWorks_Joystick_API/Images/BtnSanderActive.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
RailWorks_Joystick_API/Images/BtnSmallEjectorActive.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
RailWorks_Joystick_API/Images/BtnStarterActive.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
RailWorks_Joystick_API/Images/BtnStarterInactive.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
RailWorks_Joystick_API/Images/BtnTracksideActive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnVigilanceActive.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
RailWorks_Joystick_API/Images/BtnVigilanceInactive.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
RailWorks_Joystick_API/Images/BtnWipersActive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/BtnYardActive.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
RailWorks_Joystick_API/Images/BtnZoomInActive.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
RailWorks_Joystick_API/Images/BtnZoomOutActive.png
Normal file
After Width: | Height: | Size: 815 B |
BIN
RailWorks_Joystick_API/Images/ButtonControls1bg.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
RailWorks_Joystick_API/Images/ButtonControls2bg.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
RailWorks_Joystick_API/Images/ControlSlot.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
RailWorks_Joystick_API/Images/ControlSlotGear.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
RailWorks_Joystick_API/Images/Digi0.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
RailWorks_Joystick_API/Images/Digi1.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
RailWorks_Joystick_API/Images/Digi2.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
RailWorks_Joystick_API/Images/Digi3.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
RailWorks_Joystick_API/Images/Digi4.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
RailWorks_Joystick_API/Images/Digi5.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
RailWorks_Joystick_API/Images/Digi6.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
RailWorks_Joystick_API/Images/Digi7.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
RailWorks_Joystick_API/Images/Digi8.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
RailWorks_Joystick_API/Images/Digi9.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
RailWorks_Joystick_API/Images/DigiBlank.png
Normal file
After Width: | Height: | Size: 211 B |
BIN
RailWorks_Joystick_API/Images/DigiDot.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
RailWorks_Joystick_API/Images/DigiMinus.png
Normal file
After Width: | Height: | Size: 634 B |
BIN
RailWorks_Joystick_API/Images/GearKnob.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
RailWorks_Joystick_API/Images/LabelPanel.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
RailWorks_Joystick_API/Images/ReverserKnob.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBg200Day.png
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBg200KPHDay.png
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBg300KPHDay.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBg360KPHDay.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBgBlue.png
Normal file
After Width: | Height: | Size: 95 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBgDay.png
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBgLarge200Day.png
Normal file
After Width: | Height: | Size: 205 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBgLarge200KPHDay.png
Normal file
After Width: | Height: | Size: 205 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBgLarge300KPHDay.png
Normal file
After Width: | Height: | Size: 222 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBgLarge360KPHDay.png
Normal file
After Width: | Height: | Size: 217 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBgLargeBlue.png
Normal file
After Width: | Height: | Size: 280 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBgLargeDay.png
Normal file
After Width: | Height: | Size: 200 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBgLargeOrange.png
Normal file
After Width: | Height: | Size: 287 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoBgOrange.png
Normal file
After Width: | Height: | Size: 97 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoGlass120.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoGlass200.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoGlassLarge120.png
Normal file
After Width: | Height: | Size: 183 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoGlassLarge200.png
Normal file
After Width: | Height: | Size: 183 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoIndicator.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoIndicatorBlue.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoIndicatorLarge.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
RailWorks_Joystick_API/Images/SpeedoIndicatorLargeBlue.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
RailWorks_Joystick_API/Images/ThrottleBrakeHandle.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
RailWorks_Joystick_API/Images/ThrottleHandle.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
RailWorks_Joystick_API/Images/btnPBrakeActive.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
RailWorks_Joystick_API/Images/btnPBrakeInactive.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
903
RailWorks_Joystick_API/InputHandler.cs
Normal file
@ -0,0 +1,903 @@
|
|||||||
|
using Microsoft.VisualBasic;
|
||||||
|
using RailWorks_Joystick_API.Properties;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace RailWorks_Joystick_API {
|
||||||
|
public class InputHandler {
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern IntPtr GetForegroundWindow();
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpWindowText, int nMaxCount);
|
||||||
|
|
||||||
|
[DllImport("RailDriver.dll", CharSet = CharSet.Auto)]
|
||||||
|
public static extern void SetRailSimValue(ActionList Action, float Value);
|
||||||
|
|
||||||
|
[DllImport("RailDriver.dll", CharSet = CharSet.Auto)]
|
||||||
|
public static extern float GetRailSimValue(ActionList Action, GetValueModifier Value);
|
||||||
|
|
||||||
|
[DllImport("RailDriver.dll", CharSet = CharSet.Auto)]
|
||||||
|
public static extern bool GetRailSimConnected();
|
||||||
|
|
||||||
|
[DllImport("RailDriver.dll", CharSet = CharSet.Auto)]
|
||||||
|
public static extern void SetRailSimConnected(bool Value);
|
||||||
|
|
||||||
|
[DllImport("RailDriver.dll", CharSet = CharSet.Auto)]
|
||||||
|
public static extern void SetRailDriverConnected(bool Value);
|
||||||
|
|
||||||
|
[DllImport("RailDriver.dll", CharSet = CharSet.Auto)]
|
||||||
|
public static extern bool GetRailSimCombinedThrottleBrake();
|
||||||
|
|
||||||
|
[DllImport("RailDriver.dll", CharSet = CharSet.Auto)]
|
||||||
|
public static extern bool GetRailSimLocoChanged();
|
||||||
|
|
||||||
|
public struct InputAxisStruct {
|
||||||
|
public int Value;
|
||||||
|
public int Delta;
|
||||||
|
|
||||||
|
public string Name;
|
||||||
|
public InputAxisStruct(string AxisName, int AxisValue, int AxisDelta) {
|
||||||
|
Name = AxisName;
|
||||||
|
Value = AxisValue;
|
||||||
|
Delta = AxisDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return string.Format("{0}: {1,-20}Delta: {2}", Name, Value, Delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct InputButtonStruct {
|
||||||
|
public bool Pressed;
|
||||||
|
|
||||||
|
public string Name;
|
||||||
|
public InputButtonStruct(string ButtonName, bool ButtonPressed) {
|
||||||
|
Name = ButtonName;
|
||||||
|
Pressed = ButtonPressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return (Pressed ? string.Format("{0,-10}", Name) : "").ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct DeviceStruct {
|
||||||
|
public string Name;
|
||||||
|
public int ID;
|
||||||
|
public List<InputAxisStruct> Axis;
|
||||||
|
|
||||||
|
public List<InputButtonStruct> Buttons;
|
||||||
|
public DeviceStruct(string DeviceName, int DeviceID) {
|
||||||
|
Name = DeviceName;
|
||||||
|
ID = DeviceID;
|
||||||
|
Axis = new List<InputAxisStruct>();
|
||||||
|
Buttons = new List<InputButtonStruct>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int FindAxis(string FindName) {
|
||||||
|
for(int I = 0; I <= Axis.Count - 1; I++) {
|
||||||
|
if(Axis[I].Name == FindName)
|
||||||
|
return I;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int FindButton(string FindName) {
|
||||||
|
for(int I = 0; I <= Buttons.Count - 1; I++) {
|
||||||
|
if(Buttons[I].Name == FindName)
|
||||||
|
return I;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
System.Text.StringBuilder Txt = new System.Text.StringBuilder();
|
||||||
|
Txt.AppendLine("Device: " + Name + " (" + ID + ")");
|
||||||
|
Txt.AppendLine("Axis:");
|
||||||
|
foreach(InputAxisStruct Axle in Axis) {
|
||||||
|
Txt.AppendLine(" " + Axle.ToString());
|
||||||
|
}
|
||||||
|
Txt.AppendLine("Buttons:");
|
||||||
|
int I = 0;
|
||||||
|
foreach(InputButtonStruct Button in Buttons) {
|
||||||
|
Txt.Append(Button.ToString());
|
||||||
|
if(!(string.IsNullOrEmpty(Button.ToString())))
|
||||||
|
I += 1;
|
||||||
|
if(I >= 8) {
|
||||||
|
Txt.AppendLine();
|
||||||
|
I = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Txt.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ActionList : int {
|
||||||
|
Invalid = -1,
|
||||||
|
Reverser,
|
||||||
|
Throttle,
|
||||||
|
CombinedThrottle,
|
||||||
|
GearLever,
|
||||||
|
TrainBrake,
|
||||||
|
LocomotiveBrake,
|
||||||
|
DynamicBrake,
|
||||||
|
EmergencyBrake,
|
||||||
|
HandBrake,
|
||||||
|
WarningSystemReset,
|
||||||
|
StartStopEngine,
|
||||||
|
Horn,
|
||||||
|
Wipers,
|
||||||
|
Sander,
|
||||||
|
Headlights,
|
||||||
|
Pantograph,
|
||||||
|
FireboxDoor,
|
||||||
|
ExhaustInjectorSteam,
|
||||||
|
ExhaustInjectorWater,
|
||||||
|
LiveInjectorSteam,
|
||||||
|
LiveInjectorWater,
|
||||||
|
Damper,
|
||||||
|
Blower,
|
||||||
|
Stoking,
|
||||||
|
CylinderCock,
|
||||||
|
Waterscoop,
|
||||||
|
SmallCompressor,
|
||||||
|
AWS,
|
||||||
|
AWSReset,
|
||||||
|
Startup,
|
||||||
|
Speedometer,
|
||||||
|
// Events
|
||||||
|
PromptSave,
|
||||||
|
ToggleLabels,
|
||||||
|
Toggle2DMap,
|
||||||
|
ToggleHud,
|
||||||
|
ToggleQut,
|
||||||
|
Pause,
|
||||||
|
DriverGuide,
|
||||||
|
ToggleRvNumber,
|
||||||
|
DialogAssignment,
|
||||||
|
SwitchJunktionAhead,
|
||||||
|
SwitchJunktionBehind,
|
||||||
|
LoadCargo,
|
||||||
|
UnloadCargo,
|
||||||
|
PassAtDangerAhead,
|
||||||
|
PassAtDangerBehind,
|
||||||
|
ManualCouple,
|
||||||
|
// Camera
|
||||||
|
CabCamera,
|
||||||
|
FollowCamera,
|
||||||
|
HeadOutCamera,
|
||||||
|
RearCamera,
|
||||||
|
TrackSideCamera,
|
||||||
|
CarriageCamera,
|
||||||
|
CouplingCamera,
|
||||||
|
YardCamera,
|
||||||
|
SwitchToNextFrontCab,
|
||||||
|
SwitchToNextRearCab,
|
||||||
|
FreeCamera,
|
||||||
|
Vigilance
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum GetValueModifier : int {
|
||||||
|
Current,
|
||||||
|
Min,
|
||||||
|
Max
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DeviceStruct> Devices = new List<DeviceStruct>();
|
||||||
|
public int APIInterval = 33;
|
||||||
|
private Thread RailWorksThread;
|
||||||
|
private bool _Running;
|
||||||
|
private bool _IsStopped = true;
|
||||||
|
public int AssignFilter = 1500;
|
||||||
|
public float AxisNotchOffset = 0.002f;
|
||||||
|
|
||||||
|
public InputHandler(List<string> DeviceNames) {
|
||||||
|
for(int I = 0; I <= DeviceNames.Count - 1; I++) {
|
||||||
|
DeviceStruct Dev = new DeviceStruct(DeviceNames[I], I);
|
||||||
|
Dev.Axis = new List<InputAxisStruct>();
|
||||||
|
Dev.Buttons = new List<InputButtonStruct>();
|
||||||
|
Devices.Add(Dev);
|
||||||
|
}
|
||||||
|
LoadBlank();
|
||||||
|
Settings s = new Settings();
|
||||||
|
Vigilance.MinDelay = s.MinDelay;
|
||||||
|
Vigilance.MaxDelay = s.MaxDelay;
|
||||||
|
Vigilance.EarlyTriggerChance = s.EarlyTriggerChance;
|
||||||
|
Vigilance.TrainSpeedOffsetFactor = s.TrainSpeedOffset;
|
||||||
|
Vigilance.MinimumTrainSpeed = s.MinimumTrainSpeed;
|
||||||
|
Vigilance.TriggerTimeout = s.TriggerTimeout;
|
||||||
|
Vigilance.UseVigilanceSystem = s.UseVigilance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateAxis(int DeviceID, string AxisName, int AxisValue, int AxisDelta) {
|
||||||
|
DeviceStruct Dev = Devices[DeviceID];
|
||||||
|
int Result = Dev.FindAxis(AxisName);
|
||||||
|
if(Result == -1) {
|
||||||
|
Dev.Axis.Add(new InputAxisStruct(AxisName, AxisValue, AxisDelta));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Dev.Axis[Result] = new InputAxisStruct(AxisName, AxisValue, AxisDelta);
|
||||||
|
Devices[DeviceID] = Dev;
|
||||||
|
CheckMappings(DeviceID, AxisName, AxisValue, AxisDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateButton(int DeviceID, string ButtonName, int ButtonValue, int ButtonDelta) {
|
||||||
|
DeviceStruct Dev = Devices[DeviceID];
|
||||||
|
int Result = Dev.FindButton(ButtonName);
|
||||||
|
bool ButtonPressed = Convert.ToBoolean(ButtonValue);
|
||||||
|
if(Result == -1) {
|
||||||
|
Dev.Buttons.Add(new InputButtonStruct(ButtonName, ButtonPressed));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Dev.Buttons[Result] = new InputButtonStruct(ButtonName, ButtonPressed);
|
||||||
|
Devices[DeviceID] = Dev;
|
||||||
|
CheckMappings(DeviceID, ButtonName, ButtonValue, ButtonDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartAPI() {
|
||||||
|
_Running = true;
|
||||||
|
_IsStopped = false;
|
||||||
|
RailWorksThread = new Thread(RailWorksThreadMain);
|
||||||
|
RailWorksThread.IsBackground = true;
|
||||||
|
RailWorksThread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FileName = "LastUsed.CMap";
|
||||||
|
public void SaveMaps(string FilePath = "") {
|
||||||
|
if(string.IsNullOrEmpty(FilePath))
|
||||||
|
FilePath = FileName;
|
||||||
|
FileStream FStream = new FileStream(FilePath, FileMode.OpenOrCreate);
|
||||||
|
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter BFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
|
||||||
|
try {
|
||||||
|
BFormatter.Serialize(FStream, Mappings);
|
||||||
|
} catch(Exception) {
|
||||||
|
Interaction.MsgBox("The settings could not be saved to " + FilePath + "!");
|
||||||
|
} finally {
|
||||||
|
FStream.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadMaps(string FilePath = "") {
|
||||||
|
FileStream FStream = default(FileStream);
|
||||||
|
try {
|
||||||
|
FStream = new FileStream(FilePath, FileMode.Open);
|
||||||
|
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter BFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
|
||||||
|
|
||||||
|
Mappings.Clear();
|
||||||
|
Mappings = (List<Map>)BFormatter.Deserialize(FStream);
|
||||||
|
} catch(Exception) {
|
||||||
|
Interaction.MsgBox("The settings could not be loaded from " + FilePath + "!");
|
||||||
|
} finally {
|
||||||
|
if(FStream != null)
|
||||||
|
FStream.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShiftMaps(int Direction) {
|
||||||
|
Map CMap = null;
|
||||||
|
InputMap IMap = null;
|
||||||
|
|
||||||
|
for(int I = 0; I <= Mappings.Count - 1; I++) {
|
||||||
|
CMap = Mappings[I];
|
||||||
|
Removed:
|
||||||
|
for(int J = 0; J <= CMap.InputMaps.Count - 1; J++) {
|
||||||
|
IMap = CMap.InputMaps[J];
|
||||||
|
IMap.DeviceID += Direction;
|
||||||
|
if(IMap.DeviceID < 0 | IMap.DeviceID > Globals.DeviceNames.Count - 1) {
|
||||||
|
CMap.InputMaps.RemoveAt(J);
|
||||||
|
goto Removed;
|
||||||
|
}
|
||||||
|
CMap.InputMaps[J] = IMap;
|
||||||
|
}
|
||||||
|
Mappings[I] = CMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopAPI() {
|
||||||
|
SaveMaps();
|
||||||
|
Settings s = new Settings();
|
||||||
|
s.MinDelay = Vigilance.MinDelay;
|
||||||
|
s.MaxDelay = Vigilance.MaxDelay;
|
||||||
|
s.EarlyTriggerChance = Vigilance.EarlyTriggerChance;
|
||||||
|
s.TrainSpeedOffset = Vigilance.TrainSpeedOffsetFactor;
|
||||||
|
s.MinimumTrainSpeed = Vigilance.MinimumTrainSpeed;
|
||||||
|
s.TriggerTimeout = Vigilance.TriggerTimeout;
|
||||||
|
s.UseVigilance = Vigilance.UseVigilanceSystem;
|
||||||
|
_Running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsStopped() {
|
||||||
|
return _IsStopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RailWorksThreadMain() {
|
||||||
|
|
||||||
|
SetRailSimConnected(true);
|
||||||
|
SetRailDriverConnected(true);
|
||||||
|
while(_Running) {
|
||||||
|
IntPtr CurHWnd = GetForegroundWindow();
|
||||||
|
System.Text.StringBuilder CurWindowText = new System.Text.StringBuilder(255);
|
||||||
|
GetWindowText(CurHWnd, CurWindowText, 255);
|
||||||
|
if(CurWindowText.ToString() == "RailWorks") {
|
||||||
|
Vigilance.InGame = true;
|
||||||
|
SendToRW();
|
||||||
|
Vigilance.LastTrainSpeed = Math.Abs(GetRailSimValue(ActionList.Speedometer, GetValueModifier.Current));
|
||||||
|
Debug.Print(GetRailSimValue(ActionList.EmergencyBrake, GetValueModifier.Current).ToString());
|
||||||
|
if((Globals.ControlsWindow.Visible)) {
|
||||||
|
GetCurrentValues();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Vigilance.InGame = false;
|
||||||
|
}
|
||||||
|
Thread.Sleep(APIInterval);
|
||||||
|
}
|
||||||
|
_IsStopped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private delegate void OneShotDelegate(ActionList Action, float Value);
|
||||||
|
private class OneShotArgs {
|
||||||
|
public ActionList Action;
|
||||||
|
public float Value;
|
||||||
|
|
||||||
|
public OneShotDelegate OneShotDel;
|
||||||
|
public void OneShot() {
|
||||||
|
OneShotDel(Action, Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public VigilanceSystem Vigilance = new VigilanceSystem();
|
||||||
|
public void SendToRW() {
|
||||||
|
Map[] Maps = Mappings.ToArray();
|
||||||
|
foreach(Map CMap_loopVariable in Maps) {
|
||||||
|
Map CMap = CMap_loopVariable;
|
||||||
|
if(CMap.InputMaps.Count > 0) {
|
||||||
|
if(CMap.Action == ActionList.Vigilance) {
|
||||||
|
float Value = CMap.GetOutputPercent();
|
||||||
|
if(Value > 0.5) {
|
||||||
|
Vigilance.ButtonState = VigilanceSystem.Actions.Press;
|
||||||
|
} else {
|
||||||
|
Vigilance.ButtonState = VigilanceSystem.Actions.Release;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(Vigilance.State == VigilanceSystem.VigilanceState.Triggered) {
|
||||||
|
SetRailSimValue(ActionList.EmergencyBrake, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(CMap.APIType == InputMap.ControlType.Button) {
|
||||||
|
if(CMap.OneTimeShotConsumed)
|
||||||
|
continue;
|
||||||
|
CMap.OneTimeShotConsumed = true;
|
||||||
|
OneShotArgs OneShot = new OneShotArgs();
|
||||||
|
OneShot.Action = CMap.Action;
|
||||||
|
OneShot.Value = CMap.GetOutputPercent();
|
||||||
|
OneShot.OneShotDel = SendToRWOneShot;
|
||||||
|
Thread OneShotThread = new Thread(OneShot.OneShot);
|
||||||
|
OneShotThread.IsBackground = true;
|
||||||
|
OneShotThread.Start();
|
||||||
|
} else {
|
||||||
|
float Value = CMap.GetOutputPercent();
|
||||||
|
//Debug.Print("Sending " & Value & " to game with control " & CMap.Action.ToString)
|
||||||
|
switch(CMap.Action) {
|
||||||
|
case ActionList.Reverser:
|
||||||
|
Value = -1 + Value * 2;
|
||||||
|
SetRailSimValue(CMap.Action, Value);
|
||||||
|
break;
|
||||||
|
case ActionList.Throttle:
|
||||||
|
SetRailSimValue(CMap.Action, Value);
|
||||||
|
SetRailSimValue(ActionList.CombinedThrottle, Value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SetRailSimValue(CMap.Action, Value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendToRWOneShot(ActionList Action, float Value) {
|
||||||
|
switch(Action) {
|
||||||
|
// The following are treated differently
|
||||||
|
case ActionList.Sander:
|
||||||
|
case ActionList.EmergencyBrake:
|
||||||
|
case ActionList.Horn:
|
||||||
|
case ActionList.SwitchJunktionAhead:
|
||||||
|
case ActionList.SwitchJunktionBehind:
|
||||||
|
case ActionList.SwitchToNextFrontCab:
|
||||||
|
case ActionList.SwitchToNextRearCab:
|
||||||
|
SetRailSimValue(Action, Value);
|
||||||
|
break;
|
||||||
|
case ActionList.LoadCargo:
|
||||||
|
SetRailSimValue(Action, Value);
|
||||||
|
SetRailSimValue(ActionList.UnloadCargo, Value);
|
||||||
|
Thread.Sleep(50);
|
||||||
|
SetRailSimValue(Action, 0);
|
||||||
|
SetRailSimValue(ActionList.UnloadCargo, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SetRailSimValue(Action, Value);
|
||||||
|
Thread.Sleep(100);
|
||||||
|
SetRailSimValue(Action, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private delegate void GetFromRWDelegate();
|
||||||
|
|
||||||
|
public void GetCurrentValues() {
|
||||||
|
if((Globals.ControlsWindow.InvokeRequired)) {
|
||||||
|
GetFromRWDelegate Del = new GetFromRWDelegate(GetCurrentValues);
|
||||||
|
Globals.ControlsWindow.Invoke(Del);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Dictionary<string, float> DataMap = new Dictionary<string, float>();
|
||||||
|
// Get Speedometer
|
||||||
|
DataMap.Add("Speed", Math.Abs(GetRailSimValue(ActionList.Speedometer, GetValueModifier.Current)));
|
||||||
|
|
||||||
|
// Get throttle etc
|
||||||
|
// TODO: Move this someplace else?
|
||||||
|
DataMap.Add("Throttle", Mappings[(int)ActionList.Throttle].GetOutputPercent());
|
||||||
|
DataMap.Add("TrainBrake", Mappings[(int)ActionList.TrainBrake].GetOutputPercent());
|
||||||
|
DataMap.Add("LocomotiveBrake", Mappings[(int)ActionList.LocomotiveBrake].GetOutputPercent());
|
||||||
|
DataMap.Add("DynamicBrake", Mappings[(int)ActionList.DynamicBrake].GetOutputPercent());
|
||||||
|
DataMap.Add("Reverser", Mappings[(int)ActionList.Reverser].GetOutputPercent());
|
||||||
|
DataMap.Add("Gear", Mappings[(int)ActionList.GearLever].GetOutputPercent());
|
||||||
|
|
||||||
|
Globals.ControlsWindow.UpdateControls(DataMap);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<Map> Mappings = new List<Map>();
|
||||||
|
public void LoadBlank() {
|
||||||
|
|
||||||
|
Mappings.Clear();
|
||||||
|
|
||||||
|
Mappings.Add(new Map(ActionList.Reverser, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.Throttle, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.CombinedThrottle, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.GearLever, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.TrainBrake, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.LocomotiveBrake, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.DynamicBrake, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.EmergencyBrake, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.HandBrake, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.WarningSystemReset, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.StartStopEngine, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.Horn, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.Wipers, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.Sander, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.Headlights, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.Pantograph, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.FireboxDoor, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.ExhaustInjectorSteam, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.ExhaustInjectorWater, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.LiveInjectorSteam, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.LiveInjectorWater, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.Damper, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.Blower, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.Stoking, InputMap.ControlType.Axis));
|
||||||
|
Mappings.Add(new Map(ActionList.CylinderCock, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.Waterscoop, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.SmallCompressor, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.AWS, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.AWSReset, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.Startup, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.Speedometer, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.PromptSave, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.ToggleLabels, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.Toggle2DMap, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.ToggleHud, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.ToggleQut, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.Pause, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.DriverGuide, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.ToggleRvNumber, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.DialogAssignment, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.SwitchJunktionAhead, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.SwitchJunktionBehind, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.LoadCargo, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.UnloadCargo, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.PassAtDangerAhead, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.PassAtDangerBehind, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.ManualCouple, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.CabCamera, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.FollowCamera, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.HeadOutCamera, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.RearCamera, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.TrackSideCamera, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.CarriageCamera, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.CouplingCamera, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.YardCamera, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.SwitchToNextFrontCab, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.SwitchToNextRearCab, InputMap.ControlType.Button));
|
||||||
|
Mappings.Add(new Map(ActionList.FreeCamera, InputMap.ControlType.Button));
|
||||||
|
// Vigilance system is NOT part of the Raildriver dll.
|
||||||
|
Mappings.Add(new Map(ActionList.Vigilance, InputMap.ControlType.Button));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckMappings(int DeviceID, string DeviceInputName, int Value, int Delta) {
|
||||||
|
Map CMap = null;
|
||||||
|
for(int I = 0; I <= Mappings.Count - 1; I++) {
|
||||||
|
CMap = Mappings[I];
|
||||||
|
CheckInputMappings(ref CMap, DeviceID, DeviceInputName, Value, Delta);
|
||||||
|
Mappings[I] = CMap;
|
||||||
|
if(I == Globals.ControlManager.APIMapIndex & Globals.ControlManager.Visible)
|
||||||
|
Globals.ControlManager.UpdateSubscription(null,null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckInputMappings(ref Map CMap, int DeviceID, string DeviceInputName, int Value, int Delta) {
|
||||||
|
InputMap IMap = null;
|
||||||
|
bool WasAssigned = false;
|
||||||
|
for(int I = 0; I <= CMap.InputMaps.Count - 1; I++) {
|
||||||
|
IMap = CMap.InputMaps[I];
|
||||||
|
if((IMap.TreatAs == InputMap.ControlType.NotAssigned)) {
|
||||||
|
IMap.MapName = "";
|
||||||
|
IMap.DeviceID = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(IMap.TreatAs == InputMap.ControlType.Assigning & (Math.Abs(Delta) >= AssignFilter | DeviceInputName.Contains("B") | DeviceInputName.Contains("Pov"))) {
|
||||||
|
IMap.DeviceID = DeviceID;
|
||||||
|
IMap.MapName = DeviceInputName;
|
||||||
|
if(IMap.MapName.Contains("B") | IMap.MapName.Contains("Pov")) {
|
||||||
|
IMap.TreatAs = InputMap.ControlType.Button;
|
||||||
|
} else {
|
||||||
|
IMap.TreatAs = InputMap.ControlType.Axis;
|
||||||
|
}
|
||||||
|
if(Delta < 0)
|
||||||
|
IMap.Direction = InputMap.ControlDirection.Negative;
|
||||||
|
if(Delta > 0)
|
||||||
|
IMap.Direction = InputMap.ControlDirection.Positive;
|
||||||
|
if(Delta == 0)
|
||||||
|
IMap.Direction = InputMap.ControlDirection.Neutral;
|
||||||
|
// This shall NOT happen!
|
||||||
|
WasAssigned = true;
|
||||||
|
}
|
||||||
|
if((IMap.DeviceID == DeviceID & IMap.MapName == DeviceInputName)) {
|
||||||
|
IMap.DeviceValue = Value;
|
||||||
|
IMap.DeviceDelta = Delta;
|
||||||
|
CMap.InputMaps[I] = IMap;
|
||||||
|
if(WasAssigned) {
|
||||||
|
Globals.ControlManager.LoadControlMap();
|
||||||
|
WasAssigned = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopAssigning() {
|
||||||
|
Map CMap = null;
|
||||||
|
InputMap IMap = null;
|
||||||
|
for(int I = 0; I <= Mappings.Count - 1; I++) {
|
||||||
|
CMap = Mappings[I];
|
||||||
|
for(int J = 0; J <= Mappings[I].InputMaps.Count - 1; J++) {
|
||||||
|
IMap = CMap.InputMaps[J];
|
||||||
|
if(IMap.TreatAs == InputMap.ControlType.Assigning) {
|
||||||
|
IMap.TreatAs = InputMap.ControlType.NotAssigned;
|
||||||
|
CMap.InputMaps[J] = IMap;
|
||||||
|
Mappings[I] = CMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Map Class
|
||||||
|
[Serializable()]
|
||||||
|
public class Map {
|
||||||
|
public InputHandler.ActionList Action;
|
||||||
|
public InputMap.ControlType APIType;
|
||||||
|
public List<InputMap> InputMaps;
|
||||||
|
|
||||||
|
public bool OneTimeShotConsumed;
|
||||||
|
public float LatchedValue;
|
||||||
|
private float RelativeLatch;
|
||||||
|
private int LastInput = -1;
|
||||||
|
|
||||||
|
private int Toggle;
|
||||||
|
public Map(InputHandler.ActionList MapAction, InputMap.ControlType MapAPIType) {
|
||||||
|
Action = MapAction;
|
||||||
|
APIType = MapAPIType;
|
||||||
|
InputMaps = new List<InputMap>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddInput(ref InputMap IMap) {
|
||||||
|
IMap.GotInput += InputMaps_GotInput;
|
||||||
|
InputMaps.Add(IMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetPercent() {
|
||||||
|
InputMap IMap = null;
|
||||||
|
if((LastInput > InputMaps.Count - 1))
|
||||||
|
LastInput = -1;
|
||||||
|
if((LastInput == -1)) {
|
||||||
|
if(InputMaps.Count == 0)
|
||||||
|
return 0;
|
||||||
|
LastInput = 0;
|
||||||
|
}
|
||||||
|
IMap = InputMaps[LastInput];
|
||||||
|
return Globals.Clamp(IMap.GetPercent(), 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetOutputPercent() {
|
||||||
|
InputMap IMap = null;
|
||||||
|
if((LastInput > InputMaps.Count - 1))
|
||||||
|
LastInput = -1;
|
||||||
|
if((LastInput == -1)) {
|
||||||
|
if(InputMaps.Count == 0)
|
||||||
|
return 0;
|
||||||
|
LastInput = 0;
|
||||||
|
}
|
||||||
|
IMap = InputMaps[LastInput];
|
||||||
|
switch(IMap.MapMode) {
|
||||||
|
case InputMap.ControlMode.Slider: // TODO: to InputMap.ControlMode.NotchedSliderTargets
|
||||||
|
if(IMap.IsNegativePositiveRange)
|
||||||
|
return Globals.Clamp(IMap.GetOutputPercent(), -1, 1);
|
||||||
|
return Globals.Clamp(IMap.GetOutputPercent(), 0, 1);
|
||||||
|
default:
|
||||||
|
if(IMap.IsNegativePositiveRange)
|
||||||
|
return Globals.Clamp(LatchedValue, -1, 1);
|
||||||
|
return Globals.Clamp(LatchedValue, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InputMaps_GotInput(InputMap IMap) {
|
||||||
|
LastInput = InputMaps.IndexOf(IMap);
|
||||||
|
OneTimeShotConsumed = false;
|
||||||
|
switch(IMap.MapMode) {
|
||||||
|
case InputMap.ControlMode.Slider: // TODO: to InputMap.ControlMode.NotchedSliderTargets
|
||||||
|
break;
|
||||||
|
case InputMap.ControlMode.UpDownLatch:
|
||||||
|
// TODO: Check if we can use direction here too...
|
||||||
|
if(IMap.GetOutputPercent() > 0.501 & IMap.GetOutputPercent() > LatchedValue) {
|
||||||
|
LatchedValue = IMap.GetOutputPercent();
|
||||||
|
} else if(IMap.GetOutputPercent() < 0.499 & IMap.GetOutputPercent() < LatchedValue) {
|
||||||
|
LatchedValue = IMap.GetOutputPercent();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case InputMap.ControlMode.UpDownRelative:
|
||||||
|
float OutputPercent = IMap.GetOutputPercent();
|
||||||
|
float DeltaValue = 0;
|
||||||
|
if(OutputPercent > 0.501 & ((IMap.DeviceDelta > 0 & IMap.Direction == InputMap.ControlDirection.Positive) | (IMap.DeviceDelta < 0 & IMap.Direction == InputMap.ControlDirection.Negative))) {
|
||||||
|
DeltaValue = Convert.ToSingle(OutputPercent - RelativeLatch);
|
||||||
|
if(DeltaValue > 0)
|
||||||
|
LatchedValue += DeltaValue * 2;
|
||||||
|
} else if(IMap.GetOutputPercent() < 0.499 & ((IMap.DeviceDelta < 0 & IMap.Direction == InputMap.ControlDirection.Positive) | (IMap.DeviceDelta > 0 & IMap.Direction == InputMap.ControlDirection.Negative))) {
|
||||||
|
DeltaValue = Convert.ToSingle(OutputPercent - RelativeLatch);
|
||||||
|
if(DeltaValue < 0)
|
||||||
|
LatchedValue += DeltaValue * 2;
|
||||||
|
}
|
||||||
|
LatchedValue = Globals.Clamp(LatchedValue, 0, 1);
|
||||||
|
RelativeLatch = OutputPercent;
|
||||||
|
break;
|
||||||
|
case InputMap.ControlMode.Toggle:
|
||||||
|
if(IMap.NotchRanges.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(IMap.DeviceDelta > 0 & IMap.Direction == InputMap.ControlDirection.Positive) {
|
||||||
|
Toggle += 1;
|
||||||
|
}
|
||||||
|
if(IMap.DeviceDelta > 0 & IMap.Direction == InputMap.ControlDirection.Negative) {
|
||||||
|
Toggle -= 1;
|
||||||
|
}
|
||||||
|
if(Toggle >= IMap.NotchRanges.Count)
|
||||||
|
Toggle = 0;
|
||||||
|
if(Toggle < 0)
|
||||||
|
Toggle = IMap.NotchRanges.Count - 1;
|
||||||
|
LatchedValue = Globals.Clamp(IMap.NotchRanges[Toggle], 0, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// InputMap Class
|
||||||
|
[Serializable()]
|
||||||
|
public class InputMap {
|
||||||
|
|
||||||
|
public enum ControlDirection : int {
|
||||||
|
Negative = -1,
|
||||||
|
Neutral = 0,
|
||||||
|
Positive = 1
|
||||||
|
}
|
||||||
|
public enum ControlType : int {
|
||||||
|
Assigning = -1,
|
||||||
|
NotAssigned,
|
||||||
|
Axis,
|
||||||
|
Button
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ControlMode : int {
|
||||||
|
Slider,
|
||||||
|
NotchedSlider,
|
||||||
|
NotchedSliderRanges,
|
||||||
|
NotchedSliderTargets,
|
||||||
|
UpDownLatch,
|
||||||
|
UpDownRelative,
|
||||||
|
Toggle
|
||||||
|
}
|
||||||
|
|
||||||
|
public int DeviceID;
|
||||||
|
|
||||||
|
public string DeviceName {
|
||||||
|
get {
|
||||||
|
if(DeviceID < Globals.DeviceNames.Count) {
|
||||||
|
return Globals.DeviceNames[DeviceID];
|
||||||
|
}
|
||||||
|
return "<DEVICE DISCONNECTED>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string MapName;
|
||||||
|
public ControlMode MapMode;
|
||||||
|
private int _DeviceValue;
|
||||||
|
public int DeviceValue {
|
||||||
|
get { return _DeviceValue; }
|
||||||
|
set {
|
||||||
|
DeviceDelta = value - _DeviceValue;
|
||||||
|
_DeviceValue = value;
|
||||||
|
if(GotInput != null) {
|
||||||
|
GotInput(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int DeviceDelta;
|
||||||
|
public ControlDirection Direction;
|
||||||
|
|
||||||
|
public ControlType TreatAs;
|
||||||
|
public List<float> Notches;
|
||||||
|
public List<float> NotchRanges;
|
||||||
|
|
||||||
|
public bool IsNegativePositiveRange = false;
|
||||||
|
public event GotInputEventHandler GotInput;
|
||||||
|
public delegate void GotInputEventHandler(InputMap IMap);
|
||||||
|
|
||||||
|
public InputMap(ControlType TreatAsValue) {
|
||||||
|
TreatAs = TreatAsValue;
|
||||||
|
MapMode = ControlMode.Slider;
|
||||||
|
Notches = new List<float>();
|
||||||
|
NotchRanges = new List<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
if((TreatAs == ControlType.NotAssigned)) {
|
||||||
|
return "<NOT ASSIGNED>";
|
||||||
|
} else if((TreatAs == ControlType.Assigning)) {
|
||||||
|
return "<ASSIGNING...>";
|
||||||
|
} else {
|
||||||
|
return string.Format("{0} ({1}), {2}, {3}", DeviceName, DeviceID, MapName, Direction.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetPercent() {
|
||||||
|
|
||||||
|
switch(TreatAs) {
|
||||||
|
case ControlType.Axis:
|
||||||
|
if(Direction == ControlDirection.Negative) {
|
||||||
|
if(IsNegativePositiveRange)
|
||||||
|
return -1 + (Globals.Clamp(1 - Convert.ToSingle(_DeviceValue / 65535), -1, 1) * 2);
|
||||||
|
return Globals.Clamp(1 - Convert.ToSingle(_DeviceValue / 65535), 0, 1);
|
||||||
|
} else {
|
||||||
|
if(IsNegativePositiveRange)
|
||||||
|
return -1 + (Globals.Clamp(Convert.ToSingle(_DeviceValue / 65535), -1, 1) * 2);
|
||||||
|
return Globals.Clamp(Convert.ToSingle(_DeviceValue / 65535), 0, 1);
|
||||||
|
}
|
||||||
|
case ControlType.Button:
|
||||||
|
if(Direction == ControlDirection.Negative) {
|
||||||
|
return 1 - Convert.ToSingle(Globals.Clamp(_DeviceValue, 0, 1));
|
||||||
|
} else {
|
||||||
|
return Globals.Clamp(Convert.ToSingle(Globals.Clamp(_DeviceValue, 0, 1)), 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetOutputPercent() {
|
||||||
|
float Perc = GetPercent();
|
||||||
|
switch(MapMode) {
|
||||||
|
case ControlMode.Slider:
|
||||||
|
return Perc;
|
||||||
|
case ControlMode.NotchedSlider:
|
||||||
|
if(Notches.Count > 0) {
|
||||||
|
List<int> ClosestNotches = GetClosestNotches(Perc, Notches);
|
||||||
|
if(IsNegativePositiveRange)
|
||||||
|
return -1 + (Globals.Clamp(Notches[ClosestNotches[0]], -1, 1) * 2);
|
||||||
|
return Globals.Clamp(Notches[ClosestNotches[0]], 0, 1);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case ControlMode.NotchedSliderTargets:
|
||||||
|
if(Notches.Count > 1 & NotchRanges.Count > 1 & Notches.Count <= NotchRanges.Count) {
|
||||||
|
List<int> ClosestNotches = GetClosestNotches(Perc, Notches);
|
||||||
|
if(IsNegativePositiveRange)
|
||||||
|
return -1 + (Globals.Clamp(NotchRanges[ClosestNotches[0]], -1, 1) * 2);
|
||||||
|
return Globals.Clamp(NotchRanges[ClosestNotches[0]], 0, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ControlMode.NotchedSliderRanges: // TODO: to ControlMode.UpDownRelative
|
||||||
|
List<int> ClosestNotches1 = default(List<int>);
|
||||||
|
int ClosestNotchAbove = 0;
|
||||||
|
int ClosestNotchBelow = 0;
|
||||||
|
float NotchRange = 0;
|
||||||
|
float NotchPercent = 0;
|
||||||
|
float RangeRange = 0;
|
||||||
|
if(Notches.Count > 1 & NotchRanges.Count > 1 & Notches.Count <= NotchRanges.Count) {
|
||||||
|
ClosestNotches1 = GetClosestNotches(Perc, Notches);
|
||||||
|
ClosestNotchBelow = GetClosestNotch(false, Perc, ClosestNotches1, Notches);
|
||||||
|
ClosestNotchAbove = GetClosestNotch(true, Perc, ClosestNotches1, Notches);
|
||||||
|
NotchRange = Notches[ClosestNotchAbove] - Notches[ClosestNotchBelow];
|
||||||
|
if(NotchRange == 0) {
|
||||||
|
NotchPercent = 0;
|
||||||
|
} else {
|
||||||
|
NotchPercent = (Perc - Notches[ClosestNotchBelow]) / NotchRange;
|
||||||
|
}
|
||||||
|
RangeRange = NotchRanges[ClosestNotchAbove] - NotchRanges[ClosestNotchBelow];
|
||||||
|
if(IsNegativePositiveRange)
|
||||||
|
return -1 + (Globals.Clamp(NotchRanges[ClosestNotchBelow] + (RangeRange * NotchPercent), -1, 1) * 2);
|
||||||
|
return Globals.Clamp(NotchRanges[ClosestNotchBelow] + (RangeRange * NotchPercent), 0, 1);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case ControlMode.Toggle:
|
||||||
|
return Perc;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<int> GetClosestNotches(float InputPercent, List<float> NotchList)
|
||||||
|
{
|
||||||
|
Dictionary<float, int> SortDict = new Dictionary<float, int>();
|
||||||
|
float Notch = 0;
|
||||||
|
for (int I = 0; I <= NotchList.Count - 1; I++) {
|
||||||
|
Notch = NotchList[I];
|
||||||
|
float KeyName = Math.Abs(InputPercent - Notch);
|
||||||
|
if (SortDict.ContainsKey(KeyName))
|
||||||
|
KeyName += Convert.ToSingle(0.001);
|
||||||
|
SortDict.Add(Math.Abs(InputPercent - Notch), I);
|
||||||
|
}
|
||||||
|
List<float> Keys = SortDict.Keys.ToList();
|
||||||
|
Keys.Sort();
|
||||||
|
List<int> Ret = new List<int>();
|
||||||
|
foreach (float Key_loopVariable in Keys) {
|
||||||
|
float Key = Key_loopVariable;
|
||||||
|
Ret.Add(SortDict[Key]);
|
||||||
|
}
|
||||||
|
return Ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetClosestNotch(bool Above, float InputPercent, List<int> ClosestList, List<float> NotchList) {
|
||||||
|
switch(Above) {
|
||||||
|
case true:
|
||||||
|
for(int I = 0; I <= ClosestList.Count - 1; I++) {
|
||||||
|
if((NotchList[ClosestList[I]] >= InputPercent))
|
||||||
|
return ClosestList[I];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
case false:
|
||||||
|
for(int I = 0; I <= ClosestList.Count - 1; I++) {
|
||||||
|
if((NotchList[ClosestList[I]] < InputPercent))
|
||||||
|
return ClosestList[I];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|