This commit is contained in:
BlubbFish 2015-06-18 16:44:44 +00:00
commit b5e98da66b
124 changed files with 6088 additions and 0 deletions

View 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

View 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();
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

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

Some files were not shown because too many files have changed in this diff Show More