1 using System; 2 using System.Collections.Generic; 3 using System.Globalization; 4 using System.IO; 5 using System.Reflection; 6 using System.Windows.Forms; 7 using OpenTK.Input; 8 using OpenBveApi.Interface; 9 using Control = OpenBveApi.Interface.Control; 10 11 namespace OpenBve 12 { 13 internal static partial class Interface 14 { 15 /// <summary>The list of current in-game controls</summary> 16 internal static Control[] CurrentControls = { }; 17 18 /// <summary>Saves a control configuration to disk</summary> 19 /// <param name="FileOrNull">An absolute file path if we are exporting the controls, or a null reference to save to the default configuration location</param> 20 /// <param name="controlsToSave">The list of controls to save</param> SaveControls(string FileOrNull, Control[] controlsToSave)21 internal static void SaveControls(string FileOrNull, Control[] controlsToSave) { 22 CultureInfo Culture = CultureInfo.InvariantCulture; 23 System.Text.StringBuilder Builder = new System.Text.StringBuilder(); 24 Builder.AppendLine("; Current control configuration"); 25 Builder.AppendLine("; ============================="); 26 Builder.AppendLine("; This file was automatically generated. Please modify only if you know what you're doing."); 27 Builder.AppendLine("; This file is INCOMPATIBLE with versions older than 1.4.4."); 28 Builder.AppendLine(); 29 for (int i = 0; i < controlsToSave.Length; i++) { 30 Translations.CommandInfo Info = Translations.CommandInfos.TryGetInfo(controlsToSave[i].Command); 31 Builder.Append(Info.Name + ", "); 32 switch (controlsToSave[i].Method) { 33 case ControlMethod.Keyboard: 34 Builder.Append("keyboard, " + controlsToSave[i].Key + ", " + ((int)controlsToSave[i].Modifier).ToString(Culture) + ", " + controlsToSave[i].Option.ToString(Culture)); 35 break; 36 case ControlMethod.Joystick: 37 Builder.Append("joystick, " + controlsToSave[i].Device + ", "); 38 switch (controlsToSave[i].Component) { 39 case JoystickComponent.Axis: 40 Builder.Append("axis, " + controlsToSave[i].Element.ToString(Culture) + ", " + controlsToSave[i].Direction.ToString(Culture)); 41 break; 42 case JoystickComponent.Ball: 43 Builder.Append("ball, " + controlsToSave[i].Element.ToString(Culture) + ", " + controlsToSave[i].Direction.ToString(Culture)); 44 break; 45 case JoystickComponent.Hat: 46 Builder.Append("hat, " + controlsToSave[i].Element.ToString(Culture) + ", " + controlsToSave[i].Direction.ToString(Culture)); 47 break; 48 case JoystickComponent.Button: 49 Builder.Append("button, " + controlsToSave[i].Element.ToString(Culture)); 50 break; 51 default: 52 Builder.Append("invalid"); 53 break; 54 } 55 Builder.Append(", " + controlsToSave[i].Option.ToString(Culture)); 56 break; 57 case ControlMethod.RailDriver: 58 Builder.Append("raildriver, 0, "); 59 switch (controlsToSave[i].Component) { 60 case JoystickComponent.Axis: 61 Builder.Append("axis, " + controlsToSave[i].Element.ToString(Culture) + ", " + controlsToSave[i].Direction.ToString(Culture)); 62 break; 63 case JoystickComponent.Button: 64 Builder.Append("button, " + controlsToSave[i].Element.ToString(Culture)); 65 break; 66 default: 67 Builder.Append("invalid"); 68 break; 69 } 70 Builder.Append(", " + controlsToSave[i].Option.ToString(Culture)); 71 break; 72 } 73 Builder.Append("\n"); 74 } 75 string File; 76 if (FileOrNull == null) { 77 File = OpenBveApi.Path.CombineFile(Program.FileSystem.SettingsFolder, "1.5.0/controls.cfg"); 78 } else { 79 File = FileOrNull; 80 } 81 System.IO.File.WriteAllText(File, Builder.ToString(), new System.Text.UTF8Encoding(true)); 82 } 83 84 private static bool ControlsReset = false; 85 GetLines(Stream resourceStream)86 private static string[] GetLines(Stream resourceStream) 87 { 88 List<string> lines = new List<string>(); 89 using (StreamReader reader = new StreamReader(resourceStream)) 90 { 91 string currentLine; 92 while ((currentLine = reader.ReadLine()) != null) 93 { 94 lines.Add(currentLine); 95 } 96 } 97 return lines.ToArray(); 98 } 99 100 /// <summary>Loads the current controls from the controls.cfg file</summary> 101 /// <param name="FileOrNull">An absolute path reference to a saved controls.cfg file, or a null reference to check the default locations</param> 102 /// <param name="Controls">The current controls array</param> LoadControls(string FileOrNull, out Control[] Controls)103 internal static void LoadControls(string FileOrNull, out Control[] Controls) 104 { 105 string File; 106 string[] Lines = {}; 107 try 108 { 109 //Don't crash horribly if the embedded default controls file is missing (makefile.....) 110 Lines = GetLines(Assembly.GetExecutingAssembly().GetManifestResourceStream("OpenBve.Default.controls")); 111 } 112 catch 113 { 114 //ignored 115 } 116 117 if (FileOrNull == null) 118 { 119 File = OpenBveApi.Path.CombineFile(Program.FileSystem.SettingsFolder, "1.5.0/controls.cfg"); 120 if (!System.IO.File.Exists(File)) 121 { 122 File = OpenBveApi.Path.CombineFile(Program.FileSystem.SettingsFolder, "controls.cfg"); 123 } 124 125 if (!System.IO.File.Exists(File)) 126 { 127 //Load the default key assignments if the user settings don't exist 128 File = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Controls"), "Default.controls"); 129 if (!System.IO.File.Exists(File)) 130 { 131 MessageBox.Show(Translations.GetInterfaceString("errors_warning") + Environment.NewLine + Translations.GetInterfaceString("errors_controls_missing"), 132 Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); 133 } 134 } 135 } 136 else 137 { 138 File = FileOrNull; 139 } 140 141 Controls = new Control[256]; 142 int Length = 0; 143 CultureInfo Culture = CultureInfo.InvariantCulture; 144 if (System.IO.File.Exists(File)) 145 { 146 Lines = System.IO.File.ReadAllLines(File, new System.Text.UTF8Encoding()); 147 } 148 149 for (int i = 0; i < Lines.Length; i++) 150 { 151 Lines[i] = Lines[i].Trim(); 152 if (Lines[i].Length != 0 && !Lines[i].StartsWith(";", StringComparison.OrdinalIgnoreCase)) 153 { 154 string[] Terms = Lines[i].Split(','); 155 for (int j = 0; j < Terms.Length; j++) 156 { 157 Terms[j] = Terms[j].Trim(); 158 } 159 160 if (Terms.Length >= 2) 161 { 162 if (Length >= Controls.Length) 163 { 164 Array.Resize(ref Controls, Controls.Length << 1); 165 } 166 167 int j; 168 for (j = 0; j < Translations.CommandInfos.Length; j++) 169 { 170 if (string.Compare(Translations.CommandInfos[j].Name, Terms[0], StringComparison.OrdinalIgnoreCase) == 0) break; 171 } 172 173 if (j == Translations.CommandInfos.Length) 174 { 175 Controls[Length].Command = Translations.Command.None; 176 Controls[Length].InheritedType = Translations.CommandType.Digital; 177 Controls[Length].Method = ControlMethod.Invalid; 178 Controls[Length].Device = new Guid(); 179 Controls[Length].Component = JoystickComponent.Invalid; 180 Controls[Length].Element = -1; 181 Controls[Length].Direction = 0; 182 Controls[Length].Modifier = KeyboardModifier.None; 183 Controls[Length].Option = 0; 184 } 185 else 186 { 187 Controls[Length].Command = Translations.CommandInfos[j].Command; 188 Controls[Length].InheritedType = Translations.CommandInfos[j].Type; 189 string Method = Terms[1].ToLowerInvariant(); 190 bool Valid = false; 191 if (Method == "keyboard" & Terms.Length >= 4) 192 { 193 Key CurrentKey; 194 // ReSharper disable once NotAccessedVariable 195 int SDLTest; 196 if (int.TryParse(Terms[2], out SDLTest)) 197 { 198 //We've discovered a SDL keybinding is present, so reset the loading process with the default keyconfig & show an appropriate error message 199 if (ControlsReset == false) 200 { 201 MessageBox.Show(Translations.GetInterfaceString("errors_controls_oldversion") + Environment.NewLine + Translations.GetInterfaceString("errors_controls_reset"), Application.ProductName, 202 MessageBoxButtons.OK, MessageBoxIcon.Hand); 203 } 204 205 var DefaultControls = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Controls"), "Default keyboard assignment.controls"); 206 if (System.IO.File.Exists(DefaultControls)) 207 { 208 if (ControlsReset == false) 209 { 210 ControlsReset = true; 211 LoadControls(DefaultControls, out CurrentControls); 212 } 213 else 214 { 215 MessageBox.Show(Translations.GetInterfaceString("errors_warning") + Environment.NewLine + Translations.GetInterfaceString("errors_controls_default_oldversion"), 216 Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); 217 i = 0; 218 Lines = GetLines(Assembly.GetExecutingAssembly().GetManifestResourceStream("OpenBve.Default.controls")); 219 continue; 220 } 221 222 } 223 else 224 { 225 MessageBox.Show(Translations.GetInterfaceString("errors_warning") + Environment.NewLine + Translations.GetInterfaceString("errors_controls_default_missing"), 226 Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); 227 Controls = new Control[0]; 228 } 229 230 return; 231 } 232 233 if (Enum.TryParse(Terms[2], true, out CurrentKey)) 234 { 235 int Modifiers; 236 if (int.TryParse(Terms[3], NumberStyles.Integer, Culture, out Modifiers)) 237 { 238 Controls[Length].Method = ControlMethod.Keyboard; 239 Controls[Length].Device = new Guid(); //will create invalid all zero GUID 240 Controls[Length].Component = JoystickComponent.Invalid; 241 Controls[Length].Key = (OpenBveApi.Input.Key)CurrentKey; 242 Controls[Length].Direction = 0; 243 Controls[Length].Modifier = (KeyboardModifier) Modifiers; 244 int Option; 245 if (Terms.Length >= 5 && int.TryParse(Terms[4], NumberStyles.Integer, Culture, out Option)) 246 { 247 Controls[Length].Option = Option; 248 } 249 250 Valid = true; 251 } 252 } 253 } 254 255 256 else if (Method == "joystick" & Terms.Length >= 4) 257 { 258 int oldDevice; 259 Guid Device = new Guid(); 260 if (int.TryParse(Terms[2], NumberStyles.Integer, Culture, out oldDevice)) 261 { 262 Device = Joystick.GetGuid(oldDevice); 263 } 264 265 if (Device != new Guid() || Guid.TryParse(Terms[2], out Device)) 266 { 267 string Component = Terms[3].ToLowerInvariant(); 268 if (Component == "axis" & Terms.Length >= 6) 269 { 270 int CurrentAxis; 271 if (Int32.TryParse(Terms[4], out CurrentAxis)) 272 { 273 int Direction; 274 if (int.TryParse(Terms[5], NumberStyles.Integer, Culture, out Direction)) 275 { 276 277 Controls[Length].Method = ControlMethod.Joystick; 278 Controls[Length].Device = Device; 279 Controls[Length].Component = JoystickComponent.Axis; 280 Controls[Length].Element = CurrentAxis; 281 Controls[Length].Direction = Direction; 282 Controls[Length].Modifier = KeyboardModifier.None; 283 int Option; 284 if (Terms.Length >= 7 && int.TryParse(Terms[6], NumberStyles.Integer, Culture, out Option)) 285 { 286 Controls[Length].Option = Option; 287 } 288 289 Valid = true; 290 } 291 } 292 } 293 else if (Component == "hat" & Terms.Length >= 6) 294 { 295 int CurrentHat; 296 if (Int32.TryParse(Terms[4], out CurrentHat)) 297 { 298 int HatDirection; 299 if (Int32.TryParse(Terms[5], out HatDirection)) 300 { 301 Controls[Length].Method = ControlMethod.Joystick; 302 Controls[Length].Device = Device; 303 Controls[Length].Component = JoystickComponent.Hat; 304 Controls[Length].Element = CurrentHat; 305 Controls[Length].Direction = HatDirection; 306 Controls[Length].Modifier = KeyboardModifier.None; 307 int Option; 308 if (Terms.Length >= 7 && int.TryParse(Terms[6], NumberStyles.Integer, Culture, out Option)) 309 { 310 Controls[Length].Option = Option; 311 } 312 313 Valid = true; 314 } 315 316 } 317 } 318 else if (Component == "button" & Terms.Length >= 5) 319 { 320 int CurrentButton; 321 if (Int32.TryParse(Terms[4], out CurrentButton)) 322 { 323 Controls[Length].Method = ControlMethod.Joystick; 324 Controls[Length].Device = Device; 325 Controls[Length].Component = JoystickComponent.Button; 326 Controls[Length].Element = CurrentButton; 327 Controls[Length].Direction = 0; 328 Controls[Length].Modifier = KeyboardModifier.None; 329 int Option; 330 if (Terms.Length >= 6 && int.TryParse(Terms[5], NumberStyles.Integer, Culture, out Option)) 331 { 332 Controls[Length].Option = Option; 333 } 334 335 Valid = true; 336 } 337 } 338 339 } 340 } 341 else if (Method == "raildriver" & Terms.Length >= 4) 342 { 343 int oldDevice; 344 Guid Device = new Guid(); 345 if (int.TryParse(Terms[2], NumberStyles.Integer, Culture, out oldDevice)) 346 { 347 Device = Joystick.GetGuid(oldDevice); 348 } 349 350 if (Device != new Guid() || Guid.TryParse(Terms[2], out Device)) 351 { 352 string Component = Terms[3].ToLowerInvariant(); 353 if (Component == "axis" & Terms.Length >= 6) 354 { 355 int CurrentAxis; 356 if (Int32.TryParse(Terms[4], out CurrentAxis)) 357 { 358 int Direction; 359 if (int.TryParse(Terms[5], NumberStyles.Integer, Culture, out Direction)) 360 { 361 362 Controls[Length].Method = ControlMethod.RailDriver; 363 Controls[Length].Device = Device; 364 Controls[Length].Component = JoystickComponent.Axis; 365 Controls[Length].Element = CurrentAxis; 366 Controls[Length].Direction = Direction; 367 Controls[Length].Modifier = KeyboardModifier.None; 368 int Option; 369 if (Terms.Length >= 7 && int.TryParse(Terms[6], NumberStyles.Integer, Culture, out Option)) 370 { 371 Controls[Length].Option = Option; 372 } 373 374 Valid = true; 375 } 376 } 377 } 378 else if (Component == "button" & Terms.Length >= 5) 379 { 380 int CurrentButton; 381 if (Int32.TryParse(Terms[4], out CurrentButton)) 382 { 383 Controls[Length].Method = ControlMethod.RailDriver; 384 Controls[Length].Device = Device; 385 Controls[Length].Component = JoystickComponent.Button; 386 Controls[Length].Element = CurrentButton; 387 Controls[Length].Direction = 0; 388 Controls[Length].Modifier = KeyboardModifier.None; 389 int Option; 390 if (Terms.Length >= 6 && int.TryParse(Terms[5], NumberStyles.Integer, Culture, out Option)) 391 { 392 Controls[Length].Option = Option; 393 } 394 395 Valid = true; 396 } 397 } 398 399 } 400 } 401 402 if (!Valid) 403 { 404 Controls[Length].Method = ControlMethod.Invalid; 405 Controls[Length].Device = new Guid(); //Invalid all zero GUID 406 Controls[Length].Component = JoystickComponent.Invalid; 407 Controls[Length].Element = -1; 408 Controls[Length].Direction = 0; 409 Controls[Length].Modifier = KeyboardModifier.None; 410 Controls[Length].Option = 0; 411 } 412 } 413 414 Length++; 415 } 416 } 417 } 418 Array.Resize(ref Controls, Length); 419 } 420 421 422 /// <summary>Adds an array of controls to an existing control array</summary> 423 /// <param name="Base">The base control array</param> 424 /// <param name="Add">The new controls to add</param> AddControls(ref Control[] Base, Control[] Add)425 internal static void AddControls(ref Control[] Base, Control[] Add) { 426 for (int i = 0; i < Add.Length; i++) { 427 int j; 428 for (j = 0; j < Base.Length; j++) { 429 if (Add[i].Command == Base[j].Command) break; 430 } 431 if (j == Base.Length) { 432 Array.Resize(ref Base, Base.Length + 1); 433 Base[Base.Length - 1] = Add[i]; 434 } 435 } 436 } 437 } 438 } 439