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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|