using Firebird2D.EventPipelines; using SFML.System; using SFML.Window; using System.Runtime.CompilerServices; using System.Text.Json; namespace Firebird2D.KeyMapping { public class KeyMapper { private EventBus eventBus; private Dictionary inputEvents = []; private Dictionary eventTypes = []; private Dictionary inputMapping = []; private Dictionary cachedPipelines = []; public KeyMapper(EventBus eventBus) { if (eventBus == null) throw new NullReferenceException(nameof(eventBus)); this.eventBus = eventBus; } public void RegisterEvent(string EventName, EventHandler handler, FirebirdEvent eventNumber) where T : EventArgs { if (inputEvents.ContainsKey(EventName)) throw new ArgumentException($"Event {EventName} exist Already."); inputEvents.Add(EventName, handler); eventTypes.Add(EventName, typeof(T)); Map(EventName, eventNumber); } public void Map(string EventName, FirebirdEvent eventNumber) { if (inputMapping.ContainsKey(EventName)) { RemoveMapping(EventName); inputMapping[EventName] = eventNumber; AjustPipeline(EventName, eventNumber); } else { inputMapping.Add(EventName, eventNumber); AjustPipeline(EventName, eventNumber); } } private void RemoveMapping(string EventName) { if (!inputMapping.TryGetValue(EventName, out var firebirdEvent)) return; if (!eventTypes.TryGetValue(EventName, out var type)) return; I_Pipeline? pipeline = eventBus.GetPipeline(firebirdEvent, type); if (pipeline != null) { pipeline.Unsubscribe(inputEvents[EventName]); if (pipeline.IsEventEmpty) { eventBus.DestroyPipeline(firebirdEvent, this); cachedPipelines.Remove(firebirdEvent); } } inputMapping.Remove(EventName); } private void AjustPipeline(string EventName, FirebirdEvent eventNumber) { if (!eventTypes.TryGetValue(EventName, out var type)) return; I_Pipeline pipeline = eventBus.GetOrBuildPipeline(eventNumber, type, this); pipeline.Subscribe(inputEvents[EventName]); } public void SaveMapping(string Path) { string json = JsonSerializer.Serialize(inputMapping); File.WriteAllText(Path, json); } public void LoadMapping(string Path) { string json = File.ReadAllText(Path); Dictionary? keyValuePairs = JsonSerializer.Deserialize>(json); if (keyValuePairs == null) throw new FileLoadException("Unable to deserialize Inputmapping"); cachedPipelines.Clear(); foreach (var kvp in inputMapping) { RemoveMapping(kvp.Key); } inputMapping = keyValuePairs; foreach (var kvp in inputMapping) { if (inputEvents.ContainsKey(kvp.Key)) { AjustPipeline(kvp.Key, kvp.Value); } } } public void InvalidatePipelineCache(FirebirdEvent fbEvent) { cachedPipelines.Remove(fbEvent); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private Pipeline? GetOrCachePipeline(FirebirdEvent fbEvent) where T : EventArgs { if (cachedPipelines.TryGetValue(fbEvent, out var pipelineObj) && pipelineObj is Pipeline cached) return cached; var pipeline = eventBus?.GetPipeline(fbEvent, typeof(T)) as Pipeline; if (pipeline != null) cachedPipelines[fbEvent] = pipeline; return pipeline; } public void HandleKeyboardInput(KeyEvent key) { var pipeline = GetOrCachePipeline((FirebirdEvent)key.Code); pipeline?.SendEvent(this, new KeyEventArgs(key)); } public void HandleMouseInput(MouseButtonEvent button) { var pipeline = GetOrCachePipeline((FirebirdEvent)(button.Button + 101)); pipeline?.SendEvent(this, new MouseButtonEventArgs(button)); } public void HandleJoystickButtonInput(JoystickButtonEvent joystickButton) { var pipeline = GetOrCachePipeline(FirebirdEvent.JoystickButton); pipeline?.SendEvent(this, new JoystickButtonEventArgs(joystickButton)); } public void HandleMouseMovement(MouseMoveEvent mouseMove) { var pipeline = GetOrCachePipeline(FirebirdEvent.MouseMove); pipeline?.SendEvent(this, new MouseMoveEventArgs(mouseMove)); } public void HandleJoytickMove(JoystickMoveEvent joystickMove) { var pipeline = GetOrCachePipeline(FirebirdEvent.JoystickMove); pipeline?.SendEvent(this, new JoystickMoveEventArgs(joystickMove)); } } }