Reorganize source files into logical subdirectories

Co-authored-by: Hirek193 <23196899+Hirek193@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-14 19:01:57 +00:00
parent f981f81d55
commit 0531086bb9
221 changed files with 131 additions and 108 deletions

895
input/command.cpp Normal file
View File

@@ -0,0 +1,895 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "command.h"
#include "Globals.h"
#include "Logs.h"
#include "Timer.h"
#include "utilities.h"
#include "simulation.h"
#include "Train.h"
namespace simulation {
command_queue Commands;
commanddescription_sequence Commands_descriptions = {
{"aidriverenable", command_target::vehicle, command_mode::oneoff},
{"aidriverdisable", command_target::vehicle, command_mode::oneoff},
{"jointcontrollerset", command_target::vehicle, command_mode::oneoff},
{"mastercontrollerincrease", command_target::vehicle, command_mode::oneoff},
{"mastercontrollerincreasefast", command_target::vehicle, command_mode::oneoff},
{"mastercontrollerdecrease", command_target::vehicle, command_mode::oneoff},
{"mastercontrollerdecreasefast", command_target::vehicle, command_mode::oneoff},
{"mastercontrollerset", command_target::vehicle, command_mode::oneoff},
{"secondcontrollerincrease", command_target::vehicle, command_mode::oneoff},
{"secondcontrollerincreasefast", command_target::vehicle, command_mode::oneoff},
{"secondcontrollerdecrease", command_target::vehicle, command_mode::oneoff},
{"secondcontrollerdecreasefast", command_target::vehicle, command_mode::oneoff},
{"secondcontrollerset", command_target::vehicle, command_mode::oneoff},
{"mucurrentindicatorothersourceactivate", command_target::vehicle, command_mode::oneoff},
{"independentbrakeincrease", command_target::vehicle, command_mode::continuous},
{"independentbrakeincreasefast", command_target::vehicle, command_mode::oneoff},
{"independentbrakedecrease", command_target::vehicle, command_mode::continuous},
{"independentbrakedecreasefast", command_target::vehicle, command_mode::oneoff},
{"independentbrakeset", command_target::vehicle, command_mode::oneoff},
{"independentbrakebailoff", command_target::vehicle, command_mode::oneoff},
{"universalbrakebutton1", command_target::vehicle, command_mode::oneoff},
{"universalbrakebutton2", command_target::vehicle, command_mode::oneoff},
{"universalbrakebutton3", command_target::vehicle, command_mode::oneoff},
{"trainbrakeincrease", command_target::vehicle, command_mode::continuous},
{"trainbrakedecrease", command_target::vehicle, command_mode::continuous},
{"trainbrakeset", command_target::vehicle, command_mode::oneoff},
{"trainbrakecharging", command_target::vehicle, command_mode::oneoff},
{"trainbrakerelease", command_target::vehicle, command_mode::oneoff},
{"trainbrakefirstservice", command_target::vehicle, command_mode::oneoff},
{"trainbrakeservice", command_target::vehicle, command_mode::oneoff},
{"trainbrakefullservice", command_target::vehicle, command_mode::oneoff},
{"trainbrakehandleoff", command_target::vehicle, command_mode::oneoff},
{"trainbrakeemergency", command_target::vehicle, command_mode::oneoff},
{"trainbrakebasepressureincrease", command_target::vehicle, command_mode::oneoff},
{"trainbrakebasepressuredecrease", command_target::vehicle, command_mode::oneoff},
{"trainbrakebasepressurereset", command_target::vehicle, command_mode::oneoff},
{"trainbrakeoperationtoggle", command_target::vehicle, command_mode::oneoff},
{"manualbrakeincrease", command_target::vehicle, command_mode::oneoff},
{"manualbrakedecrease", command_target::vehicle, command_mode::oneoff},
{"alarmchaintoggle", command_target::vehicle, command_mode::oneoff},
{"alarmchainenable", command_target::vehicle, command_mode::oneoff},
{"alarmchaindisable", command_target::vehicle, command_mode::oneoff},
{"wheelspinbrakeactivate", command_target::vehicle, command_mode::oneoff},
{"sandboxactivate", command_target::vehicle, command_mode::oneoff},
{"autosandboxtoggle", command_target::vehicle, command_mode::oneoff},
{"autosandboxactivate", command_target::vehicle, command_mode::oneoff},
{"autosandboxdeactivate", command_target::vehicle, command_mode::oneoff},
{"reverserincrease", command_target::vehicle, command_mode::oneoff},
{"reverserdecrease", command_target::vehicle, command_mode::oneoff},
{"reverserforwardhigh", command_target::vehicle, command_mode::oneoff},
{"reverserforward", command_target::vehicle, command_mode::oneoff},
{"reverserneutral", command_target::vehicle, command_mode::oneoff},
{"reverserbackward", command_target::vehicle, command_mode::oneoff},
{"waterpumpbreakertoggle", command_target::vehicle, command_mode::oneoff},
{"waterpumpbreakerclose", command_target::vehicle, command_mode::oneoff},
{"waterpumpbreakeropen", command_target::vehicle, command_mode::oneoff},
{"waterpumptoggle", command_target::vehicle, command_mode::oneoff},
{"waterpumpenable", command_target::vehicle, command_mode::oneoff},
{"waterpumpdisable", command_target::vehicle, command_mode::oneoff},
{"waterheaterbreakertoggle", command_target::vehicle, command_mode::oneoff},
{"waterheaterbreakerclose", command_target::vehicle, command_mode::oneoff},
{"waterheaterbreakeropen", command_target::vehicle, command_mode::oneoff},
{"waterheatertoggle", command_target::vehicle, command_mode::oneoff},
{"waterheaterenable", command_target::vehicle, command_mode::oneoff},
{"waterheaterdisable", command_target::vehicle, command_mode::oneoff},
{"watercircuitslinktoggle", command_target::vehicle, command_mode::oneoff},
{"watercircuitslinkenable", command_target::vehicle, command_mode::oneoff},
{"watercircuitslinkdisable", command_target::vehicle, command_mode::oneoff},
{"fuelpumptoggle", command_target::vehicle, command_mode::oneoff},
{"fuelpumpenable", command_target::vehicle, command_mode::oneoff},
{"fuelpumpdisable", command_target::vehicle, command_mode::oneoff},
{"oilpumptoggle", command_target::vehicle, command_mode::oneoff},
{"oilpumpenable", command_target::vehicle, command_mode::oneoff},
{"oilpumpdisable", command_target::vehicle, command_mode::oneoff},
{"linebreakertoggle", command_target::vehicle, command_mode::oneoff},
{"linebreakeropen", command_target::vehicle, command_mode::oneoff},
{"linebreakerclose", command_target::vehicle, command_mode::oneoff},
{"convertertoggle", command_target::vehicle, command_mode::oneoff},
{"converterenable", command_target::vehicle, command_mode::oneoff},
{"converterdisable", command_target::vehicle, command_mode::oneoff},
{"convertertogglelocal", command_target::vehicle, command_mode::oneoff},
{"converteroverloadrelayreset", command_target::vehicle, command_mode::oneoff},
{"compressortoggle", command_target::vehicle, command_mode::oneoff},
{"compressorenable", command_target::vehicle, command_mode::oneoff},
{"compressordisable", command_target::vehicle, command_mode::oneoff},
{"compressortogglelocal", command_target::vehicle, command_mode::oneoff},
{"compressorpresetactivatenext", command_target::vehicle, command_mode::oneoff},
{"compressorpresetactivateprevious", command_target::vehicle, command_mode::oneoff},
{"compressorpresetactivatedefault", command_target::vehicle, command_mode::oneoff},
{"motoroverloadrelaythresholdtoggle", command_target::vehicle, command_mode::oneoff},
{"motoroverloadrelaythresholdsetlow", command_target::vehicle, command_mode::oneoff},
{"motoroverloadrelaythresholdsethigh", command_target::vehicle, command_mode::oneoff},
{"motoroverloadrelayreset", command_target::vehicle, command_mode::oneoff},
{"universalrelayreset1", command_target::vehicle, command_mode::oneoff},
{"universalrelayreset2", command_target::vehicle, command_mode::oneoff},
{"universalrelayreset3", command_target::vehicle, command_mode::oneoff},
{"notchingrelaytoggle", command_target::vehicle, command_mode::oneoff},
{"epbrakecontroltoggle", command_target::vehicle, command_mode::oneoff},
{"epbrakecontrolenable", command_target::vehicle, command_mode::oneoff},
{"epbrakecontroldisable", command_target::vehicle, command_mode::oneoff},
{"trainbrakeoperationmodeincrease", command_target::vehicle, command_mode::oneoff},
{"trainbrakeoperationmodedecrease", command_target::vehicle, command_mode::oneoff},
{"brakeactingspeedincrease", command_target::vehicle, command_mode::oneoff},
{"brakeactingspeeddecrease", command_target::vehicle, command_mode::oneoff},
{"brakeactingspeedsetcargo", command_target::vehicle, command_mode::oneoff},
{"brakeactingspeedsetpassenger", command_target::vehicle, command_mode::oneoff},
{"brakeactingspeedsetrapid", command_target::vehicle, command_mode::oneoff},
{"brakeloadcompensationincrease", command_target::vehicle, command_mode::oneoff},
{"brakeloadcompensationdecrease", command_target::vehicle, command_mode::oneoff},
{"mubrakingindicatortoggle", command_target::vehicle, command_mode::oneoff},
{"alerteracknowledge", command_target::vehicle, command_mode::oneoff},
{"cabsignalacknowledge", command_target::vehicle, command_mode::oneoff},
{"hornlowactivate", command_target::vehicle, command_mode::oneoff},
{"hornhighactivate", command_target::vehicle, command_mode::oneoff},
{"whistleactivate", command_target::vehicle, command_mode::oneoff},
{"radiotoggle", command_target::vehicle, command_mode::oneoff},
{"radioenable", command_target::vehicle, command_mode::oneoff},
{"radiodisable", command_target::vehicle, command_mode::oneoff},
{"radiochannelincrease", command_target::vehicle, command_mode::oneoff},
{"radiochanneldecrease", command_target::vehicle, command_mode::oneoff},
{"radiochannelset", command_target::vehicle, command_mode::oneoff},
{"radiostopsend", command_target::vehicle, command_mode::oneoff},
{"radiostopenable", command_target::vehicle, command_mode::oneoff},
{"radiostopdisable", command_target::vehicle, command_mode::oneoff},
{"radiostoptest", command_target::vehicle, command_mode::oneoff},
{"radiocall3send", command_target::vehicle, command_mode::oneoff},
{"radiovolumeincrease", command_target::vehicle, command_mode::oneoff},
{"radiovolumedecrease", command_target::vehicle, command_mode::oneoff},
{"radiovolumeset", command_target::vehicle, command_mode::oneoff},
{"cabchangeforward", command_target::vehicle, command_mode::oneoff},
{"cabchangebackward", command_target::vehicle, command_mode::oneoff},
{"modernlightdimmerdecrease", command_target::vehicle, command_mode::oneoff},
{"modernlightdimmerincrease", command_target::vehicle, command_mode::oneoff},
{ "viewturn", command_target::entity, command_mode::oneoff },
{ "movehorizontal", command_target::entity, command_mode::oneoff },
{ "movehorizontalfast", command_target::entity, command_mode::oneoff },
{ "movevertical", command_target::entity, command_mode::oneoff },
{ "moveverticalfast", command_target::entity, command_mode::oneoff },
{ "moveleft", command_target::entity, command_mode::oneoff },
{ "moveright", command_target::entity, command_mode::oneoff },
{ "moveforward", command_target::entity, command_mode::oneoff },
{ "moveback", command_target::entity, command_mode::oneoff },
{ "moveup", command_target::entity, command_mode::oneoff },
{ "movedown", command_target::entity, command_mode::oneoff },
{ "nearestcarcouplingincrease", command_target::vehicle, command_mode::oneoff },
{ "nearestcarcouplingdisconnect", command_target::vehicle, command_mode::oneoff },
{ "nearestcarcoupleradapterattach", command_target::vehicle, command_mode::oneoff },
{ "nearestcarcoupleradapterremove", command_target::vehicle, command_mode::oneoff },
{ "occupiedcarcouplingdisconnect", command_target::vehicle, command_mode::oneoff },
{ "occupiedcarcouplingdisconnectback", command_target::vehicle, command_mode::oneoff },
{ "doortoggleleft", command_target::vehicle, command_mode::oneoff },
{ "doortoggleright", command_target::vehicle, command_mode::oneoff },
{ "doorpermitleft", command_target::vehicle, command_mode::oneoff },
{ "doorpermitright", command_target::vehicle, command_mode::oneoff },
{ "doorpermitpresetactivatenext", command_target::vehicle, command_mode::oneoff },
{ "doorpermitpresetactivateprevious", command_target::vehicle, command_mode::oneoff },
{ "dooropenleft", command_target::vehicle, command_mode::oneoff },
{ "dooropenright", command_target::vehicle, command_mode::oneoff },
{ "dooropenall", command_target::vehicle, command_mode::oneoff },
{ "doorcloseleft", command_target::vehicle, command_mode::oneoff },
{ "doorcloseright", command_target::vehicle, command_mode::oneoff },
{ "doorcloseall", command_target::vehicle, command_mode::oneoff },
{ "doorsteptoggle", command_target::vehicle, command_mode::oneoff },
{ "doormodetoggle", command_target::vehicle, command_mode::oneoff },
{ "mirrorstoggle", command_target::vehicle, command_mode::oneoff },
{ "departureannounce", command_target::vehicle, command_mode::oneoff },
{ "doorlocktoggle", command_target::vehicle, command_mode::oneoff },
{ "pantographcompressorvalvetoggle", command_target::vehicle, command_mode::oneoff },
{ "pantographcompressorvalveenable", command_target::vehicle, command_mode::oneoff },
{ "pantographcompressorvalvedisable", command_target::vehicle, command_mode::oneoff },
{ "pantographcompressoractivate", command_target::vehicle, command_mode::oneoff },
{ "pantographtogglefront", command_target::vehicle, command_mode::oneoff },
{ "pantographtogglerear", command_target::vehicle, command_mode::oneoff },
{ "pantographraisefront", command_target::vehicle, command_mode::oneoff },
{ "pantographraiserear", command_target::vehicle, command_mode::oneoff },
{ "pantographlowerfront", command_target::vehicle, command_mode::oneoff },
{ "pantographlowerrear", command_target::vehicle, command_mode::oneoff },
{ "pantographlowerall", command_target::vehicle, command_mode::oneoff },
{ "pantographselectnext", command_target::vehicle, command_mode::oneoff },
{ "pantographselectprevious", command_target::vehicle, command_mode::oneoff },
{ "pantographtoggleselected", command_target::vehicle, command_mode::oneoff },
{ "pantographraiseselected", command_target::vehicle, command_mode::oneoff },
{ "pantographlowerselected", command_target::vehicle, command_mode::oneoff },
{ "pantographvalvesupdate", command_target::vehicle, command_mode::oneoff },
{ "pantographvalvesoff", command_target::vehicle, command_mode::oneoff },
{ "heatingtoggle", command_target::vehicle, command_mode::oneoff },
{ "heatingenable", command_target::vehicle, command_mode::oneoff },
{ "heatingdisable", command_target::vehicle, command_mode::oneoff },
{ "lightspresetactivatenext", command_target::vehicle, command_mode::oneoff },
{ "lightspresetactivateprevious", command_target::vehicle, command_mode::oneoff },
{ "headlighttoggleleft", command_target::vehicle, command_mode::oneoff },
{ "headlightenableleft", command_target::vehicle, command_mode::oneoff },
{ "headlightdisableleft", command_target::vehicle, command_mode::oneoff },
{ "headlighttoggleright", command_target::vehicle, command_mode::oneoff },
{ "headlightenableright", command_target::vehicle, command_mode::oneoff },
{ "headlightdisableright", command_target::vehicle, command_mode::oneoff },
{ "headlighttoggleupper", command_target::vehicle, command_mode::oneoff },
{ "headlightenableupper", command_target::vehicle, command_mode::oneoff },
{ "headlightdisableupper", command_target::vehicle, command_mode::oneoff },
{ "redmarkertoggleleft", command_target::vehicle, command_mode::oneoff },
{ "redmarkerenableleft", command_target::vehicle, command_mode::oneoff },
{ "redmarkerdisableleft", command_target::vehicle, command_mode::oneoff },
{ "redmarkertoggleright", command_target::vehicle, command_mode::oneoff },
{ "redmarkerenableright", command_target::vehicle, command_mode::oneoff },
{ "redmarkerdisableright", command_target::vehicle, command_mode::oneoff },
{ "headlighttogglerearleft", command_target::vehicle, command_mode::oneoff },
{ "headlightenablerearleft", command_target::vehicle, command_mode::oneoff },
{ "headlightdisablerearleft", command_target::vehicle, command_mode::oneoff },
{ "headlighttogglerearright", command_target::vehicle, command_mode::oneoff },
{ "headlightenablerearright", command_target::vehicle, command_mode::oneoff },
{ "headlightdisablerearright", command_target::vehicle, command_mode::oneoff },
{ "headlighttogglerearupper", command_target::vehicle, command_mode::oneoff },
{ "headlightenablerearupper", command_target::vehicle, command_mode::oneoff },
{ "headlightdisablerearupper", command_target::vehicle, command_mode::oneoff },
{ "redmarkertogglerearleft", command_target::vehicle, command_mode::oneoff },
{ "redmarkerenablerearleft", command_target::vehicle, command_mode::oneoff },
{ "redmarkerdisablerearleft", command_target::vehicle, command_mode::oneoff },
{ "redmarkertogglerearright", command_target::vehicle, command_mode::oneoff },
{ "redmarkerenablerearright", command_target::vehicle, command_mode::oneoff },
{ "redmarkerdisablerearright", command_target::vehicle, command_mode::oneoff },
{ "redmarkerstoggle", command_target::vehicle, command_mode::oneoff },
{ "endsignalstoggle", command_target::vehicle, command_mode::oneoff },
{ "headlightsdimtoggle", command_target::vehicle, command_mode::oneoff },
{ "headlightsdimenable", command_target::vehicle, command_mode::oneoff },
{ "headlightsdimdisable", command_target::vehicle, command_mode::oneoff },
{ "motorconnectorsopen", command_target::vehicle, command_mode::oneoff },
{ "motorconnectorsclose", command_target::vehicle, command_mode::oneoff },
{ "motordisconnect", command_target::vehicle, command_mode::oneoff },
{ "interiorlighttoggle", command_target::vehicle, command_mode::oneoff },
{ "interiorlightenable", command_target::vehicle, command_mode::oneoff },
{ "interiorlightdisable", command_target::vehicle, command_mode::oneoff },
{ "interiorlightdimtoggle", command_target::vehicle, command_mode::oneoff },
{ "interiorlightdimenable", command_target::vehicle, command_mode::oneoff },
{ "interiorlightdimdisable", command_target::vehicle, command_mode::oneoff },
{ "compartmentlightstoggle", command_target::vehicle, command_mode::oneoff },
{ "compartmentlightsenable", command_target::vehicle, command_mode::oneoff },
{ "compartmentlightsdisable", command_target::vehicle, command_mode::oneoff },
{ "instrumentlighttoggle", command_target::vehicle, command_mode::oneoff },
{ "instrumentlightenable", command_target::vehicle, command_mode::oneoff },
{ "instrumentlightdisable", command_target::vehicle, command_mode::oneoff },
{ "dashboardlighttoggle", command_target::vehicle, command_mode::oneoff },
{ "dashboardlightenable", command_target::vehicle, command_mode::oneoff },
{ "dashboardlightdisable", command_target::vehicle, command_mode::oneoff },
{ "timetablelighttoggle", command_target::vehicle, command_mode::oneoff },
{ "timetablelightenable", command_target::vehicle, command_mode::oneoff },
{ "timetablelightdisable", command_target::vehicle, command_mode::oneoff },
{"generictoggle0", command_target::vehicle, command_mode::oneoff},
{"generictoggle1", command_target::vehicle, command_mode::oneoff},
{"generictoggle2", command_target::vehicle, command_mode::oneoff},
{"generictoggle3", command_target::vehicle, command_mode::oneoff},
{"generictoggle4", command_target::vehicle, command_mode::oneoff},
{"generictoggle5", command_target::vehicle, command_mode::oneoff},
{"generictoggle6", command_target::vehicle, command_mode::oneoff},
{"generictoggle7", command_target::vehicle, command_mode::oneoff},
{"generictoggle8", command_target::vehicle, command_mode::oneoff},
{"generictoggle9", command_target::vehicle, command_mode::oneoff},
{"generictoggle10", command_target::vehicle, command_mode::oneoff},
{"generictoggle11", command_target::vehicle, command_mode::oneoff},
{"generictoggle12", command_target::vehicle, command_mode::oneoff},
{"generictoggle13", command_target::vehicle, command_mode::oneoff},
{"generictoggle14", command_target::vehicle, command_mode::oneoff},
{"generictoggle15", command_target::vehicle, command_mode::oneoff},
{"generictoggle16", command_target::vehicle, command_mode::oneoff},
{"generictoggle17", command_target::vehicle, command_mode::oneoff},
{"generictoggle18", command_target::vehicle, command_mode::oneoff},
{"generictoggle19", command_target::vehicle, command_mode::oneoff},
{"generictoggle20", command_target::vehicle, command_mode::oneoff},
{"generictoggle21", command_target::vehicle, command_mode::oneoff},
{"generictoggle22", command_target::vehicle, command_mode::oneoff},
{"generictoggle23", command_target::vehicle, command_mode::oneoff},
{"generictoggle24", command_target::vehicle, command_mode::oneoff},
{"generictoggle25", command_target::vehicle, command_mode::oneoff},
{"generictoggle26", command_target::vehicle, command_mode::oneoff},
{"generictoggle27", command_target::vehicle, command_mode::oneoff},
{"generictoggle28", command_target::vehicle, command_mode::oneoff},
{"generictoggle29", command_target::vehicle, command_mode::oneoff},
{ "batterytoggle", command_target::vehicle, command_mode::oneoff },
{ "batteryenable", command_target::vehicle, command_mode::oneoff },
{ "batterydisable", command_target::vehicle, command_mode::oneoff },
{ "cabactivationtoggle", command_target::vehicle, command_mode::oneoff },
{ "cabactivationenable", command_target::vehicle, command_mode::oneoff },
{ "cabactivationdisable", command_target::vehicle, command_mode::oneoff },
{ "motorblowerstogglefront", command_target::vehicle, command_mode::oneoff },
{ "motorblowerstogglerear", command_target::vehicle, command_mode::oneoff },
{ "motorblowersdisableall", command_target::vehicle, command_mode::oneoff },
{ "coolingfanstoggle", command_target::vehicle, command_mode::oneoff },
{ "tempomattoggle", command_target::vehicle, command_mode::oneoff },
{ "springbraketoggle", command_target::vehicle, command_mode::oneoff },
{ "springbrakeenable", command_target::vehicle, command_mode::oneoff },
{ "springbrakedisable", command_target::vehicle, command_mode::oneoff },
{ "springbrakeshutofftoggle", command_target::vehicle, command_mode::oneoff },
{ "springbrakeshutoffenable", command_target::vehicle, command_mode::oneoff },
{ "springbrakeshutoffdisable", command_target::vehicle, command_mode::oneoff },
{ "springbrakerelease", command_target::vehicle },
{ "distancecounteractivate", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolincrease", command_target::vehicle, command_mode::oneoff },
{ "speedcontroldecrease", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolpowerincrease", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolpowerdecrease", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolbutton0", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolbutton1", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolbutton2", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolbutton3", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolbutton4", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolbutton5", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolbutton6", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolbutton7", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolbutton8", command_target::vehicle, command_mode::oneoff },
{ "speedcontrolbutton9", command_target::vehicle, command_mode::oneoff },
{ "inverterenable1", command_target::vehicle, command_mode::oneoff },
{ "inverterenable2", command_target::vehicle, command_mode::oneoff },
{ "inverterenable3", command_target::vehicle, command_mode::oneoff },
{ "inverterenable4", command_target::vehicle, command_mode::oneoff },
{ "inverterenable5", command_target::vehicle, command_mode::oneoff },
{ "inverterenable6", command_target::vehicle, command_mode::oneoff },
{ "inverterenable7", command_target::vehicle, command_mode::oneoff },
{ "inverterenable8", command_target::vehicle, command_mode::oneoff },
{ "inverterenable9", command_target::vehicle, command_mode::oneoff },
{ "inverterenable10", command_target::vehicle, command_mode::oneoff },
{ "inverterenable11", command_target::vehicle, command_mode::oneoff },
{ "inverterenable12", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable1", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable2", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable3", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable4", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable5", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable6", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable7", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable8", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable9", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable10", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable11", command_target::vehicle, command_mode::oneoff },
{ "inverterdisable12", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle1", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle2", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle3", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle4", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle5", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle6", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle7", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle8", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle9", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle10", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle11", command_target::vehicle, command_mode::oneoff },
{ "invertertoggle12", command_target::vehicle, command_mode::oneoff },
{ "globalradiostop", command_target::simulation, command_mode::oneoff },
{ "timejump", command_target::simulation, command_mode::oneoff },
{ "timejumplarge", command_target::simulation, command_mode::oneoff },
{ "timejumpsmall", command_target::simulation, command_mode::oneoff },
{ "setdatetime", command_target::simulation, command_mode::oneoff },
{ "setweather", command_target::simulation, command_mode::oneoff },
{ "settemperature", command_target::simulation, command_mode::oneoff },
{ "vehiclemoveforwards", command_target::vehicle, command_mode::oneoff },
{ "vehiclemovebackwards", command_target::vehicle, command_mode::oneoff },
{ "vehicleboost", command_target::vehicle, command_mode::oneoff },
{ "debugtoggle", command_target::simulation, command_mode::oneoff },
{ "focuspauseset", command_target::simulation, command_mode::oneoff },
{ "pausetoggle", command_target::simulation, command_mode::oneoff },
{ "entervehicle", command_target::simulation, command_mode::oneoff },
{ "resetconsist", command_target::simulation, command_mode::oneoff },
{ "fillcompressor", command_target::simulation, command_mode::oneoff },
{ "consistreleaser", command_target::simulation, command_mode::oneoff },
{ "queueevent", command_target::simulation, command_mode::oneoff },
{ "setlight", command_target::simulation, command_mode::oneoff },
{ "insertmodel", command_target::simulation, command_mode::oneoff },
{ "deletemodel", command_target::simulation, command_mode::oneoff },
{ "trainsetmove", command_target::simulation, command_mode::oneoff },
{ "consistteleport", command_target::simulation, command_mode::oneoff },
{ "pullalarmchain", command_target::simulation, command_mode::oneoff },
{ "sendaicommand", command_target::simulation, command_mode::oneoff },
{ "spawntrainset", command_target::simulation, command_mode::oneoff },
{ "destroytrainset", command_target::simulation, command_mode::oneoff },
{ "quitsimulation", command_target::simulation, command_mode::oneoff },
{"wiperswitchincrease", command_target::vehicle, command_mode::oneoff},
{"wiperswitchdecrease", command_target::vehicle, command_mode::oneoff},
{"lightsset", command_target::vehicle, command_mode::oneoff},
};
// Maps of command and coresponding strings
std::unordered_map<std::string, user_command> commandMap = {
{"aidriverdisable", user_command::aidriverdisable},
{"jointcontrollerset", user_command::jointcontrollerset},
{"mastercontrollerincrease", user_command::mastercontrollerincrease},
{"mastercontrollerincreasefast", user_command::mastercontrollerincreasefast},
{"mastercontrollerdecrease", user_command::mastercontrollerdecrease},
{"mastercontrollerdecreasefast", user_command::mastercontrollerdecreasefast},
{"mastercontrollerset", user_command::mastercontrollerset},
{"secondcontrollerincrease", user_command::secondcontrollerincrease},
{"secondcontrollerincreasefast", user_command::secondcontrollerincreasefast},
{"secondcontrollerdecrease", user_command::secondcontrollerdecrease},
{"secondcontrollerdecreasefast", user_command::secondcontrollerdecreasefast},
{"secondcontrollerset", user_command::secondcontrollerset},
{"mucurrentindicatorothersourceactivate", user_command::mucurrentindicatorothersourceactivate},
{"independentbrakeincrease", user_command::independentbrakeincrease},
{"independentbrakeincreasefast", user_command::independentbrakeincreasefast},
{"independentbrakedecrease", user_command::independentbrakedecrease},
{"independentbrakedecreasefast", user_command::independentbrakedecreasefast},
{"independentbrakeset", user_command::independentbrakeset},
{"independentbrakebailoff", user_command::independentbrakebailoff},
{"universalbrakebutton1", user_command::universalbrakebutton1},
{"universalbrakebutton2", user_command::universalbrakebutton2},
{"universalbrakebutton3", user_command::universalbrakebutton3},
{"trainbrakeincrease", user_command::trainbrakeincrease},
{"trainbrakedecrease", user_command::trainbrakedecrease},
{"trainbrakeset", user_command::trainbrakeset},
{"trainbrakecharging", user_command::trainbrakecharging},
{"trainbrakerelease", user_command::trainbrakerelease},
{"trainbrakefirstservice", user_command::trainbrakefirstservice},
{"trainbrakeservice", user_command::trainbrakeservice},
{"trainbrakefullservice", user_command::trainbrakefullservice},
{"trainbrakehandleoff", user_command::trainbrakehandleoff},
{"trainbrakeemergency", user_command::trainbrakeemergency},
{"trainbrakebasepressureincrease", user_command::trainbrakebasepressureincrease},
{"trainbrakebasepressuredecrease", user_command::trainbrakebasepressuredecrease},
{"trainbrakebasepressurereset", user_command::trainbrakebasepressurereset},
{"trainbrakeoperationtoggle", user_command::trainbrakeoperationtoggle},
{"manualbrakeincrease", user_command::manualbrakeincrease},
{"manualbrakedecrease", user_command::manualbrakedecrease},
{"alarmchaintoggle", user_command::alarmchaintoggle},
{"alarmchainenable", user_command::alarmchainenable},
{"alarmchaindisable", user_command::alarmchaindisable},
{"wheelspinbrakeactivate", user_command::wheelspinbrakeactivate},
{"sandboxactivate", user_command::sandboxactivate},
{"autosandboxtoggle", user_command::autosandboxtoggle},
{"autosandboxactivate", user_command::autosandboxactivate},
{"autosandboxdeactivate", user_command::autosandboxdeactivate},
{"reverserincrease", user_command::reverserincrease},
{"reverserdecrease", user_command::reverserdecrease},
{"reverserforwardhigh", user_command::reverserforwardhigh},
{"reverserforward", user_command::reverserforward},
{"reverserneutral", user_command::reverserneutral},
{"reverserbackward", user_command::reverserbackward},
{"waterpumpbreakertoggle", user_command::waterpumpbreakertoggle},
{"waterpumpbreakerclose", user_command::waterpumpbreakerclose},
{"waterpumpbreakeropen", user_command::waterpumpbreakeropen},
{"waterpumptoggle", user_command::waterpumptoggle},
{"waterpumpenable", user_command::waterpumpenable},
{"waterpumpdisable", user_command::waterpumpdisable},
{"waterheaterbreakertoggle", user_command::waterheaterbreakertoggle},
{"waterheaterbreakerclose", user_command::waterheaterbreakerclose},
{"waterheaterbreakeropen", user_command::waterheaterbreakeropen},
{"waterheatertoggle", user_command::waterheatertoggle},
{"waterheaterenable", user_command::waterheaterenable},
{"waterheaterdisable", user_command::waterheaterdisable},
{"watercircuitslinktoggle", user_command::watercircuitslinktoggle},
{"watercircuitslinkenable", user_command::watercircuitslinkenable},
{"watercircuitslinkdisable", user_command::watercircuitslinkdisable},
{"fuelpumptoggle", user_command::fuelpumptoggle},
{"fuelpumpenable", user_command::fuelpumpenable},
{"fuelpumpdisable", user_command::fuelpumpdisable},
{"oilpumptoggle", user_command::oilpumptoggle},
{"oilpumpenable", user_command::oilpumpenable},
{"oilpumpdisable", user_command::oilpumpdisable},
{"linebreakertoggle", user_command::linebreakertoggle},
{"linebreakeropen", user_command::linebreakeropen},
{"linebreakerclose", user_command::linebreakerclose},
{"convertertoggle", user_command::convertertoggle},
{"converterenable", user_command::converterenable},
{"converterdisable", user_command::converterdisable},
{"convertertogglelocal", user_command::convertertogglelocal},
{"converteroverloadrelayreset", user_command::converteroverloadrelayreset},
{"compressortoggle", user_command::compressortoggle},
{"compressorenable", user_command::compressorenable},
{"compressordisable", user_command::compressordisable},
{"compressortogglelocal", user_command::compressortogglelocal},
{"compressorpresetactivatenext", user_command::compressorpresetactivatenext},
{"compressorpresetactivateprevious", user_command::compressorpresetactivateprevious},
{"compressorpresetactivatedefault", user_command::compressorpresetactivatedefault},
{"motoroverloadrelaythresholdtoggle", user_command::motoroverloadrelaythresholdtoggle},
{"motoroverloadrelaythresholdsetlow", user_command::motoroverloadrelaythresholdsetlow},
{"motoroverloadrelaythresholdsethigh", user_command::motoroverloadrelaythresholdsethigh},
{"motoroverloadrelayreset", user_command::motoroverloadrelayreset},
{"universalrelayreset1", user_command::universalrelayreset1},
{"universalrelayreset2", user_command::universalrelayreset2},
{"universalrelayreset3", user_command::universalrelayreset3},
{"notchingrelaytoggle", user_command::notchingrelaytoggle},
{"epbrakecontroltoggle", user_command::epbrakecontroltoggle},
{"epbrakecontrolenable", user_command::epbrakecontrolenable},
{"epbrakecontroldisable", user_command::epbrakecontroldisable},
{"trainbrakeoperationmodeincrease", user_command::trainbrakeoperationmodeincrease},
{"trainbrakeoperationmodedecrease", user_command::trainbrakeoperationmodedecrease},
{"brakeactingspeedincrease", user_command::brakeactingspeedincrease},
{"brakeactingspeeddecrease", user_command::brakeactingspeeddecrease},
{"brakeactingspeedsetcargo", user_command::brakeactingspeedsetcargo},
{"brakeactingspeedsetpassenger", user_command::brakeactingspeedsetpassenger},
{"brakeactingspeedsetrapid", user_command::brakeactingspeedsetrapid},
{"brakeloadcompensationincrease", user_command::brakeloadcompensationincrease},
{"brakeloadcompensationdecrease", user_command::brakeloadcompensationdecrease},
{"mubrakingindicatortoggle", user_command::mubrakingindicatortoggle},
{"alerteracknowledge", user_command::alerteracknowledge},
{"cabsignalacknowledge", user_command::cabsignalacknowledge},
{"hornlowactivate", user_command::hornlowactivate},
{"hornhighactivate", user_command::hornhighactivate},
{"whistleactivate", user_command::whistleactivate},
{"radiotoggle", user_command::radiotoggle},
{"radioenable", user_command::radioenable},
{"radiodisable", user_command::radiodisable},
{"radiochannelincrease", user_command::radiochannelincrease},
{"radiochanneldecrease", user_command::radiochanneldecrease},
{"radiochannelset", user_command::radiochannelset},
{"radiostopsend", user_command::radiostopsend},
{"radiostopenable", user_command::radiostopenable},
{"radiostopdisable", user_command::radiostopdisable},
{"radiostoptest", user_command::radiostoptest},
{"radiocall3send", user_command::radiocall3send},
{"radiovolumeincrease", user_command::radiovolumeincrease},
{"radiovolumedecrease", user_command::radiovolumedecrease},
{"radiovolumeset", user_command::radiovolumeset},
{"cabchangeforward", user_command::cabchangeforward},
{"cabchangebackward", user_command::cabchangebackward},
{"viewturn", user_command::viewturn},
{"movehorizontal", user_command::movehorizontal},
{"movehorizontalfast", user_command::movehorizontalfast},
{"movevertical", user_command::movevertical},
{"moveverticalfast", user_command::moveverticalfast},
{"moveleft", user_command::moveleft},
{"moveright", user_command::moveright},
{"moveforward", user_command::moveforward},
{"moveback", user_command::moveback},
{"moveup", user_command::moveup},
{"movedown", user_command::movedown},
{"nearestcarcouplingincrease", user_command::nearestcarcouplingincrease},
{"nearestcarcouplingdisconnect", user_command::nearestcarcouplingdisconnect},
{"nearestcarcoupleradapterattach", user_command::nearestcarcoupleradapterattach},
{"nearestcarcoupleradapterremove", user_command::nearestcarcoupleradapterremove},
{"occupiedcarcouplingdisconnect", user_command::occupiedcarcouplingdisconnect},
{"occupiedcarcouplingdisconnectback", user_command::occupiedcarcouplingdisconnectback},
{"doortoggleleft", user_command::doortoggleleft},
{"doortoggleright", user_command::doortoggleright},
{"doorpermitleft", user_command::doorpermitleft},
{"doorpermitright", user_command::doorpermitright},
{"doorpermitpresetactivatenext", user_command::doorpermitpresetactivatenext},
{"doorpermitpresetactivateprevious", user_command::doorpermitpresetactivateprevious},
{"dooropenleft", user_command::dooropenleft},
{"dooropenright", user_command::dooropenright},
{"dooropenall", user_command::dooropenall},
{"doorcloseleft", user_command::doorcloseleft},
{"doorcloseright", user_command::doorcloseright},
{"doorcloseall", user_command::doorcloseall},
{"doorsteptoggle", user_command::doorsteptoggle},
{"doormodetoggle", user_command::doormodetoggle},
{"mirrorstoggle", user_command::mirrorstoggle},
{"departureannounce", user_command::departureannounce},
{"doorlocktoggle", user_command::doorlocktoggle},
{"pantographcompressorvalvetoggle", user_command::pantographcompressorvalvetoggle},
{"pantographcompressorvalveenable", user_command::pantographcompressorvalveenable},
{"pantographcompressorvalvedisable", user_command::pantographcompressorvalvedisable},
{"pantographcompressoractivate", user_command::pantographcompressoractivate},
{"pantographtogglefront", user_command::pantographtogglefront},
{"pantographtogglerear", user_command::pantographtogglerear},
{"pantographraisefront", user_command::pantographraisefront},
{"pantographraiserear", user_command::pantographraiserear},
{"pantographlowerfront", user_command::pantographlowerfront},
{"pantographlowerrear", user_command::pantographlowerrear},
{"pantographlowerall", user_command::pantographlowerall},
{"pantographselectnext", user_command::pantographselectnext},
{"pantographselectprevious", user_command::pantographselectprevious},
{"pantographtoggleselected", user_command::pantographtoggleselected},
{"pantographraiseselected", user_command::pantographraiseselected},
{"pantographlowerselected", user_command::pantographlowerselected},
{"pantographvalvesupdate", user_command::pantographvalvesupdate},
{"pantographvalvesoff", user_command::pantographvalvesoff},
{"heatingtoggle", user_command::heatingtoggle},
{"heatingenable", user_command::heatingenable},
{"heatingdisable", user_command::heatingdisable},
{"lightspresetactivatenext", user_command::lightspresetactivatenext},
{"lightspresetactivateprevious", user_command::lightspresetactivateprevious},
{"headlighttoggleleft", user_command::headlighttoggleleft},
{"headlightenableleft", user_command::headlightenableleft},
{"headlightdisableleft", user_command::headlightdisableleft},
{"headlighttoggleright", user_command::headlighttoggleright},
{"headlightenableright", user_command::headlightenableright},
{"headlightdisableright", user_command::headlightdisableright},
{"headlighttoggleupper", user_command::headlighttoggleupper},
{"headlightenableupper", user_command::headlightenableupper},
{"headlightdisableupper", user_command::headlightdisableupper},
{"redmarkertoggleleft", user_command::redmarkertoggleleft},
{"redmarkerenableleft", user_command::redmarkerenableleft},
{"redmarkerdisableleft", user_command::redmarkerdisableleft},
{"redmarkertoggleright", user_command::redmarkertoggleright},
{"redmarkerenableright", user_command::redmarkerenableright},
{"redmarkerdisableright", user_command::redmarkerdisableright},
{"headlighttogglerearleft", user_command::headlighttogglerearleft},
{"headlightenablerearleft", user_command::headlightenablerearleft},
{"headlightdisablerearleft", user_command::headlightdisablerearleft},
{"headlighttogglerearright", user_command::headlighttogglerearright},
{"headlightenablerearright", user_command::headlightenablerearright},
{"headlightdisablerearright", user_command::headlightdisablerearright},
{"headlighttogglerearupper", user_command::headlighttogglerearupper},
{"headlightenablerearupper", user_command::headlightenablerearupper},
{"headlightdisablerearupper", user_command::headlightdisablerearupper},
{"redmarkertogglerearleft", user_command::redmarkertogglerearleft},
{"redmarkerenablerearleft", user_command::redmarkerenablerearleft},
{"redmarkerdisablerearleft", user_command::redmarkerdisablerearleft},
{"redmarkertogglerearright", user_command::redmarkertogglerearright},
{"redmarkerenablerearright", user_command::redmarkerenablerearright},
{"redmarkerdisablerearright", user_command::redmarkerdisablerearright},
{"redmarkerstoggle", user_command::redmarkerstoggle},
{"endsignalstoggle", user_command::endsignalstoggle},
{"headlightsdimtoggle", user_command::headlightsdimtoggle},
{"headlightsdimenable", user_command::headlightsdimenable},
{"headlightsdimdisable", user_command::headlightsdimdisable},
{"motorconnectorsopen", user_command::motorconnectorsopen},
{"motorconnectorsclose", user_command::motorconnectorsclose},
{"motordisconnect", user_command::motordisconnect},
{"interiorlighttoggle", user_command::interiorlighttoggle},
{"interiorlightenable", user_command::interiorlightenable},
{"interiorlightdisable", user_command::interiorlightdisable},
{"interiorlightdimtoggle", user_command::interiorlightdimtoggle},
{"interiorlightdimenable", user_command::interiorlightdimenable},
{"interiorlightdimdisable", user_command::interiorlightdimdisable},
{"compartmentlightstoggle", user_command::compartmentlightstoggle},
{"compartmentlightsenable", user_command::compartmentlightsenable},
{"compartmentlightsdisable", user_command::compartmentlightsdisable},
{"instrumentlighttoggle", user_command::instrumentlighttoggle},
{"instrumentlightenable", user_command::instrumentlightenable},
{"instrumentlightdisable", user_command::instrumentlightdisable},
{"dashboardlighttoggle", user_command::dashboardlighttoggle},
{"dashboardlightenable", user_command::dashboardlightenable},
{"dashboardlightdisable", user_command::dashboardlightdisable},
{"timetablelighttoggle", user_command::timetablelighttoggle},
{"timetablelightenable", user_command::timetablelightenable},
{"timetablelightdisable", user_command::timetablelightdisable},
{"generictoggle0", user_command::generictoggle0},
{"generictoggle1", user_command::generictoggle1},
{"generictoggle2", user_command::generictoggle2},
{"generictoggle3", user_command::generictoggle3},
{"generictoggle4", user_command::generictoggle4},
{"generictoggle5", user_command::generictoggle5},
{"generictoggle6", user_command::generictoggle6},
{"generictoggle7", user_command::generictoggle7},
{"generictoggle8", user_command::generictoggle8},
{"generictoggle9", user_command::generictoggle9},
{"generictoggle10", user_command::generictoggle10},
{"generictoggle11", user_command::generictoggle11},
{"generictoggle12", user_command::generictoggle12},
{"generictoggle13", user_command::generictoggle13},
{"generictoggle14", user_command::generictoggle14},
{"generictoggle15", user_command::generictoggle15},
{"generictoggle16", user_command::generictoggle16},
{"generictoggle17", user_command::generictoggle17},
{"generictoggle18", user_command::generictoggle18},
{"generictoggle19", user_command::generictoggle19},
{"generictoggle20", user_command::generictoggle20},
{"generictoggle21", user_command::generictoggle21},
{"generictoggle22", user_command::generictoggle22},
{"generictoggle23", user_command::generictoggle23},
{"generictoggle24", user_command::generictoggle24},
{"generictoggle25", user_command::generictoggle25},
{"generictoggle26", user_command::generictoggle26},
{"generictoggle27", user_command::generictoggle27},
{"generictoggle28", user_command::generictoggle28},
{"generictoggle29", user_command::generictoggle29},
{"batterytoggle", user_command::batterytoggle},
{"batteryenable", user_command::batteryenable},
{"batterydisable", user_command::batterydisable},
{"cabactivationtoggle", user_command::cabactivationtoggle},
{"cabactivationenable", user_command::cabactivationenable},
{"cabactivationdisable", user_command::cabactivationdisable},
{"motorblowerstogglefront", user_command::motorblowerstogglefront},
{"motorblowerstogglerear", user_command::motorblowerstogglerear},
{"motorblowersdisableall", user_command::motorblowersdisableall},
{"coolingfanstoggle", user_command::coolingfanstoggle},
{"tempomattoggle", user_command::tempomattoggle},
{"springbraketoggle", user_command::springbraketoggle},
{"springbrakeenable", user_command::springbrakeenable},
{"springbrakedisable", user_command::springbrakedisable},
{"springbrakeshutofftoggle", user_command::springbrakeshutofftoggle},
{"springbrakeshutoffenable", user_command::springbrakeshutoffenable},
{"springbrakeshutoffdisable", user_command::springbrakeshutoffdisable},
{"springbrakerelease", user_command::springbrakerelease},
{"distancecounteractivate", user_command::distancecounteractivate},
{"speedcontrolincrease", user_command::speedcontrolincrease},
{"speedcontroldecrease", user_command::speedcontroldecrease},
{"speedcontrolpowerincrease", user_command::speedcontrolpowerincrease},
{"speedcontrolpowerdecrease", user_command::speedcontrolpowerdecrease},
{"speedcontrolbutton0", user_command::speedcontrolbutton0},
{"speedcontrolbutton1", user_command::speedcontrolbutton1},
{"speedcontrolbutton2", user_command::speedcontrolbutton2},
{"speedcontrolbutton3", user_command::speedcontrolbutton3},
{"speedcontrolbutton4", user_command::speedcontrolbutton4},
{"speedcontrolbutton5", user_command::speedcontrolbutton5},
{"speedcontrolbutton6", user_command::speedcontrolbutton6},
{"speedcontrolbutton7", user_command::speedcontrolbutton7},
{"speedcontrolbutton8", user_command::speedcontrolbutton8},
{"speedcontrolbutton9", user_command::speedcontrolbutton9},
{"inverterenable1", user_command::inverterenable1},
{"inverterenable2", user_command::inverterenable2},
{"inverterenable3", user_command::inverterenable3},
{"inverterenable4", user_command::inverterenable4},
{"inverterenable5", user_command::inverterenable5},
{"inverterenable6", user_command::inverterenable6},
{"inverterenable7", user_command::inverterenable7},
{"inverterenable8", user_command::inverterenable8},
{"inverterenable9", user_command::inverterenable9},
{"inverterenable10", user_command::inverterenable10},
{"inverterenable11", user_command::inverterenable11},
{"inverterenable12", user_command::inverterenable12},
{"inverterdisable1", user_command::inverterdisable1},
{"inverterdisable2", user_command::inverterdisable2},
{"inverterdisable3", user_command::inverterdisable3},
{"inverterdisable4", user_command::inverterdisable4},
{"inverterdisable5", user_command::inverterdisable5},
{"inverterdisable6", user_command::inverterdisable6},
{"inverterdisable7", user_command::inverterdisable7},
{"inverterdisable8", user_command::inverterdisable8},
{"inverterdisable9", user_command::inverterdisable9},
{"inverterdisable10", user_command::inverterdisable10},
{"inverterdisable11", user_command::inverterdisable11},
{"inverterdisable12", user_command::inverterdisable12},
{"invertertoggle1", user_command::invertertoggle1},
{"invertertoggle2", user_command::invertertoggle2},
{"invertertoggle3", user_command::invertertoggle3},
{"invertertoggle4", user_command::invertertoggle4},
{"invertertoggle5", user_command::invertertoggle5},
{"invertertoggle6", user_command::invertertoggle6},
{"invertertoggle7", user_command::invertertoggle7},
{"invertertoggle8", user_command::invertertoggle8},
{"invertertoggle9", user_command::invertertoggle9},
{"invertertoggle10", user_command::invertertoggle10},
{"invertertoggle11", user_command::invertertoggle11},
{"invertertoggle12", user_command::invertertoggle12},
{"globalradiostop", user_command::globalradiostop},
{"timejump", user_command::timejump},
{"timejumplarge", user_command::timejumplarge},
{"timejumpsmall", user_command::timejumpsmall},
{"setdatetime", user_command::setdatetime},
{"setweather", user_command::setweather},
{"settemperature", user_command::settemperature},
{"vehiclemoveforwards", user_command::vehiclemoveforwards},
{"vehiclemovebackwards", user_command::vehiclemovebackwards},
{"vehicleboost", user_command::vehicleboost},
{"debugtoggle", user_command::debugtoggle},
{"focuspauseset", user_command::focuspauseset},
{"pausetoggle", user_command::pausetoggle},
{"entervehicle", user_command::entervehicle},
{"resetconsist", user_command::resetconsist},
{"fillcompressor", user_command::fillcompressor},
{"consistreleaser", user_command::consistreleaser},
{"queueevent", user_command::queueevent},
{"setlight", user_command::setlight},
{"insertmodel", user_command::insertmodel},
{"deletemodel", user_command::deletemodel},
{"dynamicmove", user_command::dynamicmove},
{"consistteleport", user_command::consistteleport},
{"pullalarmchain", user_command::pullalarmchain},
{"sendaicommand", user_command::sendaicommand},
{"spawntrainset", user_command::spawntrainset},
{"destroytrainset", user_command::destroytrainset},
{"quitsimulation", user_command::quitsimulation},
{"wiperswitchincrease", user_command::wiperswitchincrease},
{"wiperswitchdecrease", user_command::wiperswitchdecrease},
{"lightsset", user_command::lightsset},
{"none", user_command::none}};
} // namespace simulation
void command_queue::update()
{
double delta = Timer::GetDeltaTime();
for (auto c : m_active_continuous)
{
command_data data({c.first, GLFW_REPEAT, 0.0, 0.0, delta, false, glm::vec3()}); // todo: improve
auto lookup = m_commands.emplace( c.second, commanddata_sequence() );
// recipient stack was either located or created, so we can add to it quite safely
lookup.first->second.emplace_back( data );
}
}
// posts specified command for specified recipient
void
command_queue::push( command_data const &Command, uint32_t const Recipient ) {
if (is_network_target(Recipient)) {
auto lookup = m_intercept_queue.emplace(Recipient, commanddata_sequence());
lookup.first->second.emplace_back(Command);
} else {
push_direct(Command, Recipient);
}
}
void command_queue::push_direct(const command_data &Command, const uint32_t Recipient) {
auto const &desc = simulation::Commands_descriptions[ static_cast<std::size_t>( Command.command ) ];
if (desc.mode == command_mode::continuous)
{
if (Command.action == GLFW_PRESS)
m_active_continuous.emplace(std::make_pair(Command.command, Recipient));
else if (Command.action == GLFW_RELEASE)
m_active_continuous.erase(std::make_pair(Command.command, Recipient));
else if (Command.action == GLFW_REPEAT)
return;
}
auto lookup = m_commands.emplace( Recipient, commanddata_sequence() );
// recipient stack was either located or created, so we can add to it quite safely
lookup.first->second.emplace_back( Command );
}
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
bool
command_queue::pop( command_data &Command, uint32_t const Recipient ) {
auto lookup = m_commands.find( Recipient );
if( lookup == m_commands.end() ) {
// no command stack for this recipient, so no commands
return false;
}
auto &commands = lookup->second;
if( true == commands.empty() ) {
return false;
}
// we have command stack with command(s) on it, retrieve and pop the first one
Command = commands.front();
commands.pop_front();
return true;
}
bool command_queue::is_network_target(uint32_t const Recipient) {
const command_target target = (command_target)(Recipient & ~0xffff);
if (target == command_target::entity)
return false;
return true;
}
command_queue::commands_map command_queue::pop_intercept_queue() {
commands_map map(m_intercept_queue);
m_intercept_queue.clear();
return map;
}
void command_queue::push_commands(const commands_map &commands) {
for (auto const &kv : commands)
for (command_data const &data : kv.second)
push_direct(data, kv.first);
}
void
command_relay::post(user_command const Command, double const Param1, double const Param2,
int const Action, uint16_t Recipient, glm::vec3 Position, const std::string *Payload) const {
auto const &command = simulation::Commands_descriptions[ static_cast<std::size_t>( Command ) ];
if (command.target == command_target::vehicle && Recipient == 0) {
// default 0 recipient is currently controlled train
if (simulation::Train == nullptr)
return;
Recipient = simulation::Train->id();
}
if( ( command.target == command_target::vehicle )
&& ( true == FreeFlyModeFlag )
&& ( ( false == DebugModeFlag )
&& ( true == Global.RealisticControlMode ) ) ) {
// in realistic control mode don't pass vehicle commands if the user isn't in one, unless we're in debug mode
return;
}
if (Position == glm::vec3(0.0f))
Position = Global.pCamera.Pos;
uint32_t combined_recipient = static_cast<uint32_t>( command.target ) | Recipient;
command_data commanddata({Command, Action, Param1, Param2, Timer::GetDeltaTime(), FreeFlyModeFlag, Position });
if (Payload)
commanddata.payload = *Payload;
simulation::Commands.push(commanddata, combined_recipient);
}

532
input/command.h Normal file
View File

@@ -0,0 +1,532 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <unordered_map>
#include <queue>
#include <unordered_set>
enum class user_command
{
aidriverenable = 0,
aidriverdisable,
jointcontrollerset,
mastercontrollerincrease,
mastercontrollerincreasefast,
mastercontrollerdecrease,
mastercontrollerdecreasefast,
mastercontrollerset,
secondcontrollerincrease,
secondcontrollerincreasefast,
secondcontrollerdecrease,
secondcontrollerdecreasefast,
secondcontrollerset,
mucurrentindicatorothersourceactivate,
independentbrakeincrease,
independentbrakeincreasefast,
independentbrakedecrease,
independentbrakedecreasefast,
independentbrakeset,
independentbrakebailoff,
universalbrakebutton1,
universalbrakebutton2,
universalbrakebutton3,
trainbrakeincrease,
trainbrakedecrease,
trainbrakeset,
trainbrakecharging,
trainbrakerelease,
trainbrakefirstservice,
trainbrakeservice,
trainbrakefullservice,
trainbrakehandleoff,
trainbrakeemergency,
trainbrakebasepressureincrease,
trainbrakebasepressuredecrease,
trainbrakebasepressurereset,
trainbrakeoperationtoggle,
manualbrakeincrease,
manualbrakedecrease,
alarmchaintoggle,
alarmchainenable,
alarmchaindisable,
wheelspinbrakeactivate,
sandboxactivate,
autosandboxtoggle,
autosandboxactivate,
autosandboxdeactivate,
reverserincrease,
reverserdecrease,
reverserforwardhigh,
reverserforward,
reverserneutral,
reverserbackward,
waterpumpbreakertoggle,
waterpumpbreakerclose,
waterpumpbreakeropen,
waterpumptoggle,
waterpumpenable,
waterpumpdisable,
waterheaterbreakertoggle,
waterheaterbreakerclose,
waterheaterbreakeropen,
waterheatertoggle,
waterheaterenable,
waterheaterdisable,
watercircuitslinktoggle,
watercircuitslinkenable,
watercircuitslinkdisable,
fuelpumptoggle,
fuelpumpenable,
fuelpumpdisable,
oilpumptoggle,
oilpumpenable,
oilpumpdisable,
linebreakertoggle,
linebreakeropen,
linebreakerclose,
convertertoggle,
converterenable,
converterdisable,
convertertogglelocal,
converteroverloadrelayreset,
compressortoggle,
compressorenable,
compressordisable,
compressortogglelocal,
compressorpresetactivatenext,
compressorpresetactivateprevious,
compressorpresetactivatedefault,
motoroverloadrelaythresholdtoggle,
motoroverloadrelaythresholdsetlow,
motoroverloadrelaythresholdsethigh,
motoroverloadrelayreset,
universalrelayreset1,
universalrelayreset2,
universalrelayreset3,
notchingrelaytoggle,
epbrakecontroltoggle,
epbrakecontrolenable,
epbrakecontroldisable,
trainbrakeoperationmodeincrease,
trainbrakeoperationmodedecrease,
brakeactingspeedincrease,
brakeactingspeeddecrease,
brakeactingspeedsetcargo,
brakeactingspeedsetpassenger,
brakeactingspeedsetrapid,
brakeloadcompensationincrease,
brakeloadcompensationdecrease,
mubrakingindicatortoggle,
alerteracknowledge,
cabsignalacknowledge,
hornlowactivate,
hornhighactivate,
whistleactivate,
radiotoggle,
radioenable,
radiodisable,
radiochannelincrease,
radiochanneldecrease,
radiochannelset,
radiostopsend,
radiostopenable,
radiostopdisable,
radiostoptest,
radiocall3send,
radiovolumeincrease,
radiovolumedecrease,
radiovolumeset,
cabchangeforward,
cabchangebackward,
modernlightdimmerdecrease,
modernlightdimmerincrease,
viewturn,
movehorizontal,
movehorizontalfast,
movevertical,
moveverticalfast,
moveleft,
moveright,
moveforward,
moveback,
moveup,
movedown,
nearestcarcouplingincrease,
nearestcarcouplingdisconnect,
nearestcarcoupleradapterattach,
nearestcarcoupleradapterremove,
occupiedcarcouplingdisconnect,
occupiedcarcouplingdisconnectback,
doortoggleleft,
doortoggleright,
doorpermitleft,
doorpermitright,
doorpermitpresetactivatenext,
doorpermitpresetactivateprevious,
dooropenleft,
dooropenright,
dooropenall,
doorcloseleft,
doorcloseright,
doorcloseall,
doorsteptoggle,
doormodetoggle,
mirrorstoggle,
departureannounce,
doorlocktoggle,
pantographcompressorvalvetoggle,
pantographcompressorvalveenable,
pantographcompressorvalvedisable,
pantographcompressoractivate,
pantographtogglefront,
pantographtogglerear,
pantographraisefront,
pantographraiserear,
pantographlowerfront,
pantographlowerrear,
pantographlowerall,
pantographselectnext,
pantographselectprevious,
pantographtoggleselected,
pantographraiseselected,
pantographlowerselected,
pantographvalvesupdate,
pantographvalvesoff,
heatingtoggle,
heatingenable,
heatingdisable,
lightspresetactivatenext,
lightspresetactivateprevious,
headlighttoggleleft,
headlightenableleft,
headlightdisableleft,
headlighttoggleright,
headlightenableright,
headlightdisableright,
headlighttoggleupper,
headlightenableupper,
headlightdisableupper,
redmarkertoggleleft,
redmarkerenableleft,
redmarkerdisableleft,
redmarkertoggleright,
redmarkerenableright,
redmarkerdisableright,
headlighttogglerearleft,
headlightenablerearleft,
headlightdisablerearleft,
headlighttogglerearright,
headlightenablerearright,
headlightdisablerearright,
headlighttogglerearupper,
headlightenablerearupper,
headlightdisablerearupper,
redmarkertogglerearleft,
redmarkerenablerearleft,
redmarkerdisablerearleft,
redmarkertogglerearright,
redmarkerenablerearright,
redmarkerdisablerearright,
redmarkerstoggle,
endsignalstoggle,
headlightsdimtoggle,
headlightsdimenable,
headlightsdimdisable,
motorconnectorsopen,
motorconnectorsclose,
motordisconnect,
interiorlighttoggle,
interiorlightenable,
interiorlightdisable,
interiorlightdimtoggle,
interiorlightdimenable,
interiorlightdimdisable,
compartmentlightstoggle,
compartmentlightsenable,
compartmentlightsdisable,
instrumentlighttoggle,
instrumentlightenable,
instrumentlightdisable,
dashboardlighttoggle,
dashboardlightenable,
dashboardlightdisable,
timetablelighttoggle,
timetablelightenable,
timetablelightdisable,
generictoggle0,
generictoggle1,
generictoggle2,
generictoggle3,
generictoggle4,
generictoggle5,
generictoggle6,
generictoggle7,
generictoggle8,
generictoggle9,
generictoggle10,
generictoggle11,
generictoggle12,
generictoggle13,
generictoggle14,
generictoggle15,
generictoggle16,
generictoggle17,
generictoggle18,
generictoggle19,
generictoggle20,
generictoggle21,
generictoggle22,
generictoggle23,
generictoggle24,
generictoggle25,
generictoggle26,
generictoggle27,
generictoggle28,
generictoggle29,
batterytoggle,
batteryenable,
batterydisable,
cabactivationtoggle,
cabactivationenable,
cabactivationdisable,
motorblowerstogglefront,
motorblowerstogglerear,
motorblowersdisableall,
coolingfanstoggle,
tempomattoggle,
springbraketoggle,
springbrakeenable,
springbrakedisable,
springbrakeshutofftoggle,
springbrakeshutoffenable,
springbrakeshutoffdisable,
springbrakerelease,
distancecounteractivate,
speedcontrolincrease,
speedcontroldecrease,
speedcontrolpowerincrease,
speedcontrolpowerdecrease,
speedcontrolbutton0,
speedcontrolbutton1,
speedcontrolbutton2,
speedcontrolbutton3,
speedcontrolbutton4,
speedcontrolbutton5,
speedcontrolbutton6,
speedcontrolbutton7,
speedcontrolbutton8,
speedcontrolbutton9,
inverterenable1,
inverterenable2,
inverterenable3,
inverterenable4,
inverterenable5,
inverterenable6,
inverterenable7,
inverterenable8,
inverterenable9,
inverterenable10,
inverterenable11,
inverterenable12,
inverterdisable1,
inverterdisable2,
inverterdisable3,
inverterdisable4,
inverterdisable5,
inverterdisable6,
inverterdisable7,
inverterdisable8,
inverterdisable9,
inverterdisable10,
inverterdisable11,
inverterdisable12,
invertertoggle1,
invertertoggle2,
invertertoggle3,
invertertoggle4,
invertertoggle5,
invertertoggle6,
invertertoggle7,
invertertoggle8,
invertertoggle9,
invertertoggle10,
invertertoggle11,
invertertoggle12,
globalradiostop,
timejump,
timejumplarge,
timejumpsmall,
setdatetime,
setweather,
settemperature,
vehiclemoveforwards,
vehiclemovebackwards,
vehicleboost,
debugtoggle,
focuspauseset,
pausetoggle,
entervehicle,
resetconsist,
fillcompressor,
consistreleaser,
queueevent,
setlight,
insertmodel,
deletemodel,
dynamicmove,
consistteleport,
pullalarmchain,
sendaicommand,
spawntrainset,
destroytrainset,
quitsimulation,
wiperswitchincrease,
wiperswitchdecrease,
lightsset,
none = -1
};
enum class command_target {
userinterface,
/*
// NOTE: there's no need for consist- and unit-specific commands at this point, but it's a possibility.
// since command targets are mutually exclusive these don't reduce ranges for individual vehicles etc
consist = 0x4000,
unit = 0x8000,
*/
// values are combined with object id. 0xffff objects of each type should be quite enough ("for everyone")
vehicle = 0x10000,
signal = 0x20000,
entity = 0x40000,
simulation = 0x80000
};
enum class command_mode {
oneoff,
continuous
};
struct command_description {
std::string name;
command_target target;
command_mode mode;
};
struct command_data {
user_command command;
int action; // press, repeat or release
double param1;
double param2;
double time_delta;
bool freefly;
glm::vec3 location;
std::string payload;
};
// command_queues: collects and holds commands from input sources, for processing by their intended recipients
// NOTE: this won't scale well.
// TODO: turn it into a dispatcher and build individual command sequences into the items, where they can be examined without lookups
class command_queue {
public:
// types
typedef std::deque<command_data> commanddata_sequence;
typedef std::unordered_map<uint32_t, commanddata_sequence> commands_map;
// methods
// posts specified command for specified recipient into m_intercept_queue
void
push( command_data const &Command, uint32_t const Recipient );
// retrieves oldest posted command for specified recipient, if any. returns: true on retrieval, false if there's nothing to retrieve
bool
pop( command_data &Command, uint32_t const Recipient );
// generates active continuous commands
void
update();
// checks if given command must be scheduled on server
bool
is_network_target(const uint32_t Recipient);
// pops commands from intercept queue
commands_map pop_intercept_queue();
// pushes commands into main queue
void push_commands(const commands_map &commands);
private:
// members
// contains command ready to execution
commands_map m_commands;
// contains intercepted commands to be read by application layer
commands_map m_intercept_queue;
void push_direct( command_data const &Command, uint32_t const Recipient );
// hash operator for m_active_continuous
struct command_set_hash {
uint64_t operator() (const std::pair<user_command, uint32_t> &pair) const {
return ((uint64_t)pair.first << 32) | ((uint64_t) pair.second);
}
};
// currently pressed continuous commands
std::unordered_set<std::pair<user_command, uint32_t>, command_set_hash> m_active_continuous;
};
template<typename A, typename B>
void add_to_dequemap(std::unordered_map<A, std::deque<B>> &lhs, const std::unordered_map<A, std::deque<B>> &rhs) {
for (auto const &kv : rhs) {
auto lookup = lhs.emplace(kv.first, std::deque<B>());
for (B const &data : kv.second)
lookup.first->second.emplace_back(data);
}
}
// NOTE: simulation should be a (light) wrapper rather than namespace so we could potentially instance it,
// but realistically it's not like we're going to run more than one simulation at a time
namespace simulation {
typedef std::vector<command_description> commanddescription_sequence;
extern command_queue Commands;
// TODO: add name to command map, and wrap these two into helper object
extern commanddescription_sequence Commands_descriptions;
extern std::unordered_map<std::string, user_command> commandMap;
}
// command_relay: composite class component, passes specified command to appropriate command stack
class command_relay {
public:
// methods
// posts specified command for the specified recipient
void
post(user_command const Command, double const Param1, double const Param2,
int const Action, uint16_t Recipient, glm::vec3 Position = glm::vec3(0.0f) , const std::string *Payload = nullptr) const;
private:
// types
// members
};
//---------------------------------------------------------------------------

View File

@@ -0,0 +1,324 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "driverkeyboardinput.h"
bool
driverkeyboard_input::init() {
default_bindings();
recall_bindings();
bind();
return true;
}
void
driverkeyboard_input::default_bindings() {
m_bindingsetups = {
{ user_command::aidriverenable, {GLFW_KEY_Q | keymodifier::shift, ""} },
{ user_command::aidriverdisable, {GLFW_KEY_Q, ""} },
// jointcontrollerset,
{ user_command::mastercontrollerincrease, {GLFW_KEY_KP_ADD, ""} },
{ user_command::mastercontrollerincreasefast, {GLFW_KEY_KP_ADD | keymodifier::shift, ""} },
{ user_command::mastercontrollerdecrease, {GLFW_KEY_KP_SUBTRACT, ""} },
{ user_command::mastercontrollerdecreasefast, {GLFW_KEY_KP_SUBTRACT | keymodifier::shift, ""} },
// mastercontrollerset,
{ user_command::secondcontrollerincrease, {GLFW_KEY_KP_DIVIDE, ""} },
{ user_command::secondcontrollerincreasefast, {GLFW_KEY_KP_DIVIDE | keymodifier::shift, ""} },
{ user_command::secondcontrollerdecrease, {GLFW_KEY_KP_MULTIPLY, ""} },
{ user_command::secondcontrollerdecreasefast, {GLFW_KEY_KP_MULTIPLY | keymodifier::shift, ""} },
// secondcontrollerset,
{ user_command::mucurrentindicatorothersourceactivate, {GLFW_KEY_Z | keymodifier::shift, ""} },
{ user_command::independentbrakeincrease, {GLFW_KEY_KP_1, ""} },
{ user_command::independentbrakeincreasefast, {GLFW_KEY_KP_1 | keymodifier::shift, ""} },
{ user_command::independentbrakedecrease, {GLFW_KEY_KP_7, ""} },
{ user_command::independentbrakedecreasefast, {GLFW_KEY_KP_7 | keymodifier::shift, ""} },
// independentbrakeset,
{ user_command::independentbrakebailoff, {GLFW_KEY_KP_4, ""} },
// universalbrakebutton1,
// universalbrakebutton2,
// universalbrakebutton3,
{ user_command::trainbrakeincrease, {GLFW_KEY_KP_3, ""} },
{ user_command::trainbrakedecrease, {GLFW_KEY_KP_9, ""} },
// trainbrakeset,
{ user_command::trainbrakecharging, {GLFW_KEY_KP_DECIMAL, ""} },
{ user_command::trainbrakerelease, {GLFW_KEY_KP_6, ""} },
{ user_command::trainbrakefirstservice, {GLFW_KEY_KP_8, ""} },
{ user_command::trainbrakeservice, {GLFW_KEY_KP_5, ""} },
{ user_command::trainbrakefullservice, {GLFW_KEY_KP_2, ""} },
{ user_command::trainbrakehandleoff, {GLFW_KEY_KP_5 | keymodifier::control, ""} },
{ user_command::trainbrakeemergency, {GLFW_KEY_KP_0, ""} },
{ user_command::trainbrakebasepressureincrease, {GLFW_KEY_KP_3 | keymodifier::control, ""} },
{ user_command::trainbrakebasepressuredecrease, {GLFW_KEY_KP_9 | keymodifier::control, ""} },
{ user_command::trainbrakebasepressurereset, {GLFW_KEY_KP_6 | keymodifier::control, ""} },
{ user_command::trainbrakeoperationtoggle, {GLFW_KEY_KP_4 | keymodifier::control, ""} },
{ user_command::manualbrakeincrease, {GLFW_KEY_KP_1 | keymodifier::control, ""} },
{ user_command::manualbrakedecrease, {GLFW_KEY_KP_7 | keymodifier::control, ""} },
{ user_command::alarmchaintoggle, {GLFW_KEY_B | keymodifier::shift | keymodifier::control, ""} },
// alarmchainenable,
// alarmchaindisable,
{ user_command::wheelspinbrakeactivate, {GLFW_KEY_KP_ENTER, ""} },
{ user_command::sandboxactivate, {GLFW_KEY_S | keymodifier::shift, ""} },
// autosandboxtoggle,
// autosandboxactivate,
// autosandboxdeactivate,
{ user_command::reverserincrease, {GLFW_KEY_D, ""} },
{ user_command::reverserdecrease, {GLFW_KEY_R, ""} },
// reverserforwardhigh,
// reverserforward,
// reverserneutral,
// reverserbackward,
{ user_command::waterpumpbreakertoggle, {GLFW_KEY_W | keymodifier::control, ""} },
// waterpumpbreakerclose,
// waterpumpbreakeropen,
{ user_command::waterpumptoggle, {GLFW_KEY_W, ""} },
// waterpumpenable,
// waterpumpdisable,
{ user_command::waterheaterbreakertoggle, {GLFW_KEY_W | keymodifier::control | keymodifier::shift, ""} },
// waterheaterbreakerclose,
// waterheaterbreakeropen,
{ user_command::waterheatertoggle, {GLFW_KEY_W | keymodifier::shift, ""} },
// waterheaterenable,
// waterheaterdisable,
{ user_command::watercircuitslinktoggle, {GLFW_KEY_H | keymodifier::shift, ""} },
// watercircuitslinkenable,
// watercircuitslinkdisable,
{ user_command::fuelpumptoggle, {GLFW_KEY_F, ""} },
// fuelpumpenable,
// fuelpumpdisable,
{ user_command::oilpumptoggle, {GLFW_KEY_F | keymodifier::shift, ""} },
// oilpumpenable,
// oilpumpdisable,
{ user_command::linebreakertoggle, {GLFW_KEY_M, ""} },
// linebreakeropen,
// linebreakerclose,
{ user_command::convertertoggle, {GLFW_KEY_X, ""} },
// converterenable,
// converterdisable,
{ user_command::convertertogglelocal, {GLFW_KEY_X | keymodifier::shift, ""} },
{ user_command::converteroverloadrelayreset, {GLFW_KEY_N | keymodifier::control, ""} },
{ user_command::compressortoggle, {GLFW_KEY_C, ""} },
// compressorenable,
// compressordisable,
{ user_command::compressortogglelocal, {GLFW_KEY_C | keymodifier::shift, ""} },
// compressorpresetactivatenext,
// compressorpresetactivateprevious,
// compressorpresetactivatedefault,
{ user_command::motoroverloadrelaythresholdtoggle, {GLFW_KEY_F | keymodifier::control, ""} },
// motoroverloadrelaythresholdsetlow,
// motoroverloadrelaythresholdsethigh,
{ user_command::motoroverloadrelayreset, {GLFW_KEY_N, ""} },
// universalrelayreset1,
// universalrelayreset2,
// universalrelayreset3,
{ user_command::notchingrelaytoggle, {GLFW_KEY_G, ""} },
{ user_command::epbrakecontroltoggle, {GLFW_KEY_Z | keymodifier::control, ""} },
// epbrakecontrolenable
// epbrakecontroldisable
{ user_command::trainbrakeoperationmodeincrease, {GLFW_KEY_KP_2 | keymodifier::control, ""} },
{ user_command::trainbrakeoperationmodedecrease, {GLFW_KEY_KP_8 | keymodifier::control, ""} },
{ user_command::brakeactingspeedincrease, {GLFW_KEY_B | keymodifier::shift, ""} },
{ user_command::brakeactingspeeddecrease, {GLFW_KEY_B, ""} },
// brakeactingspeedsetcargo,
// brakeactingspeedsetpassenger,
// brakeactingspeedsetrapid,
{ user_command::brakeloadcompensationincrease, {GLFW_KEY_H | keymodifier::shift | keymodifier::control, ""} },
{ user_command::brakeloadcompensationdecrease, {GLFW_KEY_H | keymodifier::control, ""} },
{ user_command::mubrakingindicatortoggle, {GLFW_KEY_L | keymodifier::shift, ""} },
{ user_command::alerteracknowledge, {GLFW_KEY_SPACE, ""} },
{ user_command::hornlowactivate, {GLFW_KEY_A, ""} },
{ user_command::hornhighactivate, {GLFW_KEY_S, ""} },
{ user_command::whistleactivate, {GLFW_KEY_Z, ""} },
{ user_command::radiotoggle, {GLFW_KEY_R | keymodifier::control, ""} },
// radioenable
// radiodisable
{ user_command::radiochannelincrease, {GLFW_KEY_EQUAL, ""} },
{ user_command::radiochanneldecrease, {GLFW_KEY_MINUS, ""} },
// radiochannelset
{ user_command::radiostopsend, {GLFW_KEY_PAUSE | keymodifier::shift | keymodifier::control, ""} },
// radiostopenable
// radiostopdisable
{ user_command::radiostoptest, {GLFW_KEY_R | keymodifier::shift | keymodifier::control, ""} },
{ user_command::radiocall3send, {GLFW_KEY_BACKSPACE, ""} },
// radiovolumeincrease,
// radiovolumedecrease,
// radiovolumeset,
{ user_command::cabchangeforward, {GLFW_KEY_HOME, ""} },
{ user_command::cabchangebackward, {GLFW_KEY_END, ""} },
// viewturn,
// movehorizontal,
// movehorizontalfast,
// movevertical,
// moveverticalfast,
{ user_command::moveleft, {GLFW_KEY_LEFT, "Move left"} },
{ user_command::moveright, {GLFW_KEY_RIGHT, "Move right"} },
{ user_command::moveforward, {GLFW_KEY_UP, "Move forwards"} },
{ user_command::moveback, {GLFW_KEY_DOWN, "Move backwards"} },
{ user_command::moveup, {GLFW_KEY_PAGE_UP, "Move up"} },
{ user_command::movedown, {GLFW_KEY_PAGE_DOWN, "Move down"} },
{ user_command::nearestcarcouplingincrease, {GLFW_KEY_INSERT, ""} },
{ user_command::nearestcarcouplingdisconnect, {GLFW_KEY_DELETE, ""} },
{ user_command::nearestcarcoupleradapterattach, {GLFW_KEY_INSERT | keymodifier::control, ""} },
{ user_command::nearestcarcoupleradapterremove, {GLFW_KEY_DELETE | keymodifier::control, ""} },
{ user_command::occupiedcarcouplingdisconnect, {GLFW_KEY_DELETE | keymodifier::shift, ""} },
{ user_command::doortoggleleft, {GLFW_KEY_COMMA, ""} },
{ user_command::doortoggleright, {GLFW_KEY_PERIOD, ""} },
{ user_command::doorpermitleft, {GLFW_KEY_COMMA | keymodifier::shift, ""} },
{ user_command::doorpermitright, {GLFW_KEY_PERIOD | keymodifier::shift, ""} },
{ user_command::doorpermitpresetactivatenext, {GLFW_KEY_PERIOD | keymodifier::shift | keymodifier::control, ""} },
{ user_command::doorpermitpresetactivateprevious, {GLFW_KEY_COMMA | keymodifier::shift | keymodifier::control, ""} },
// dooropenleft,
// dooropenright,
{ user_command::dooropenall, {GLFW_KEY_SLASH | keymodifier::shift, ""} },
// doorcloseleft,
// doorcloseright,
{ user_command::doorcloseall, {GLFW_KEY_SLASH | keymodifier::control, ""} },
// doorsteptoggle,
{ user_command::doormodetoggle, {GLFW_KEY_SLASH | keymodifier::shift | keymodifier::control, ""} },
// mirrorstoggle,
{ user_command::departureannounce, {GLFW_KEY_SLASH, ""} },
{ user_command::doorlocktoggle, {GLFW_KEY_S | keymodifier::control, ""} },
{ user_command::pantographcompressorvalvetoggle, {GLFW_KEY_V | keymodifier::control, ""} },
// pantographcompressorvalveenable,
// pantographcompressorvalvedisable,
{ user_command::pantographcompressoractivate, {GLFW_KEY_V | keymodifier::shift, ""} },
{ user_command::pantographtogglefront, {GLFW_KEY_P, ""} },
{ user_command::pantographtogglerear, {GLFW_KEY_O, ""} },
// pantographraisefront,
// pantographraiserear,
// pantographlowerfront,
// pantographlowerrear,
{ user_command::pantographlowerall, {GLFW_KEY_P | keymodifier::control, ""} },
{ user_command::pantographselectnext, {GLFW_KEY_P | keymodifier::shift, ""} },
{ user_command::pantographselectprevious, {GLFW_KEY_O | keymodifier::shift, ""} },
{ user_command::pantographtoggleselected, {GLFW_KEY_O | keymodifier::shift | keymodifier::control, ""} },
// pantographraiseselected,
// pantographlowerselected,
// pantographvalvesupdate,
// pantographvalvesoff,
{ user_command::heatingtoggle, {GLFW_KEY_H, ""} },
// heatingenable,
// heatingdisable,
{ user_command::lightspresetactivatenext, {GLFW_KEY_T | keymodifier::shift, ""} },
{ user_command::lightspresetactivateprevious, {GLFW_KEY_T, ""} },
{ user_command::headlighttoggleleft, {GLFW_KEY_Y, ""} },
// headlightenableleft,
// headlightdisableleft,
{ user_command::headlighttoggleright, {GLFW_KEY_I, ""} },
// headlightenableright,
// headlightdisableright,
{ user_command::headlighttoggleupper, {GLFW_KEY_U, ""} },
// headlightenableupper,
// headlightdisableupper,
{ user_command::redmarkertoggleleft, {GLFW_KEY_Y | keymodifier::shift, ""} },
// redmarkerenableleft,
// redmarkerdisableleft,
{ user_command::redmarkertoggleright, {GLFW_KEY_I | keymodifier::shift, ""} },
// redmarkerenableright,
// redmarkerdisableright,
{ user_command::headlighttogglerearleft, {GLFW_KEY_Y | keymodifier::control, ""} },
// headlightenablerearleft
// headlightdisablerearleft
{ user_command::headlighttogglerearright, {GLFW_KEY_I | keymodifier::control, ""} },
// headlightenablerearright
// headlightdisablerearright
{ user_command::headlighttogglerearupper, {GLFW_KEY_U | keymodifier::control, ""} },
// headlightenablerearupper
// headlightdisablerearupper
{ user_command::redmarkertogglerearleft, {GLFW_KEY_Y | keymodifier::control | keymodifier::shift, ""} },
// redmarkerenablerearleft
// redmarkerdisablerearleft
{ user_command::redmarkertogglerearright, {GLFW_KEY_I | keymodifier::control | keymodifier::shift, ""} },
// redmarkerenablerearright
// redmarkerdisablerearright
{ user_command::redmarkerstoggle, {GLFW_KEY_E | keymodifier::shift, ""} },
{ user_command::endsignalstoggle, {GLFW_KEY_E, ""} },
{ user_command::headlightsdimtoggle, {GLFW_KEY_L | keymodifier::control, ""} },
// headlightsdimenable,
// headlightsdimdisable,
{ user_command::motorconnectorsopen, {GLFW_KEY_L, ""} },
// motorconnectorsclose,
{ user_command::motordisconnect, {GLFW_KEY_E | keymodifier::control, ""} },
{ user_command::interiorlighttoggle, {GLFW_KEY_APOSTROPHE, ""} },
// interiorlightenable,
// interiorlightdisable,
{ user_command::interiorlightdimtoggle, {GLFW_KEY_APOSTROPHE | keymodifier::control, ""} },
// interiorlightdimenable,
// interiorlightdimdisable,
// compartmentlightstoggle,
// compartmentlightsenable,
// compartmentlightsdisable,
{ user_command::instrumentlighttoggle, {GLFW_KEY_SEMICOLON, ""} },
// instrumentlightenable,
// instrumentlightdisable,
{ user_command::dashboardlighttoggle, {GLFW_KEY_SEMICOLON | keymodifier::shift, ""} },
// dashboardlightenable
// dashboardlightdisable
{ user_command::timetablelighttoggle, {GLFW_KEY_APOSTROPHE | keymodifier::shift, ""} },
// timetablelightenable
// timetablelightdisable
{ user_command::generictoggle0, {GLFW_KEY_0, ""} },
{ user_command::generictoggle1, {GLFW_KEY_1, ""} },
{ user_command::generictoggle2, {GLFW_KEY_2, ""} },
{ user_command::generictoggle3, {GLFW_KEY_3, ""} },
{ user_command::generictoggle4, {GLFW_KEY_4, ""} },
{ user_command::generictoggle5, {GLFW_KEY_5, ""} },
{ user_command::generictoggle6, {GLFW_KEY_6, ""} },
{ user_command::generictoggle7, {GLFW_KEY_7, ""} },
{ user_command::generictoggle8, {GLFW_KEY_8, ""} },
{ user_command::generictoggle9, {GLFW_KEY_9, ""} },
{ user_command::batterytoggle, {GLFW_KEY_J, ""} },
// batteryenable,
// batterydisable,
// cabactivationtoggle,
// cabactivationenable,
// cabactivationdisable,
{ user_command::motorblowerstogglefront, {GLFW_KEY_N | keymodifier::shift, ""} },
{ user_command::motorblowerstogglerear, {GLFW_KEY_M | keymodifier::shift, ""} },
{ user_command::motorblowersdisableall, {GLFW_KEY_M | keymodifier::control, ""} },
// coolingfanstoggle,
// tempomattoggle,
// springbraketoggle,
// springbrakeenable,
// springbrakedisable,
// springbrakeshutofftoggle,
// springbrakeshutoffenable,
// springbrakeshutoffdisable,
// springbrakerelease,
// distancecounteractivate,
// speedcontrolincrease,
// speedcontroldecrease,
// speedcontrolpowerincrease,
// speedcontrolpowerdecrease,
// speedcontrolbutton0,
// speedcontrolbutton1,
// speedcontrolbutton2,
// speedcontrolbutton3,
// speedcontrolbutton4,
// speedcontrolbutton5,
// speedcontrolbutton6,
// speedcontrolbutton7,
// speedcontrolbutton8,
// speedcontrolbutton9,
// admin_timejump,
{ user_command::timejumplarge, {GLFW_KEY_F1 | keymodifier::control, "Big time jump (Debug Mode only)"} },
{ user_command::timejumpsmall, {GLFW_KEY_F1 | keymodifier::shift, "Small time jump (Debug Mode only)"} },
// admin_vehiclemove,
{ user_command::vehiclemoveforwards, {GLFW_KEY_LEFT_BRACKET | keymodifier::control, "Move the train forwards (Debug Mode only)"} },
{ user_command::vehiclemovebackwards, {GLFW_KEY_RIGHT_BRACKET | keymodifier::control, "Move the train backwards (Debug Mode only)"} },
{ user_command::vehicleboost, {GLFW_KEY_TAB | keymodifier::control, "Boost the train (Debug Mode only)"} },
{ user_command::debugtoggle, {GLFW_KEY_F12 | keymodifier::control | keymodifier::shift, "Toggle Debug Mode"} },
{ user_command::pausetoggle, {GLFW_KEY_ESCAPE, "Pause the game"} }
};
}
//---------------------------------------------------------------------------

View File

@@ -0,0 +1,27 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "keyboardinput.h"
class driverkeyboard_input : public keyboard_input {
public:
// methods
bool
init() override;
protected:
// methods
void
default_bindings();
};
//---------------------------------------------------------------------------

1165
input/drivermouseinput.cpp Normal file

File diff suppressed because it is too large Load Diff

114
input/drivermouseinput.h Normal file
View File

@@ -0,0 +1,114 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <unordered_map>
#include "command.h"
// virtual slider; value determined by position of the mouse
class mouse_slider {
public:
// constructors
mouse_slider() = default;
// methods
void
bind( user_command const &Command );
void
release();
void
on_move( double const Mousex, double const Mousey );
inline
user_command
command() const {
return m_command; }
double
value() const {
return m_value; }
private:
// members
user_command m_command { user_command::none };
double m_value { 0.0 };
double m_valuerange { 0.0 };
bool m_analogue { false };
bool m_invertrange { false };
glm::dvec2 m_cursorposition { 0.0 };
};
class drivermouse_input {
public:
// constructors
drivermouse_input() = default;
// methods
bool
init();
bool
recall_bindings();
void
button( int const Button, int const Action );
int
button( int const Button ) const;
void
move( double const Horizontal, double const Vertical );
void
scroll( double const Xoffset, double const Yoffset );
void
poll();
user_command
command() const;
// returns pair of bindings associated with specified cab control
std::pair<user_command, user_command>
bindings( std::string const &Control ) const;
private:
// types
struct button_bindings {
user_command left;
user_command right;
};
struct wheel_bindings {
user_command up;
user_command down;
};
typedef std::unordered_map<std::string, button_bindings> buttonbindings_map;
// methods
void
default_bindings();
// potentially replaces supplied command with a more relevant one
user_command
adjust_command( user_command Command );
// members
command_relay m_relay;
mouse_slider m_slider; // virtual control, when active translates intercepted mouse position to a value
buttonbindings_map m_buttonbindings;
wheel_bindings m_wheelbindings { user_command::mastercontrollerincrease, user_command::mastercontrollerdecrease }; // commands bound to the scroll wheel
user_command m_mousecommandleft { user_command::none }; // last if any command issued with left mouse button
user_command m_mousecommandright { user_command::none }; // last if any command issued with right mouse button
double m_updaterate { 0.075 };
double m_updatedelay { 0.25 };
double m_updateaccumulator { 0.0 };
bool m_pickmodepanning { false }; // indicates mouse is in view panning mode
glm::dvec2 m_cursorposition; // stored last cursor position, used for panning
bool m_varyingpollrate { false }; // indicates rate of command repeats is affected by the cursor position
glm::dvec2 m_varyingpollrateorigin; // helper, cursor position when the command was initiated
std::array<int, GLFW_MOUSE_BUTTON_LAST> m_buttons;
bool m_pickwaiting;
};
//---------------------------------------------------------------------------

View File

@@ -0,0 +1,37 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "editorkeyboardinput.h"
bool
editorkeyboard_input::init() {
default_bindings();
// TODO: re-enable after mode-specific binding import is in place
// return recall_bindings();
bind();
return true;
}
void
editorkeyboard_input::default_bindings() {
m_bindingsetups = {
{ user_command::moveleft, {GLFW_KEY_A, "Move left"} },
{ user_command::moveright, {GLFW_KEY_D, "Move right"} },
{ user_command::moveforward, {GLFW_KEY_W, "Move forwards"} },
{ user_command::moveback, {GLFW_KEY_S, "Move backwards"} },
{ user_command::moveup, {GLFW_KEY_E, "Move up"} },
{ user_command::movedown, {GLFW_KEY_Q, "Move down"} },
};
}
//---------------------------------------------------------------------------

View File

@@ -0,0 +1,27 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "keyboardinput.h"
class editorkeyboard_input : public keyboard_input {
public:
// methods
bool
init() override;
protected:
// methods
void
default_bindings() override;
};
//---------------------------------------------------------------------------

View File

@@ -0,0 +1,54 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "editormouseinput.h"
bool
editormouse_input::init() {
return true;
}
void
editormouse_input::position( double Horizontal, double Vertical ) {
if( false == m_pickmodepanning ) {
// even if the view panning isn't active we capture the cursor position in case it does get activated
m_cursorposition.x = Horizontal;
m_cursorposition.y = Vertical;
return;
}
glm::dvec2 cursorposition { Horizontal, Vertical };
auto const viewoffset = cursorposition - m_cursorposition;
m_relay.post(
user_command::viewturn,
viewoffset.x,
viewoffset.y,
GLFW_PRESS,
// TODO: pass correct entity id once the missing systems are in place
0 );
m_cursorposition = cursorposition;
}
void
editormouse_input::button( int const Button, int const Action ) {
// store key state
if( Button >= 0 ) {
m_buttons[ Button ] = Action;
}
// right button controls panning
if( Button == GLFW_MOUSE_BUTTON_RIGHT ) {
m_pickmodepanning = ( Action == GLFW_PRESS );
}
}
//---------------------------------------------------------------------------

44
input/editormouseinput.h Normal file
View File

@@ -0,0 +1,44 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "command.h"
class editormouse_input {
public:
// constructors
editormouse_input() = default;
// methods
bool
init();
void
position( double const Horizontal, double const Vertical );
inline
glm::dvec2
position() const {
return m_cursorposition; }
void
button( int const Button, int const Action );
inline
int
button( int const Button ) const {
return m_buttons[ Button ]; }
private:
// members
command_relay m_relay;
bool m_pickmodepanning { false }; // indicates mouse is in view panning mode
glm::dvec2 m_cursorposition { 0.0 }; // stored last cursor position, used for panning
std::array<int, GLFW_MOUSE_BUTTON_LAST> m_buttons { GLFW_RELEASE };
};
//---------------------------------------------------------------------------

533
input/gamepadinput.cpp Normal file
View File

@@ -0,0 +1,533 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "gamepadinput.h"
#include "Logs.h"
#include "Timer.h"
#include "utilities.h"
#include "parser.h"
glm::vec2 circle_to_square( glm::vec2 const &Point, int const Roundness = 0 ) {
// Determine the theta angle
auto angle = std::atan2( Point.x, Point.y ) + M_PI;
glm::vec2 squared;
// Scale according to which wall we're clamping to
// X+ wall
if( angle <= M_PI_4 || angle > 7 * M_PI_4 )
squared = Point * (float)( 1.0 / std::cos( angle ) );
// Y+ wall
else if( angle > M_PI_4 && angle <= 3 * M_PI_4 )
squared = Point * (float)( 1.0 / std::sin( angle ) );
// X- wall
else if( angle > 3 * M_PI_4 && angle <= 5 * M_PI_4 )
squared = Point * (float)( -1.0 / std::cos( angle ) );
// Y- wall
else if( angle > 5 * M_PI_4 && angle <= 7 * M_PI_4 )
squared = Point * (float)( -1.0 / std::sin( angle ) );
// Early-out for a perfect square output
if( Roundness == 0 )
return squared;
// Find the inner-roundness scaling factor and LERP
auto const length = glm::length( Point );
auto const factor = std::pow( length, Roundness );
return interpolate( Point, squared, (float)factor );
}
bool
gamepad_input::init() {
m_inputaxes.clear();
m_inputbuttons.clear();
// NOTE: we're only checking for joystick_1 and rely for it to stay connected throughout.
// not exactly flexible, but for quick hack it'll do
auto const name = glfwGetJoystickName( GLFW_JOYSTICK_1 );
if( name != nullptr ) {
WriteLog( "Connected gamepad: " + std::string( name ) );
m_deviceid = GLFW_JOYSTICK_1;
}
else {
// no joystick,
WriteLog( "No gamepad detected" );
return false;
}
int count;
glfwGetJoystickAxes( m_deviceid, &count );
m_inputaxes.assign( count, { 0.0f, 0.0f, {} } );
glfwGetJoystickButtons( m_deviceid, &count );
m_inputbuttons.assign( count, { GLFW_RELEASE, -1, user_command::none } );
recall_bindings();
return true;
}
// checks state of the controls and sends issued commands
void
gamepad_input::poll() {
if( m_deviceid == -1 ) {
// if there's no gamepad we can skip the rest
return;
}
int count;
std::size_t idx = 0;
// poll button state
auto const buttons = glfwGetJoystickButtons( m_deviceid, &count );
if( count ) { // safety check in case joystick gets pulled out
for( auto &button : m_inputbuttons ) {
if( button.state != buttons[ idx ] ) {
// button pressed or released, both are important
on_button(
idx,
( buttons[ idx ] == 1 ?
GLFW_PRESS :
GLFW_RELEASE ) );
}
else {
// otherwise we only pass info about button being held down
if( button.state == GLFW_PRESS ) {
on_button(
idx,
GLFW_REPEAT );
}
}
button.state = buttons[ idx ];
++idx;
}
}
// poll axes state
idx = 0;
auto const axes = glfwGetJoystickAxes( m_deviceid, &count );
if( count ) {
// safety check in case joystick gets pulled out
for( auto &axis : m_inputaxes ) {
axis.state = axes[ idx ];
++idx;
}
}
process_axes();
}
void
gamepad_input::bind( std::vector< std::reference_wrapper<user_command> > &Targets, cParser &Input, std::unordered_map<std::string, user_command> const &Translator, std::string const Point ) {
for( auto &bindingtarget : Targets ) {
// grab command(s) associated with the input pin
auto const bindingcommandname{ Input.getToken<std::string>() };
if( true == bindingcommandname.empty() ) {
// no tokens left, may as well complain...
WriteLog( "Gamepad binding for " + Point + " didn't specify associated command(s)" );
// ...can't quit outright though, as provided references are likely to be unitialized
bindingtarget.get() = user_command::none;
continue;
}
auto const commandlookup = Translator.find( bindingcommandname );
if( commandlookup == Translator.end() ) {
WriteLog( "Gamepad binding for " + Point + " specified unknown command, \"" + bindingcommandname + "\"" );
bindingtarget.get() = user_command::none;
}
else {
bindingtarget.get() = commandlookup->second;
}
}
}
namespace fs = std::filesystem;
bool
gamepad_input::recall_bindings() {
std::string filePath = "eu07_input-gamepad.ini";
#ifdef _WIN32
if (const char *appdata = std::getenv("APPDATA"))
{
fs::path appPath = fs::path(appdata) / "MaSzyna" / "eu07_input-gamepad.ini";
if (fs::exists(appPath))
filePath = appPath.string();
}
#else
if (const char *home = std::getenv("HOME"))
{
fs::path appPath = fs::path(home) / ".config" / "MaSzyna" / "eu07_input-gamepad.ini";
if (fs::exists(appPath))
filePath = appPath.string();
}
#endif
// bindingparser tworzony zawsze, z wybran¹ œcie¿k¹
cParser bindingparser(filePath.c_str(), cParser::buffer_FILE);
if( false == bindingparser.ok() ) {
return false;
}
// build helper translation tables
std::unordered_map<std::string, user_command> nametocommandmap;
std::size_t commandid = 0;
for( auto const &description : simulation::Commands_descriptions ) {
nametocommandmap.emplace(
description.name,
static_cast<user_command>( commandid ) );
++commandid;
}
std::unordered_map<std::string, input_type> nametotypemap {
{ "3state", input_type::threestate },
{ "value", input_type::value },
{ "value_invert", input_type::value_invert } };
// NOTE: to simplify things we expect one entry per line, and whole entry in one line
while( true == bindingparser.getTokens( 1, true, "\n\r" ) ) {
std::string bindingentry;
bindingparser >> bindingentry;
cParser entryparser( bindingentry );
if( false == entryparser.getTokens( 1, true, "\n\r\t " ) ) { continue; }
std::string bindingpoint {};
entryparser >> bindingpoint;
auto const splitbindingpoint { split_string_and_number( bindingpoint ) };
if( splitbindingpoint.first == "axis" ) {
// one or more sets of: [modeIDX] input type, parameters
// [optional] modeIDX associates the set with control mode IDX
// input types:
// -- range commandname IDX; axis value is passed as paramIDX of commandname
// -- 3state commandname commandname; positive axis value issues first commandname, negative value issues second commandname
auto const axisindex { splitbindingpoint.second };
// sanity check, connected gamepad isn't guaranteed to have that many axes
if( axisindex >= m_inputaxes.size() ) { continue; }
int controlmode { -1 }; // unless stated otherwise the set will be associated with the default control mode
while( true == entryparser.getTokens( 1, true, "\n\r\t " ) ) {
std::string key {};
entryparser >> key;
// check for potential mode indicator
auto const splitkey { split_string_and_number( key ) };
if( splitkey.first == "mode" ) {
// indicate we'll be processing specified mode
controlmode = splitkey.second;
continue;
}
// if we're still here handle the original key as binding type
std::string const bindingtypename { key };
auto const typelookup = nametotypemap.find( bindingtypename );
if( typelookup == nametotypemap.end() ) {
WriteLog( "Gamepad binding for " + bindingpoint + " specified unknown control type, \"" + bindingtypename + "\"" );
}
else {
std::vector< std::reference_wrapper<user_command> > bindingtargets;
auto const bindingtype { typelookup->second };
std::get<0>( m_inputaxes[ axisindex ].bindings[ controlmode ] ) = bindingtype;
// retrieve regular commands associated with the axis and mode
switch( bindingtype ) {
case input_type::value:
case input_type::value_invert: {
bindingtargets.emplace_back( std::ref( std::get<1>( m_inputaxes[ axisindex ].bindings[ controlmode ] ) ) );
break;
}
case input_type::threestate: {
bindingtargets.emplace_back( std::ref( std::get<1>( m_inputaxes[ axisindex ].bindings[ controlmode ] ) ) );
bindingtargets.emplace_back( std::ref( std::get<2>( m_inputaxes[ axisindex ].bindings[ controlmode ] ) ) );
break;
}
default: {
break;
}
}
bind( bindingtargets, entryparser, nametocommandmap, bindingpoint );
// handle potential remaining input type-specific parameters
switch( bindingtype ) {
case input_type::value:
case input_type::value_invert: {
auto const paramidxname { entryparser.getToken<std::string>() };
auto const paramidx { (
// exceptions
paramidxname == "y" ? 1 :
paramidxname == "2" ? 1 : // human-readable param index starts with 1
// default
0 ) };
std::get<2>( m_inputaxes[ axisindex ].bindings[ controlmode ] ) = static_cast<user_command>( paramidx );
break;
}
default: {
break;
}
}
}
}
}
else if( splitbindingpoint.first == "button" ) {
auto const buttonindex { splitbindingpoint.second };
// sanity check, connected gamepad isn't guaranteed to have that many buttons
if( buttonindex >= m_inputbuttons.size() ) { continue; }
auto const bindingtype { entryparser.getToken<std::string>() };
if( bindingtype == "mode" ) {
// special case, mode selector
if( true == entryparser.getTokens( 1, true, "\n\r\t " ) ) {
entryparser >> m_inputbuttons[ buttonindex ].mode;
}
else {
WriteLog( "Gamepad binding for " + bindingpoint + " didn't specify mode index" );
}
}
else {
// regular button, single bound command
std::vector< std::reference_wrapper<user_command> > bindingtargets;
bindingtargets.emplace_back( std::ref( m_inputbuttons[ buttonindex ].binding ) );
bind( bindingtargets, entryparser, nametocommandmap, bindingpoint );
}
}
}
return true;
}
void
gamepad_input::on_button( int const Button, int const Action ) {
auto const &button { m_inputbuttons[ Button ] };
if( button.mode >= 0 ) {
switch( Action ) {
case GLFW_PRESS: {
for( auto &axis : m_inputaxes ) {
axis.accumulator = 0.0f;
}
[[fallthrough]];
}
case GLFW_REPEAT: {
m_mode = Button;
break;
}
case GLFW_RELEASE: {
if( m_mode == Button ) {
m_mode = -1;
for( auto &axis : m_inputaxes ) {
axis.accumulator = 0.0f;
}
}
break;
}
default: {
break;
}
}
}
if( button.binding != user_command::none ) {
m_relay.post(
button.binding,
0,
0,
Action,
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
0 );
}
}
void
gamepad_input::process_axes() {
input_type inputtype;
user_command boundcommand1, boundcommand2;
auto binding { std::tie( inputtype, boundcommand1, boundcommand2 ) };
// since some commands can potentially collect values from two different axes we can't post them directly
// instead, we use a small scratchpad to first put these commands together, then post them in their completed state
std::unordered_map<user_command, std::tuple< double, double, int > > commands;
// HACK: generate movement reset, it'll be eiter overriden by actual movement command, or issued if another control mode was activated
commands[ user_command::movehorizontal ] = { 0.0, 0.0, GLFW_PRESS };
for( auto &axis : m_inputaxes ) {
if( axis.bindings.empty() ) { continue; }
auto const lookup { axis.bindings.find( m_mode ) };
if( lookup == axis.bindings.end() ) { continue; }
binding = lookup->second;
switch( inputtype ) {
case input_type::threestate: {
// TODO: separate multiplier for each mode, to allow different, customizable sensitivity for each control
auto const deltatime { Timer::GetDeltaTime() * 15.0 };
if( axis.state >= 0.0f ) {
// first bound command selected
if( axis.accumulator < 0.0f ) {
// we were issuing the other command, post notification that's no longer the case
if( boundcommand2 != user_command::none ) {
m_relay.post(
boundcommand2,
0, 0,
GLFW_RELEASE,
0 );
axis.accumulator = 0.0f;
}
}
if( boundcommand1 != user_command::none ) {
if( axis.state > m_deadzone ) {
axis.accumulator += ( axis.state - m_deadzone ) / ( 1.0 - m_deadzone ) * deltatime;
// we're making sure there's always a positive charge left in the accumulator,
// to more reliably decect when the stick goes from active to dead zone, below
while( axis.accumulator > 1.0f ) {
// send commands if the accumulator(s) was filled
m_relay.post(
boundcommand1,
0, 0,
GLFW_PRESS,
0 );
axis.accumulator -= 1.0f;
}
}
else {
// if the accumulator isn't empty it's an indicator the stick moved from active to neutral zone
// indicate it with proper RELEASE command
m_relay.post(
boundcommand1,
0, 0,
GLFW_RELEASE,
0 );
axis.accumulator = 0.0f;
}
}
}
else {
// second bound command selected
if( axis.accumulator > 0.0f ) {
// we were issuing the other command, post notification that's no longer the case
if( boundcommand1 != user_command::none ) {
m_relay.post(
boundcommand1,
0, 0,
GLFW_RELEASE,
0 );
axis.accumulator = 0.0f;
}
}
if( boundcommand1 != user_command::none ) {
if( axis.state < -m_deadzone ) {
axis.accumulator += ( axis.state + m_deadzone ) / ( 1.0 - m_deadzone ) * deltatime;
// we're making sure there's always a positive charge left in the accumulator,
// to more reliably decect when the stick goes from active to dead zone, below
while( axis.accumulator < -1.0f ) {
// send commands if the accumulator(s) was filled
m_relay.post(
boundcommand2,
0, 0,
GLFW_PRESS,
0 );
axis.accumulator += 1.0f;
}
}
else {
// if the accumulator isn't empty it's an indicator the stick moved from active to neutral zone
// indicate it with proper RELEASE command
m_relay.post(
boundcommand2,
0, 0,
GLFW_RELEASE,
0 );
axis.accumulator = 0.0f;
}
}
}
break;
}
case input_type::value:
case input_type::value_invert: {
auto &command { commands[ boundcommand1 ] };
std::get<int>( command ) = GLFW_PRESS;
auto &param { (
static_cast<int>( boundcommand2 ) == 0 ? // for this type boundcommand2 stores param index
std::get<0>( command ) :
std::get<1>( command ) ) };
param = axis.state;
if( std::abs( param ) < m_deadzone ) {
param = 0.0;
}
else {
param = (
param > 0.0 ?
( param - m_deadzone ) / ( 1.0 - m_deadzone ) :
( param + m_deadzone ) / ( 1.0 - m_deadzone ) );
}
if( param != 0.0 ) {
if( inputtype == input_type::value_invert ) {
param *= -1.0;
}
}
// scale passed value according to command type
switch( boundcommand1 ) {
case user_command::viewturn: {
param *= 10.0 * ( Timer::GetDeltaRenderTime() * 60.0 );
break;
}
case user_command::movehorizontal:
case user_command::movehorizontalfast: {
// these expect value in -1:1 range
break;
}
default: {
// commands generally expect their parameter to be in 0:1 range
param = param * 0.5 + 0.5;
break;
}
}
break;
}
default: {
break;
}
}
}
// issue remaining, assembled commands
for( auto const &command : commands ) {
auto const param1 { std::get<0>( command.second ) };
auto const param2 { std::get<1>( command.second ) };
auto &lastparams { m_lastcommandparams[ command.first ] };
if( ( param1 != 0.0 ) || ( std::get<0>( lastparams ) != 0.0 )
|| ( param2 != 0.0 ) || ( std::get<1>( lastparams ) != 0.0 ) ) {
m_relay.post(
command.first,
param1,
param2,
std::get<2>( command.second ),
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
0 );
lastparams = std::tie( param1, param2 );
}
}
}
//---------------------------------------------------------------------------

95
input/gamepadinput.h Normal file
View File

@@ -0,0 +1,95 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <vector>
#include "command.h"
#include "parser.h"
class gamepad_input {
public:
// constructors
gamepad_input() = default;
// methods
// checks state of the controls and sends issued commands
bool
init();
void
poll();
private:
// types
/*
enum gamepad_button {
a,
b,
x,
y,
left_shoulder,
right_shoulder,
back,
start,
left_sticker,
right_sticker,
dpad_up,
dpad_right,
dpad_down,
dpad_left
};
enum gamepad_axes {
leftstick_x,
leftstick_y,
rightstick_x,
rightstick_y,
lefttrigger,
righttrigger
};
*/
enum class input_type {
threestate, // two commands, mapped to positive and negative axis value respectively; press and release events on state change
impulse, // one command; press event when set, release when cleared
value, // one command; press event, axis value passed as specified param (stored as second 'user_command')
value_invert // the passed value is additionally multiplied by -1
};
struct input_button {
unsigned char state; // last polled state
int mode; // associated control mode
user_command binding; // associated command
};
struct input_axis {
float state; // last polled state
float accumulator; // multipurpose helper variable
std::unordered_map< int, std::tuple< input_type, user_command, user_command > > bindings; // associated commands for respective modes
};
using inputbutton_sequence = std::vector<input_button>;
using inputaxis_sequence = std::vector<input_axis>;
// methods
bool recall_bindings();
void bind( std::vector< std::reference_wrapper<user_command> > &Targets, cParser &Input, std::unordered_map<std::string, user_command> const &Translator, std::string const Point );
void on_button( int const Button, int const Action );
void process_axes();
// members
command_relay m_relay;
inputbutton_sequence m_inputbuttons;
inputaxis_sequence m_inputaxes;
int m_deviceid{ -1 };
int m_mode{ -1 }; // currently active control mode
float m_deadzone{ 0.15f }; // TODO: allow to configure this
// double m_modeaccumulator{ 0.0 }; // used to throttle command input rate for vehicle controls
std::unordered_map< user_command, std::tuple<double, double> > m_lastcommandparams; // cached parameters for last issued command of given type
};
//---------------------------------------------------------------------------

480
input/keyboardinput.cpp Normal file
View File

@@ -0,0 +1,480 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "keyboardinput.h"
#include "Globals.h"
#include "Logs.h"
#include "parser.h"
namespace input {
std::array<char, GLFW_KEY_LAST + 1> keys { GLFW_RELEASE };
bool key_alt;
bool key_ctrl;
bool key_shift;
}
std::unordered_map<int, std::string> keyboard_input::keytonamemap =
{
{ GLFW_KEY_0, "0" },
{ GLFW_KEY_1, "1" },
{ GLFW_KEY_2, "2" },
{ GLFW_KEY_3, "3" },
{ GLFW_KEY_4, "4" },
{ GLFW_KEY_5, "5" },
{ GLFW_KEY_6, "6" },
{ GLFW_KEY_7, "7" },
{ GLFW_KEY_8, "8" },
{ GLFW_KEY_9, "9" },
{ GLFW_KEY_MINUS, "-" },
{ GLFW_KEY_EQUAL, "=" },
{ GLFW_KEY_A, "a" },
{ GLFW_KEY_B, "b" },
{ GLFW_KEY_C, "c" },
{ GLFW_KEY_D, "d" },
{ GLFW_KEY_E, "e" },
{ GLFW_KEY_F, "f" },
{ GLFW_KEY_G, "g" },
{ GLFW_KEY_H, "h" },
{ GLFW_KEY_I, "i" },
{ GLFW_KEY_J, "j" },
{ GLFW_KEY_K, "k" },
{ GLFW_KEY_L, "l" },
{ GLFW_KEY_M, "m" },
{ GLFW_KEY_N, "n" },
{ GLFW_KEY_O, "o" },
{ GLFW_KEY_P, "p" },
{ GLFW_KEY_Q, "q" },
{ GLFW_KEY_R, "r" },
{ GLFW_KEY_S, "s" },
{ GLFW_KEY_T, "t" },
{ GLFW_KEY_U, "u" },
{ GLFW_KEY_V, "v" },
{ GLFW_KEY_W, "w" },
{ GLFW_KEY_X, "x" },
{ GLFW_KEY_Y, "y" },
{ GLFW_KEY_Z, "z" },
{ GLFW_KEY_MINUS, "-" },
{ GLFW_KEY_EQUAL, "=" },
{ GLFW_KEY_BACKSPACE, "backspace" },
{ GLFW_KEY_LEFT_BRACKET, "[" },
{ GLFW_KEY_RIGHT_BRACKET, "]" },
{ GLFW_KEY_BACKSLASH, "\\" },
{ GLFW_KEY_SEMICOLON, ";" },
{ GLFW_KEY_APOSTROPHE, "'" },
{ GLFW_KEY_ENTER, "enter" },
{ GLFW_KEY_COMMA, "," },
{ GLFW_KEY_PERIOD, "." },
{ GLFW_KEY_SLASH, "/" },
{ GLFW_KEY_SPACE, "space" },
{ GLFW_KEY_PAUSE, "pause" },
{ GLFW_KEY_INSERT, "insert" },
{ GLFW_KEY_DELETE, "delete" },
{ GLFW_KEY_HOME, "home" },
{ GLFW_KEY_END, "end" },
{ GLFW_KEY_KP_DIVIDE, "num_/" },
{ GLFW_KEY_KP_MULTIPLY, "num_*" },
{ GLFW_KEY_KP_SUBTRACT, "num_-" },
{ GLFW_KEY_KP_7, "num_7" },
{ GLFW_KEY_KP_8, "num_8" },
{ GLFW_KEY_KP_9, "num_9" },
{ GLFW_KEY_KP_ADD, "num_+" },
{ GLFW_KEY_KP_4, "num_4" },
{ GLFW_KEY_KP_5, "num_5" },
{ GLFW_KEY_KP_6, "num_6" },
{ GLFW_KEY_KP_1, "num_1" },
{ GLFW_KEY_KP_2, "num_2" },
{ GLFW_KEY_KP_3, "num_3" },
{ GLFW_KEY_KP_ENTER, "num_enter" },
{ GLFW_KEY_KP_0, "num_0" },
{ GLFW_KEY_KP_DECIMAL, "num_." },
{ GLFW_KEY_F1, "f1" },
{ GLFW_KEY_F2, "f2" },
{ GLFW_KEY_F3, "f3" },
{ GLFW_KEY_F4, "f4" },
{ GLFW_KEY_F5, "f5" },
{ GLFW_KEY_F6, "f6" },
{ GLFW_KEY_F7, "f7" },
{ GLFW_KEY_F8, "f8" },
{ GLFW_KEY_F9, "f9" },
{ GLFW_KEY_F10, "f10" },
{ GLFW_KEY_F11, "f11" },
{ GLFW_KEY_F12, "f12" },
{ GLFW_KEY_TAB, "tab" },
{ GLFW_KEY_ESCAPE, "esc" },
{ GLFW_KEY_LEFT, "left" },
{ GLFW_KEY_RIGHT, "right" },
{ GLFW_KEY_UP, "up" },
{ GLFW_KEY_DOWN, "down" },
{ GLFW_KEY_PAGE_UP, "page_up" },
{ GLFW_KEY_PAGE_DOWN, "page_down" },
};
namespace fs = std::filesystem;
bool
keyboard_input::recall_bindings() {
fs::path iniPath;
std::string path = "";
#ifdef _WIN32
if (const char *appdata = std::getenv("APPDATA"))
{
iniPath = fs::path(appdata) / "MaSzyna" / "eu07_input-keyboard.ini";
}
#else
if (const char *home = std::getenv("HOME"))
{
iniPath = fs::path(home) / ".config" / "MaSzyna" / "eu07_input-keyboard.ini";
}
#endif
if (!iniPath.empty() && fs::exists(iniPath))
{
// Plik istnieje w AppData / ~/.config
path = iniPath.string().c_str();
}
else
{
// Fallback plik w folderze symulatora
path = "eu07_input-keyboard.ini";
}
cParser bindingparser(path.c_str(), cParser::buffer_FILE);
bindingparser.skipComments = false;
if( false == bindingparser.ok() ) {
return false;
}
// build helper translation tables
std::unordered_map<std::string, user_command> nametocommandmap;
std::size_t commandid = 0;
for( auto const &description : simulation::Commands_descriptions ) {
nametocommandmap.emplace(
description.name,
static_cast<user_command>( commandid ) );
++commandid;
}
std::unordered_map<std::string, int> nametokeymap;
for (const std::pair<int, std::string> &key : keytonamemap) {
nametokeymap.emplace(key.second, key.first);
}
// NOTE: to simplify things we expect one entry per line, and whole entry in one line
while( true == bindingparser.getTokens( 1, true, "\n\r" ) ) {
std::string bindingentry;
bindingparser >> bindingentry;
cParser entryparser( bindingentry );
entryparser.skipComments = false;
if( true == entryparser.getTokens( 1, true, "\n\r\t " ) ) {
std::string commandname;
entryparser >> commandname;
auto const lookup = nametocommandmap.find( commandname );
if( lookup == nametocommandmap.end() ) {
WriteLog( "Keyboard binding defined for unknown command, \"" + commandname + "\"" );
}
else {
int keycode = 0;
std::string description = "";
bool descriptionStarted = false;
while( entryparser.getTokens( 1, true, "\n\r\t " ) ) {
std::string bindingkeyname;
entryparser >> bindingkeyname;
// Parse command description, starting with "//".
// TODO: At some point, rewind this and add translation keys instead for multilingual support.
// This can't be done now as by default this would destroy all command descriptions,
// which are used by Starter.
// Do this when szczawik's Starter becomes deprecated or implements command descriptions in some other way.
if (descriptionStarted) {
if (description.size() > 0) {
description += " ";
}
description += bindingkeyname;
} else if (bindingkeyname == "//") {
descriptionStarted = true;
} else {
if( bindingkeyname == "shift" ) { keycode |= keymodifier::shift; }
else if( bindingkeyname == "ctrl" ) { keycode |= keymodifier::control; }
else if( bindingkeyname == "none" ) { keycode = 0; }
else {
// regular key, convert it to glfw key code
auto const keylookup = nametokeymap.find( bindingkeyname );
if( keylookup == nametokeymap.end() ) {
WriteLog( "Keyboard binding included unrecognized key, \"" + bindingkeyname + "\"" );
}
else {
// replace any existing binding, preserve modifiers
// (protection from cases where there's more than one key listed in the entry)
keycode = keylookup->second | ( keycode & 0xffff0000 );
}
}
}
std::tuple<int, std::string> binding{keycode, description};
m_bindingsetups.insert_or_assign(lookup->second, binding);
}
}
}
}
return true;
}
void keyboard_input::dump_bindings()
{
std::fstream stream("eu07_input-keyboard.ini",
std::ios_base::binary | std::ios_base::trunc | std::ios_base::out);
if (!stream.is_open()) {
ErrorLog("failed to save keyboard config");
return;
}
for (const std::pair<user_command, std::tuple<int, std::string>> &binding : m_bindingsetups) {
stream << simulation::Commands_descriptions[static_cast<std::size_t>(binding.first)].name << ' ';
int keycode = std::get<int>(binding.second);
auto it = keytonamemap.find(keycode & 0xFFFF);
if (it != keytonamemap.end()) {
if (keycode & keymodifier::control)
stream << "ctrl ";
if (keycode & keymodifier::shift)
stream << "shift ";
stream << it->second;
} else {
stream << "none";
}
std::string description = std::get<std::string>(binding.second);
if (description.size() > 0)
stream << " // " << description << "\r\n";
}
}
bool
keyboard_input::key( int const Key, int const Action ) {
bool modifier( false );
if( ( Key == GLFW_KEY_LEFT_SHIFT ) || ( Key == GLFW_KEY_RIGHT_SHIFT ) ) {
// update internal state, but don't bother passing these
input::key_shift =
( Action == GLFW_RELEASE ?
false :
true );
modifier = true;
// whenever shift key is used it may affect currently pressed movement keys, so check and update these
}
if( ( Key == GLFW_KEY_LEFT_CONTROL ) || ( Key == GLFW_KEY_RIGHT_CONTROL ) ) {
// update internal state, but don't bother passing these
input::key_ctrl =
( Action == GLFW_RELEASE ?
false :
true );
modifier = true;
}
if( ( Key == GLFW_KEY_LEFT_ALT ) || ( Key == GLFW_KEY_RIGHT_ALT ) ) {
// update internal state, but don't bother passing these
input::key_alt =
( Action == GLFW_RELEASE ?
false :
true );
}
if( Key == -1 ) { return false; }
// store key state
input::keys[ Key ] = Action;
if( true == is_movement_key( Key ) ) {
// if the received key was one of movement keys, it's been handled and we don't need to bother further
return true;
}
// include active modifiers for currently pressed key, except if the key is a modifier itself
auto const key =
Key
| ( modifier ? 0 : ( input::key_shift ? keymodifier::shift : 0 ) )
| ( modifier ? 0 : ( input::key_ctrl ? keymodifier::control : 0 ) );
auto const lookup = m_bindings.find( key );
if( lookup == m_bindings.end() ) {
// no binding for this key
return false;
}
// NOTE: basic keyboard controls don't have any parameters
// as we haven't yet implemented either item id system or multiplayer, the 'local' controlled vehicle and entity have temporary ids of 0
// TODO: pass correct entity id once the missing systems are in place
m_relay.post( lookup->second, 0, 0, Action, 0 );
m_command = (
Action == GLFW_RELEASE ?
user_command::none :
lookup->second );
return true;
}
int
keyboard_input::key( int const Key ) const {
return input::keys[ Key ];
}
void
keyboard_input::bind() {
m_bindings.clear();
for( auto const &bindingsetup : m_bindingsetups ) {
m_bindings[ std::get<int>(bindingsetup.second) ] = bindingsetup.first;
}
// cache movement key bindings
m_bindingscache.forward = binding( user_command::moveforward );
m_bindingscache.back = binding( user_command::moveback );
m_bindingscache.left = binding( user_command::moveleft );
m_bindingscache.right = binding( user_command::moveright );
m_bindingscache.up = binding( user_command::moveup );
m_bindingscache.down = binding( user_command::movedown );
}
int
keyboard_input::binding( user_command const Command ) const {
for( auto const &binding : m_bindings ) {
if( binding.second == Command ) {
return binding.first;
}
}
return -1;
}
bool
keyboard_input::is_movement_key( int const Key ) const {
bool const ismovementkey =
( ( Key == m_bindingscache.forward )
|| ( Key == m_bindingscache.back )
|| ( Key == m_bindingscache.left )
|| ( Key == m_bindingscache.right )
|| ( Key == m_bindingscache.up )
|| ( Key == m_bindingscache.down ) );
return ismovementkey;
}
void
keyboard_input::poll() {
glm::vec2 const movementhorizontal {
// x-axis
( Global.shiftState ? 1.f : (2.0f / 3.0f) ) *
( input::keys[ m_bindingscache.left ] != GLFW_RELEASE ? -1.f :
input::keys[ m_bindingscache.right ] != GLFW_RELEASE ? 1.f :
0.f ),
// z-axis
( Global.shiftState ? 1.f : (2.0f / 3.0f) ) *
( input::keys[ m_bindingscache.forward ] != GLFW_RELEASE ? 1.f :
input::keys[ m_bindingscache.back ] != GLFW_RELEASE ? -1.f :
0.f ) };
if( ( movementhorizontal.x != 0.f || movementhorizontal.y != 0.f )
|| ( m_movementhorizontal.x != 0.f || m_movementhorizontal.y != 0.f ) ) {
m_relay.post(
( true == Global.ctrlState ?
user_command::movehorizontalfast :
user_command::movehorizontal ),
movementhorizontal.x,
movementhorizontal.y,
GLFW_PRESS,
0 );
}
m_movementhorizontal = movementhorizontal;
float const movementvertical {
// y-axis
( Global.shiftState ? 1.f : (2.0f / 3.0f) ) *
( input::keys[ m_bindingscache.up ] != GLFW_RELEASE ? 1.f :
input::keys[ m_bindingscache.down ] != GLFW_RELEASE ? -1.f :
0.f ) };
if( ( movementvertical != 0.f )
|| ( m_movementvertical != 0.f ) ) {
m_relay.post(
( true == Global.ctrlState ?
user_command::moveverticalfast :
user_command::movevertical ),
movementvertical,
0,
GLFW_PRESS,
0 );
}
m_movementvertical = movementvertical;
}
std::unordered_map<int, std::string> keytonamemap = {
{ GLFW_KEY_0, "0" }, { GLFW_KEY_1, "1" }, { GLFW_KEY_2, "2" }, { GLFW_KEY_3, "3" }, { GLFW_KEY_4, "4" },
{ GLFW_KEY_5, "5" }, { GLFW_KEY_6, "6" }, { GLFW_KEY_7, "7" }, { GLFW_KEY_8, "8" }, { GLFW_KEY_9, "9" },
{ GLFW_KEY_MINUS, "-" }, { GLFW_KEY_EQUAL, "=" },
{ GLFW_KEY_A, "A" }, { GLFW_KEY_B, "B" }, { GLFW_KEY_C, "C" }, { GLFW_KEY_D, "D" }, { GLFW_KEY_E, "E" },
{ GLFW_KEY_F, "F" }, { GLFW_KEY_G, "G" }, { GLFW_KEY_H, "H" }, { GLFW_KEY_I, "I" }, { GLFW_KEY_J, "J" },
{ GLFW_KEY_K, "K" }, { GLFW_KEY_L, "L" }, { GLFW_KEY_M, "M" }, { GLFW_KEY_N, "N" }, { GLFW_KEY_O, "O" },
{ GLFW_KEY_P, "P" }, { GLFW_KEY_Q, "Q" }, { GLFW_KEY_R, "R" }, { GLFW_KEY_S, "S" }, { GLFW_KEY_T, "T" },
{ GLFW_KEY_U, "U" }, { GLFW_KEY_V, "V" }, { GLFW_KEY_W, "W" }, { GLFW_KEY_X, "X" }, { GLFW_KEY_Y, "Y" }, { GLFW_KEY_Z, "Z" },
{ GLFW_KEY_BACKSPACE, "BACKSPACE" },
{ GLFW_KEY_LEFT_BRACKET, "[" }, { GLFW_KEY_RIGHT_BRACKET, "]" }, { GLFW_KEY_BACKSLASH, "\\" },
{ GLFW_KEY_SEMICOLON, ";" }, { GLFW_KEY_APOSTROPHE, "'" }, { GLFW_KEY_ENTER, "ENTER" },
{ GLFW_KEY_COMMA, "<" }, { GLFW_KEY_PERIOD, ">" }, { GLFW_KEY_SLASH, "/" },
{ GLFW_KEY_SPACE, "SPACE" },
{ GLFW_KEY_PAUSE, "PAUSE" }, { GLFW_KEY_INSERT, "INSERT" }, { GLFW_KEY_DELETE, "DELETE" }, { GLFW_KEY_HOME, "HOME" }, { GLFW_KEY_END, "END" },
// numpad block
{ GLFW_KEY_KP_DIVIDE, "NUM /" }, { GLFW_KEY_KP_MULTIPLY, "NUM *" }, { GLFW_KEY_KP_SUBTRACT, "NUM -" },
{ GLFW_KEY_KP_7, "NUM 7" }, { GLFW_KEY_KP_8, "NUM 8" }, { GLFW_KEY_KP_9, "NUM 9" }, { GLFW_KEY_KP_ADD, "NUM +" },
{ GLFW_KEY_KP_4, "NUM 4" }, { GLFW_KEY_KP_5, "NUM 5" }, { GLFW_KEY_KP_6, "NUM 6" },
{ GLFW_KEY_KP_1, "NUM 1" }, { GLFW_KEY_KP_2, "NUM 2" }, { GLFW_KEY_KP_3, "NUM 3" }, { GLFW_KEY_KP_ENTER, "NUM ENTER" },
{ GLFW_KEY_KP_0, "NUM 0" }, { GLFW_KEY_KP_DECIMAL, "NUM ." }
};
std::string
keyboard_input::binding_hint( user_command const Command ) const {
if( Command == user_command::none ) { return ""; }
auto const binding { this->binding( Command ) };
if( binding == -1 ) { return ""; }
auto const lookup { keytonamemap.find( binding & 0xffff ) };
if( lookup == keytonamemap.end() ) { return ""; }
std::string hint;
if( ( binding & keymodifier::shift ) != 0 ) {
hint += "SHIFT ";
}
if( ( binding & keymodifier::control ) != 0 ) {
hint += "CTRL ";
}
hint += lookup->second;
return hint;
}
//---------------------------------------------------------------------------

115
input/keyboardinput.h Normal file
View File

@@ -0,0 +1,115 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <unordered_map>
#include <array>
#include "command.h"
namespace input {
extern std::array<char, GLFW_KEY_LAST + 1> keys;
extern bool key_alt;
extern bool key_ctrl;
extern bool key_shift;
}
namespace ui {
class keymapper_panel;
}
class keyboard_input {
friend class ui::keymapper_panel;
public:
// types
using bindingsetup_sequence = std::map<user_command, std::tuple<int, std::string>>;
enum keymodifier : int {
shift = 0x10000,
control = 0x20000
};
// constructors
keyboard_input() = default;
// destructor
virtual ~keyboard_input() = default;
// methods
virtual
bool
init() { return true; }
bool
key( int const Key, int const Action );
int
key( int const Key ) const;
void
poll();
inline
user_command const
command() const {
return m_command; }
bindingsetup_sequence&
bindings() {
return m_bindingsetups; }
int
binding( user_command const Command ) const;
std::string
binding_hint( user_command const Command ) const;
void
dump_bindings();
// members
static std::unordered_map<int, std::string> keytonamemap;
protected:
// methods
virtual
void
default_bindings() = 0;
bool
recall_bindings();
void
bind();
// members
bindingsetup_sequence m_bindingsetups;
private:
// types
using usercommand_map = std::unordered_map<int, user_command>;
struct bindings_cache {
int forward { -1 };
int back { -1 };
int left { -1 };
int right { -1 };
int up { -1 };
int down { -1 };
};
// methods
bool
is_movement_key( int const Key ) const;
// members
user_command m_command { user_command::none }; // last, if any, issued command
usercommand_map m_bindings;
command_relay m_relay;
bindings_cache m_bindingscache;
glm::vec2 m_movementhorizontal { 0.f };
float m_movementvertical { 0.f };
};
//---------------------------------------------------------------------------

429
input/messaging.cpp Normal file
View File

@@ -0,0 +1,429 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "messaging.h"
#include "Globals.h"
#include "application.h"
#include "simulation.h"
#include "simulationtime.h"
#include "Event.h"
#include "DynObj.h"
#include "Driver.h"
#include "mtable.h"
#include "Logs.h"
#ifdef _WIN32
extern "C"
{
GLFWAPI HWND glfwGetWin32Window( GLFWwindow* window );
}
#endif
namespace multiplayer {
std::uint32_t const EU07_MESSAGEHEADER { MAKE_ID4( 'E','U','0','7' ) };
void
Navigate(std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam) {
#ifdef _WIN32
// wysłanie komunikatu do sterującego
HWND h = FindWindow(ClassName.c_str(), 0); // można by to zapamiętać
if (h == 0)
h = FindWindow(0, ClassName.c_str()); // można by to zapamiętać
SendMessage(h, Msg, wParam, lParam);
#endif
}
void
OnCommandGet(multiplayer::DaneRozkaz *pRozkaz)
{ // odebranie komunikatu z serwera
if (pRozkaz->iSygn == EU07_MESSAGEHEADER )
switch (pRozkaz->iComm)
{
case 0: // odesłanie identyfikatora wersji
CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " version" + " rcvd");
WyslijString(Global.asVersion, 0); // przedsatwienie się
break;
case 1: // odesłanie identyfikatora wersji
CommLog( Now() + " " + std::to_string(pRozkaz->iComm) + " scenery" + " rcvd");
WyslijString(Global.SceneryFile, 1); // nazwa scenerii
break;
case 2: {
// event
CommLog( Now() + " " + std::to_string( pRozkaz->iComm ) + " " +
std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) + " rcvd" );
if( Global.iMultiplayer ) {
auto *event = simulation::Events.FindEvent( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) );
if( event != nullptr ) {
if( ( typeid( *event ) == typeid( multi_event ) )
|| ( typeid( *event ) == typeid( lights_event ) )
|| ( event->m_sibling != 0 ) ) {
// tylko jawne albo niejawne Multiple
command_relay relay;
relay.post(user_command::queueevent, 0.0, 0.0, GLFW_PRESS, 0, glm::vec3(0.0f), &event->name());
}
}
}
break;
}
case 3: // rozkaz dla AI
if (Global.iMultiplayer)
{
int i = int(pRozkaz->cString[8]); // długość pierwszego łańcucha (z przodu dwa floaty)
CommLog(
Now() + " " + to_string(pRozkaz->iComm) + " " +
std::string(pRozkaz->cString + 11 + i, (unsigned)(pRozkaz->cString[10 + i])) +
" rcvd");
// nazwa pojazdu jest druga
auto *vehicle = simulation::Vehicles.find( { pRozkaz->cString + 11 + i, (unsigned)pRozkaz->cString[ 10 + i ] } );
if( ( vehicle != nullptr )
&& ( vehicle->Mechanik != nullptr ) ) {
vehicle->Mechanik->PutCommand(
{ pRozkaz->cString + 9, static_cast<std::size_t>(i) },
pRozkaz->fPar[0], pRozkaz->fPar[1],
nullptr,
stopExt ); // floaty są z przodu
WriteLog("AI command: " + std::string(pRozkaz->cString + 9, i));
}
}
break;
case 4: // badanie zajętości toru
{
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " +
std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd");
auto *track = simulation::Paths.find( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) );
if( ( track != nullptr )
&& ( track->IsEmpty() ) ) {
WyslijWolny( track->name() );
}
}
break;
case 5: // ustawienie parametrów
{
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " params " + to_string(*pRozkaz->iPar) + " rcvd");
if (*pRozkaz->iPar == 0) // sprawdzenie czasu
if (*pRozkaz->iPar & 1) // ustawienie czasu
{
auto t = pRozkaz->fPar[1];
simulation::Time.data().wDay = std::floor(t); // niby nie powinno być dnia, ale...
if (Global.fMoveLight >= 0)
Global.fMoveLight = t; // trzeba by deklinację Słońca przeliczyć
simulation::Time.data().wHour = std::floor(24 * t) - 24.0 * simulation::Time.data().wDay;
simulation::Time.data().wMinute = std::floor(60 * 24 * t) - 60.0 * (24.0 * simulation::Time.data().wDay + simulation::Time.data().wHour);
simulation::Time.data().wSecond = std::floor( 60 * 60 * 24 * t ) - 60.0 * ( 60.0 * ( 24.0 * simulation::Time.data().wDay + simulation::Time.data().wHour ) + simulation::Time.data().wMinute );
}
if (*pRozkaz->iPar & 2)
{ // ustawienie flag zapauzowania
Global.iPause = pRozkaz->fPar[2]; // zakładamy, że wysyłający wie, co robi
}
}
break;
case 6: // pobranie parametrów ruchu pojazdu
if (Global.iMultiplayer) {
// Ra 2014-12: to ma działać również dla pojazdów bez obsady
CommLog(
Now() + " "
+ to_string( pRozkaz->iComm ) + " "
+ std::string{ pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) }
+ " rcvd" );
if (pRozkaz->cString[0]) {
// jeśli długość nazwy jest niezerowa szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #7
auto *vehicle = (
pRozkaz->cString[ 1 ] == '*' ?
simulation::Train->Dynamic() :
simulation::Vehicles.find( std::string{ pRozkaz->cString + 1, (unsigned)pRozkaz->cString[ 0 ] } ) );
if( vehicle != nullptr ) {
WyslijNamiary( vehicle ); // wysłanie informacji o pojeździe
}
}
else {
// dla pustego wysyłamy ramki 6 z nazwami pojazdów AI (jeśli potrzebne wszystkie, to rozpoznać np. "*")
simulation::Vehicles.DynamicList();
}
}
break;
case 8: // ponowne wysłanie informacji o zajętych odcinkach toru
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " all busy track" + " rcvd");
simulation::Paths.TrackBusyList();
break;
case 9: // ponowne wysłanie informacji o zajętych odcinkach izolowanych
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " all busy isolated" + " rcvd");
simulation::Paths.IsolatedBusyList();
break;
case 10: // badanie zajętości jednego odcinka izolowanego
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " +
std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) + " rcvd");
simulation::Paths.IsolatedBusy( std::string( pRozkaz->cString + 1, (unsigned)( pRozkaz->cString[ 0 ] ) ) );
break;
case 11: // ustawienie parametrów ruchu pojazdu
// Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0])));
break;
case 12: // skrocona ramka parametrow pojazdow AI (wszystkich!!)
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " obsadzone" + " rcvd");
WyslijObsadzone();
// Ground.IsolatedBusy(AnsiString(pRozkaz->cString+1,(unsigned)(pRozkaz->cString[0])));
break;
case 13: // ramka uszkodzenia i innych stanow pojazdu, np. wylaczenie CA, wlaczenie recznego itd.
CommLog(Now() + " " + to_string(pRozkaz->iComm) + " " +
std::string(pRozkaz->cString + 1, (unsigned)(pRozkaz->cString[0])) +
" rcvd");
if( pRozkaz->cString[ 1 ] ) // jeśli długość nazwy jest niezerowa
{ // szukamy pierwszego pojazdu o takiej nazwie i odsyłamy parametry ramką #13
auto *lookup = (
pRozkaz->cString[ 2 ] == '*' ?
simulation::Train->Dynamic() : // nazwa pojazdu użytkownika
simulation::Vehicles.find( std::string( pRozkaz->cString + 2, (unsigned)pRozkaz->cString[ 1 ] ) ) ); // nazwa pojazdu
if( lookup == nullptr ) { break; } // nothing found, nothing to do
auto *d { lookup };
while( d != nullptr ) {
d->Damage( pRozkaz->cString[ 0 ] );
d = d->Next(); // pozostałe też
}
d = lookup->Prev();
while( d != nullptr ) {
d->Damage( pRozkaz->cString[ 0 ] );
d = d->Prev(); // w drugą stronę też
}
WyslijUszkodzenia( lookup->asName, lookup->MoverParameters->EngDmgFlag ); // zwrot informacji o pojeździe
}
break;
default:
break;
}
}
void
WyslijEvent(const std::string &e, const std::string &d)
{ // Ra: jeszcze do wyczyszczenia
#ifdef _WIN32
DaneRozkaz r;
r.iSygn = EU07_MESSAGEHEADER;
r.iComm = 2; // 2 - event
size_t i = e.length(), j = d.length();
r.cString[0] = char(i);
strcpy(r.cString + 1, e.c_str()); // zakończony zerem
r.cString[i + 2] = char(j); // licznik po zerze kończącym
strcpy(r.cString + 3 + i, d.c_str()); // zakończony zerem
COPYDATASTRUCT cData;
cData.dwData = EU07_MESSAGEHEADER; // sygnatura
cData.cbData = (DWORD)(12 + i + j); // 8+dwa liczniki i dwa zera kończące
cData.lpData = &r;
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
CommLog( Now() + " " + std::to_string(r.iComm) + " " + e + " sent" );
#endif
}
void
WyslijUszkodzenia(const std::string &t, char fl)
{ // wysłanie informacji w postaci pojedynczego tekstu
#ifdef _WIN32
DaneRozkaz r;
r.iSygn = EU07_MESSAGEHEADER;
r.iComm = 13; // numer komunikatu
size_t i = t.length();
r.cString[0] = char(fl);
r.cString[1] = char(i);
strcpy(r.cString + 2, t.c_str()); // z zerem kończącym
COPYDATASTRUCT cData;
cData.dwData = EU07_MESSAGEHEADER; // sygnatura
cData.cbData = (DWORD)(11 + i); // 8+licznik i zero kończące
cData.lpData = &r;
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent");
#endif
}
void
WyslijString(const std::string &t, int n)
{ // wysłanie informacji w postaci pojedynczego tekstu
#ifdef _WIN32
DaneRozkaz r;
r.iSygn = EU07_MESSAGEHEADER;
r.iComm = n; // numer komunikatu
size_t i = t.length();
r.cString[0] = char(i);
strcpy(r.cString + 1, t.c_str()); // z zerem kończącym
COPYDATASTRUCT cData;
cData.dwData = EU07_MESSAGEHEADER; // sygnatura
cData.cbData = (DWORD)(10 + i); // 8+licznik i zero kończące
cData.lpData = &r;
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
CommLog( Now() + " " + std::to_string(r.iComm) + " " + t + " sent");
#endif
}
void
WyslijWolny(const std::string &t)
{ // Ra: jeszcze do wyczyszczenia
WyslijString(t, 4); // tor wolny
}
void
WyslijNamiary(TDynamicObject const *Vehicle)
{ // wysłanie informacji o pojeździe - (float), długość ramki będzie zwiększana w miarę potrzeby
#ifdef _WIN32
DaneRozkaz r;
r.iSygn = EU07_MESSAGEHEADER;
r.iComm = 7; // 7 - dane pojazdu
int i = 32;
size_t j = Vehicle->asName.length();
r.iPar[0] = i; // ilość danych liczbowych
r.fPar[1] = Global.fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba)
r.fPar[2] = Vehicle->MoverParameters->Loc.X; // pozycja X
r.fPar[3] = Vehicle->MoverParameters->Loc.Y; // pozycja Y
r.fPar[4] = Vehicle->MoverParameters->Loc.Z; // pozycja Z
r.fPar[5] = Vehicle->MoverParameters->V; // prędkość ruchu X
r.fPar[6] = Vehicle->MoverParameters->nrot * M_PI *
Vehicle->MoverParameters->WheelDiameter; // prędkość obrotowa kóŁ
r.fPar[7] = 0; // prędkość ruchu Z
r.fPar[8] = Vehicle->MoverParameters->AccS; // przyspieszenie X
r.fPar[9] = Vehicle->MoverParameters->AccN; // przyspieszenie Y //na razie nie
r.fPar[10] = Vehicle->MoverParameters->AccVert; // przyspieszenie Z
r.fPar[11] = Vehicle->MoverParameters->DistCounter; // przejechana odległość w km
r.fPar[12] = Vehicle->MoverParameters->PipePress; // ciśnienie w PG
r.fPar[13] = Vehicle->MoverParameters->ScndPipePress; // ciśnienie w PZ
r.fPar[14] = Vehicle->MoverParameters->BrakePress; // ciśnienie w CH
r.fPar[15] = Vehicle->MoverParameters->Compressor; // ciśnienie w ZG
r.fPar[16] = Vehicle->MoverParameters->Itot; // Prąd całkowity
r.iPar[17] = Vehicle->MoverParameters->MainCtrlPos; // Pozycja NJ
r.iPar[18] = Vehicle->MoverParameters->ScndCtrlPos; // Pozycja NB
r.iPar[19] = Vehicle->MoverParameters->MainCtrlActualPos; // Pozycja jezdna
r.iPar[20] = Vehicle->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania
r.iPar[21] = Vehicle->MoverParameters->ScndCtrlActualPos; // Pozycja bocznikowania
r.iPar[22] = Vehicle->MoverParameters->ResistorsFlag * 1
+ Vehicle->MoverParameters->ConverterFlag * 2
+ Vehicle->MoverParameters->CompressorFlag * 4
+ Vehicle->MoverParameters->Mains * 8
#ifdef EU07_USEOLDDOORCODE
+ Vehicle->MoverParameters->DoorLeftOpened * 16
+ Vehicle->MoverParameters->DoorRightOpened * 32
#else
+ ( false == Vehicle->MoverParameters->Doors.instances[side::left].is_closed ) * 16
+ ( false == Vehicle->MoverParameters->Doors.instances[side::right].is_closed ) * 32
#endif
+ Vehicle->MoverParameters->FuseFlag * 64
+ Vehicle->MoverParameters->DepartureSignal * 128;
// WriteLog("Zapisalem stare");
// WriteLog("Mam patykow "+IntToStr(t->DynamicObject->iAnimType[ANIM_PANTS]));
for (int p = 0; p < 4; p++)
{
// WriteLog("Probuje pant "+IntToStr(p));
if (p < Vehicle->iAnimType[ANIM_PANTS])
{
r.fPar[23 + p] = Vehicle->pants[p].fParamPants->PantWys; // stan pantografów 4
// WriteLog("Zapisalem pant "+IntToStr(p));
}
else
{
r.fPar[23 + p] = -2;
// WriteLog("Nie mam pant "+IntToStr(p));
}
}
// WriteLog("Zapisalem pantografy");
for (int p = 0; p < 3; p++)
r.fPar[27 + p] =
Vehicle->MoverParameters->ShowCurrent(p + 1); // amperomierze kolejnych grup
// WriteLog("zapisalem prady");
r.iPar[30] = Vehicle->MoverParameters->WarningSignal; // trabienie
r.fPar[31] = Vehicle->MoverParameters->PantographVoltage; // napiecie WN
// WriteLog("Parametry gotowe");
i <<= 2; // ilość bajtów
r.cString[i] = char(j); // na końcu nazwa, żeby jakoś zidentyfikować
strcpy(r.cString + i + 1, Vehicle->asName.c_str()); // zakończony zerem
COPYDATASTRUCT cData;
cData.dwData = EU07_MESSAGEHEADER; // sygnatura
cData.cbData = (DWORD)(10 + i + j); // 8+licznik i zero kończące
cData.lpData = &r;
// WriteLog("Ramka gotowa");
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
// WriteLog("Ramka poszla!");
CommLog( Now() + " " + std::to_string(r.iComm) + " " + Vehicle->asName + " sent");
#endif
}
void
WyslijObsadzone()
{ // wysłanie informacji o pojeździe
#ifdef _WIN32
DaneRozkaz2 r;
r.iSygn = EU07_MESSAGEHEADER;
r.iComm = 12; // kod 12
for (int i=0; i<1984; ++i) r.cString[i] = 0;
// TODO: clean this up, we shouldn't be relying on direct list access
auto &vehiclelist = simulation::Vehicles.sequence();
int i = 0;
for( auto *vehicle : vehiclelist ) {
if( vehicle->Mechanik ) {
strcpy( r.cString + 64 * i, vehicle->asName.c_str() );
r.fPar[ 16 * i + 4 ] = vehicle->GetPosition().x;
r.fPar[ 16 * i + 5 ] = vehicle->GetPosition().y;
r.fPar[ 16 * i + 6 ] = vehicle->GetPosition().z;
r.iPar[ 16 * i + 7 ] = static_cast<int>( vehicle->Mechanik->action() );
strcpy( r.cString + 64 * i + 32, vehicle->GetTrack()->RemoteIsolatedName().c_str() );
strcpy( r.cString + 64 * i + 48, vehicle->Mechanik->TrainName().c_str() );
i++;
if( i > 30 ) break;
}
}
while (i <= 30)
{
strcpy(r.cString + 64 * i, "none");
r.fPar[16 * i + 4] = 1;
r.fPar[16 * i + 5] = 2;
r.fPar[16 * i + 6] = 3;
r.iPar[16 * i + 7] = 0;
strcpy(r.cString + 64 * i + 32, "none");
strcpy(r.cString + 64 * i + 48, "none");
i++;
}
COPYDATASTRUCT cData;
cData.dwData = EU07_MESSAGEHEADER; // sygnatura
cData.cbData = 8 + 1984; // 8+licznik i zero kończące
cData.lpData = &r;
// WriteLog("Ramka gotowa");
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
CommLog( Now() + " " + std::to_string(r.iComm) + " obsadzone" + " sent");
#endif
}
void
WyslijParam(int nr, int fl)
{ // wysłanie parametrów symulacji w ramce (nr) z flagami (fl)
#ifdef _WIN32
DaneRozkaz r;
r.iSygn = EU07_MESSAGEHEADER;
r.iComm = nr; // zwykle 5
r.iPar[0] = fl; // flagi istotności kolejnych parametrów
int i = 0; // domyślnie brak danych
switch (nr)
{ // można tym przesyłać różne zestawy parametrów
case 5: // czas i pauza
r.fPar[1] = Global.fTimeAngleDeg / 360.0; // aktualny czas (1.0=doba)
r.iPar[2] = Global.iPause; // stan zapauzowania
i = 8; // dwa parametry po 4 bajty każdy
break;
}
COPYDATASTRUCT cData;
cData.dwData = EU07_MESSAGEHEADER; // sygnatura
cData.cbData = 12 + i; // 12+rozmiar danych
cData.lpData = &r;
Navigate( "TEU07SRK", WM_COPYDATA, (WPARAM)glfwGetWin32Window( Application.window() ), (LPARAM)&cData );
#endif
}
} // multiplayer
//---------------------------------------------------------------------------

53
input/messaging.h Normal file
View File

@@ -0,0 +1,53 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <string>
#include "winheaders.h"
class TDynamicObject;
namespace multiplayer {
struct DaneRozkaz { // struktura komunikacji z EU07.EXE
int iSygn; // sygnatura 'EU07'
int iComm; // rozkaz/status (kod ramki)
union {
float fPar[ 62 ];
int iPar[ 62 ];
char cString[ 248 ]; // upakowane stringi
};
};
struct DaneRozkaz2 { // struktura komunikacji z EU07.EXE
int iSygn; // sygnatura 'EU07'
int iComm; // rozkaz/status (kod ramki)
union {
float fPar[ 496 ];
int iPar[ 496 ];
char cString[ 1984 ]; // upakowane stringi
};
};
void Navigate( std::string const &ClassName, UINT Msg, WPARAM wParam, LPARAM lParam );
void OnCommandGet( multiplayer::DaneRozkaz *pRozkaz );
void WyslijEvent( const std::string &e, const std::string &d );
void WyslijString( const std::string &t, int n );
void WyslijWolny( const std::string &t );
void WyslijNamiary( TDynamicObject const *Vehicle );
void WyslijParam( int nr, int fl );
void WyslijUszkodzenia( const std::string &t, char fl );
void WyslijObsadzone(); // -> skladanie wielu pojazdow
} // multiplayer
//---------------------------------------------------------------------------

316
input/zmq_input.cpp Normal file
View File

@@ -0,0 +1,316 @@
#include "stdafx.h"
#include "zmq_input.h"
#include "Globals.h"
#include "Logs.h"
#include "simulation.h"
#include "simulationtime.h"
#include "Train.h"
zmq_input::zmq_input()
{
sock.emplace(ctx, zmq::socket_type::router);
sock->bind(Global.zmq_address);
// build helper translation tables
std::size_t commandid = 0;
for( auto const &description : simulation::Commands_descriptions ) {
nametocommandmap.emplace(
description.name,
static_cast<user_command>( commandid ) );
++commandid;
}
}
float zmq_input::unpack_float(const zmq::message_t &msg) {
if (msg.size() < 4)
return 0.0f;
uint8_t *buf = (uint8_t*)msg.data();
uint32_t v = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
return reinterpret_cast<float&>(v);
}
zmq::message_t zmq_input::pack_float(float f) {
uint32_t v = reinterpret_cast<uint32_t&>(f);
uint8_t buf[4];
buf[3] = v;
buf[2] = v >> 8;
buf[1] = v >> 16;
buf[0] = v >> 24;
return zmq::message_t(buf, 4);
}
void zmq_input::poll()
{
zmq::multipart_t multipart;
bool ok;
while ((ok = multipart.recv(*sock, ZMQ_DONTWAIT))) {
if (multipart.size() < 3)
continue;
if (multipart[0].size() != 5)
continue;
uint8_t* buf = (uint8_t*)multipart[0].data();
uint32_t peer_id = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4];
auto peer_it = peers.find(peer_id);
if (peer_it == peers.end()) {
peer_it = peers.emplace(peer_id, peer_state()).first;
peer_it->second.update_interval = 60.0f;
peer_it->second.last_update = std::chrono::high_resolution_clock::now();
}
if (multipart[1] == zmq::message_t("REG_SOPI", 8)) {
if (multipart.size() < 4)
continue;
peer_it->second.update_interval = unpack_float(multipart[2]);
peer_it->second.sopi_list.clear();
for (size_t i = 3; i < multipart.size(); i++) {
std::string chan_name((char*)multipart[i].data(), multipart[i].size());
auto chan_it = output_fields_map.find(chan_name);
if (chan_it != output_fields_map.end())
peer_it->second.sopi_list.push_back(chan_it->second);
}
}
if (multipart[1] == zmq::message_t("REG_SIPO", 8)) {
peer_it->second.sipo_list.clear();
for (size_t i = 2; i < multipart.size(); i++) {
std::string chan_name((char*)multipart[i].data(), multipart[i].size());
std::istringstream stream(chan_name);
std::string id1, id2;
std::getline(stream, id1, '/');
std::getline(stream, id2, '/');
input_type type = input_type::none;
user_command cmd1 = user_command::none, cmd2 = user_command::none;
auto cmd1_it = nametocommandmap.find(id1);
if (cmd1_it != nametocommandmap.end())
cmd1 = cmd1_it->second;
if (id2 == "" || id2 == "v")
type = input_type::value;
else if (id2 == "i")
type = input_type::impulse;
else {
type = input_type::toggle;
auto cmd2_it = nametocommandmap.find(id2);
if (cmd2_it != nametocommandmap.end())
cmd2 = cmd2_it->second;
}
if (cmd1 == user_command::none)
type = input_type::none;
peer_it->second.sipo_list.push_back(std::make_tuple(type, cmd1, cmd2, false));
}
}
if (multipart[1] == zmq::message_t("SIPO_DATA", 9)) {
if (peer_it->second.sipo_list.size() != multipart.size() - 2) {
zmq::multipart_t msg;
zmq::message_t addr;
addr.copy(multipart[0]);
msg.add(std::move(addr));
msg.addstr("UNCF_SIPO");
msg.send(*sock, ZMQ_DONTWAIT);
continue;
}
size_t i = 1;
for (auto &entry : peer_it->second.sipo_list) {
i++;
float value = unpack_float(multipart[i]);
input_type type = std::get<0>(entry);
if (type == input_type::value) {
relay.post(std::get<1>(entry), value, 0, GLFW_PRESS, 0);
continue;
}
else if (type == input_type::none)
continue;
bool state = (value > 0.5f);
bool changed = (state != std::get<3>(entry));
if (!changed)
continue;
auto const action { (
type != input_type::impulse ?
GLFW_PRESS :
( state ?
GLFW_PRESS :
GLFW_RELEASE ) ) };
auto const command { (
type != input_type::toggle ?
std::get<1>( entry ) :
( state ?
std::get<1>( entry ) :
std::get<2>( entry ) ) ) };
std::get<3>(entry) = state;
relay.post(command, 0, 0, action, 0);
}
}
}
auto now = std::chrono::high_resolution_clock::now();
for (auto peer = peers.begin(); peer != peers.end();) {
if (std::chrono::duration<float>(now - peer->second.last_update).count() < peer->second.update_interval) {
++peer;
continue;
}
peer->second.last_update = now;
if (peer->second.sopi_list.empty()) {
++peer;
continue;
}
uint8_t peerbuf[5] = { 0, (uint8_t)(peer->first >> 24), (uint8_t)(peer->first >> 16), (uint8_t)(peer->first >> 8), (uint8_t)(peer->first) };
zmq::multipart_t msg;
msg.addmem(peerbuf, sizeof(peerbuf));
msg.addstr("SOPI_DATA");
for (output_fields field : peer->second.sopi_list)
msg.add(pack_field(field));
if (!msg.send(*sock, ZMQ_DONTWAIT))
peer = peers.erase(peer);
else
++peer;
}
}
std::unordered_map<std::string, zmq_input::output_fields> zmq_input::output_fields_map = {
{ "shp", output_fields::shp },
{ "alerter", output_fields::alerter },
{ "radio_stop", output_fields::radio_stop },
{ "motor_resistors", output_fields::motor_resistors },
{ "line_breaker", output_fields::line_breaker },
{ "motor_overload", output_fields::motor_overload },
{ "motor_connectors", output_fields::motor_connectors },
{ "wheelslip", output_fields::wheelslip },
{ "converter_overload", output_fields::converter_overload },
{ "converter_off", output_fields::converter_off },
{ "compressor_overload", output_fields::compressor_overload },
{ "ventilator_overload", output_fields::ventilator_overload },
{ "motor_overload_threshold", output_fields::motor_overload_threshold },
{ "train_heating", output_fields::train_heating },
{ "cab", output_fields::cab },
{ "recorder_braking", output_fields::recorder_braking },
{ "recorder_power", output_fields::recorder_power },
{ "alerter_sound",output_fields:: alerter_sound },
{ "coupled_hv_voltage_relays", output_fields::coupled_hv_voltage_relays },
{ "velocity", output_fields::velocity },
{ "reservoir_pressure", output_fields::reservoir_pressure },
{ "pipe_pressure", output_fields::pipe_pressure },
{ "brake_pressure", output_fields::brake_pressure },
{ "hv_voltage", output_fields::hv_voltage },
{ "hv_current_1", output_fields::hv_current_1 },
{ "hv_current_2", output_fields::hv_current_2 },
{ "hv_current_3", output_fields::hv_current_3 },
{ "lv_voltage", output_fields::lv_voltage },
{ "distance", output_fields::distance },
{ "radio_channel", output_fields::radio_channel },
{ "springbrake_active", output_fields::springbrake_active },
{ "time_month_of_era", output_fields::time_month_of_era },
{ "time_minute_of_month", output_fields::time_minute_of_month },
{ "time_millisecond_of_day", output_fields::time_millisecond_of_day }
};
zmq::message_t zmq_input::pack_field(zmq_input::output_fields f) {
const SYSTEMTIME time = simulation::Time.data();
if (f == output_fields::time_month_of_era)
return pack_float((time.wYear - 1) * 12 + time.wMonth - 1);
if (f == output_fields::time_minute_of_month)
return pack_float((time.wDay - 1) * 1440 + time.wHour * 60 + time.wMinute);
if (f == output_fields::time_millisecond_of_day)
return pack_float(time.wSecond * 1000 + time.wMilliseconds);
TTrain *train = simulation::Train;
if (!train)
return pack_float(0.0f);
const TTrain::state_t state = train->get_state();
if (f == output_fields::shp)
return pack_float(state.shp);
if (f == output_fields::alerter)
return pack_float(state.alerter);
if (f == output_fields::radio_stop)
return pack_float(state.radio_stop);
if (f == output_fields::motor_resistors)
return pack_float(state.motor_resistors);
if (f == output_fields::line_breaker)
return pack_float(state.line_breaker);
if (f == output_fields::motor_overload)
return pack_float(state.motor_overload);
if (f == output_fields::motor_connectors)
return pack_float(state.motor_connectors);
if (f == output_fields::wheelslip)
return pack_float(state.wheelslip);
if (f == output_fields::converter_overload)
return pack_float(state.converter_overload);
if (f == output_fields::converter_off)
return pack_float(state.converter_off);
if (f == output_fields::compressor_overload)
return pack_float(state.compressor_overload);
if (f == output_fields::ventilator_overload)
return pack_float(state.ventilator_overload);
if (f == output_fields::motor_overload_threshold)
return pack_float(state.motor_overload_threshold);
if (f == output_fields::train_heating)
return pack_float(state.train_heating);
if (f == output_fields::cab)
return pack_float(state.cab);
if (f == output_fields::recorder_braking)
return pack_float(state.recorder_braking);
if (f == output_fields::recorder_power)
return pack_float(state.recorder_power);
if (f == output_fields::alerter_sound)
return pack_float(state.alerter_sound);
if (f == output_fields::coupled_hv_voltage_relays)
return pack_float(state.coupled_hv_voltage_relays);
if (f == output_fields::velocity)
return pack_float(state.velocity);
if (f == output_fields::reservoir_pressure)
return pack_float(state.reservoir_pressure);
if (f == output_fields::pipe_pressure)
return pack_float(state.pipe_pressure);
if (f == output_fields::brake_pressure)
return pack_float(state.brake_pressure);
if (f == output_fields::hv_voltage)
return pack_float(state.hv_voltage);
if (f == output_fields::hv_current_1)
return pack_float(state.hv_current[0]);
if (f == output_fields::hv_current_2)
return pack_float(state.hv_current[1]);
if (f == output_fields::hv_current_3)
return pack_float(state.hv_current[2]);
if (f == output_fields::lv_voltage)
return pack_float(state.lv_voltage);
if (f == output_fields::distance)
return pack_float(state.distance);
if (f == output_fields::radio_channel)
return pack_float(state.radio_channel);
if (f == output_fields::springbrake_active)
return pack_float(state.springbrake_active);
return pack_float(0.0f);
}

77
input/zmq_input.h Normal file
View File

@@ -0,0 +1,77 @@
#pragma once
#include <zmq_addon.hpp>
#include "command.h"
class zmq_input
{
enum class output_fields {
shp,
alerter,
radio_stop,
motor_resistors,
line_breaker,
motor_overload,
motor_connectors,
wheelslip,
converter_overload,
converter_off,
compressor_overload,
ventilator_overload,
motor_overload_threshold,
train_heating,
cab,
recorder_braking,
recorder_power,
alerter_sound,
coupled_hv_voltage_relays,
velocity,
reservoir_pressure,
pipe_pressure,
brake_pressure,
hv_voltage,
hv_current_1,
hv_current_2,
hv_current_3,
lv_voltage,
distance,
radio_channel,
springbrake_active,
time_month_of_era,
time_minute_of_month,
time_millisecond_of_day
};
zmq::context_t ctx;
std::optional<zmq::socket_t> sock;
enum class input_type
{
none,
toggle, // two commands, each mapped to one state; press event on state change
impulse, // one command; press event when set, release when cleared
value // one command; press event, value of specified byte passed as param1
};
struct peer_state {
float update_interval;
std::vector<output_fields> sopi_list;
std::vector<std::tuple<input_type, user_command, user_command, bool>> sipo_list;;
std::chrono::time_point<std::chrono::high_resolution_clock> last_update;
};
std::map<uint32_t, peer_state> peers;
float unpack_float(const zmq::message_t &);
zmq::message_t pack_float(float f);
zmq::message_t pack_field(output_fields f);
std::unordered_map<std::string, user_command> nametocommandmap;
static std::unordered_map<std::string, output_fields> output_fields_map;
command_relay relay;
public:
zmq_input();
void poll();
};