1 #region Copyright & License Information
2 /*
3  * Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4  * This file is part of OpenRA, which is free software. It is made
5  * available to you under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, either version 3 of
7  * the License, or (at your option) any later version. For more
8  * information, see COPYING.
9  */
10 #endregion
11 
12 using System;
13 using System.Collections.Generic;
14 using OpenRA.FileSystem;
15 
16 namespace OpenRA
17 {
18 	public sealed class HotkeyManager
19 	{
20 		readonly Dictionary<string, Hotkey> settings;
21 		readonly Dictionary<string, HotkeyDefinition> definitions = new Dictionary<string, HotkeyDefinition>();
22 		readonly Dictionary<string, Hotkey> keys = new Dictionary<string, Hotkey>();
23 
HotkeyManager(IReadOnlyFileSystem fileSystem, Dictionary<string, Hotkey> settings, Manifest manifest)24 		public HotkeyManager(IReadOnlyFileSystem fileSystem, Dictionary<string, Hotkey> settings, Manifest manifest)
25 		{
26 			this.settings = settings;
27 
28 			var keyDefinitions = MiniYaml.Load(fileSystem, manifest.Hotkeys, null);
29 			foreach (var kd in keyDefinitions)
30 			{
31 				var definition = new HotkeyDefinition(kd.Key, kd.Value);
32 				definitions[kd.Key] = definition;
33 				keys[kd.Key] = definition.Default;
34 			}
35 
36 			foreach (var kv in settings)
37 			{
38 				if (definitions.ContainsKey(kv.Key))
39 					keys[kv.Key] = kv.Value;
40 			}
41 
42 			foreach (var hd in definitions)
43 				hd.Value.HasDuplicates = GetFirstDuplicate(hd.Value.Name, this[hd.Value.Name].GetValue(), hd.Value) != null;
44 		}
45 
GetHotkeyReference(string name)46 		internal Func<Hotkey> GetHotkeyReference(string name)
47 		{
48 			// Is this a mod-defined hotkey?
49 			if (keys.ContainsKey(name))
50 				return () => keys[name];
51 
52 			// Try and parse as a hardcoded definition
53 			Hotkey key;
54 			if (!Hotkey.TryParse(name, out key))
55 				key = Hotkey.Invalid;
56 
57 			return () => key;
58 		}
59 
Set(string name, Hotkey value)60 		public void Set(string name, Hotkey value)
61 		{
62 			HotkeyDefinition definition;
63 			if (!definitions.TryGetValue(name, out definition))
64 				return;
65 
66 			keys[name] = value;
67 			if (value != definition.Default)
68 				settings[name] = value;
69 			else
70 				settings.Remove(name);
71 
72 			var hadDuplicates = definition.HasDuplicates;
73 			definition.HasDuplicates = GetFirstDuplicate(definition.Name, this[definition.Name].GetValue(), definition) != null;
74 
75 			if (hadDuplicates || definition.HasDuplicates)
76 			{
77 				foreach (var hd in definitions)
78 				{
79 					if (hd.Value == definition)
80 						continue;
81 
82 					hd.Value.HasDuplicates = GetFirstDuplicate(hd.Value.Name, this[hd.Value.Name].GetValue(), hd.Value) != null;
83 				}
84 			}
85 		}
86 
GetFirstDuplicate(string name, Hotkey value, HotkeyDefinition definition)87 		public HotkeyDefinition GetFirstDuplicate(string name, Hotkey value, HotkeyDefinition definition)
88 		{
89 			foreach (var kv in keys)
90 			{
91 				if (kv.Key == name)
92 					continue;
93 
94 				if (kv.Value == value && definitions[kv.Key].Types.Overlaps(definition.Types))
95 					return definitions[kv.Key];
96 			}
97 
98 			return null;
99 		}
100 
101 		public HotkeyReference this[string name]
102 		{
103 			get
104 			{
105 				return new HotkeyReference(GetHotkeyReference(name));
106 			}
107 		}
108 
109 		public IEnumerable<HotkeyDefinition> Definitions { get { return definitions.Values; } }
110 	}
111 }
112