Browse Source

Keyboard filter

Equbuxu 3 years ago
parent
commit
556a84245e

+ 109 - 0
src/PixiEditor/Models/Controllers/KeyboardInputFilter.cs

@@ -0,0 +1,109 @@
+using System.Windows.Input;
+using PixiEditor.Models.Events;
+
+namespace PixiEditor.Models.Controllers;
+#nullable enable
+internal class KeyboardInputFilter
+{
+    /// <summary> Works like a regular keydown event, but filtered </summary>
+    public EventHandler<FilteredKeyEventArgs>? OnAnyKeyDown;
+
+    /// <summary> Works like a regular keydown event, but filtered </summary>
+    public EventHandler<FilteredKeyEventArgs>? OnAnyKeyUp;
+
+    /// <summary> Ignores duplicate modifier keys </summary>
+    public EventHandler<FilteredKeyEventArgs>? OnConvertedKeyDown;
+
+    /// <summary> Ignores duplicate modifier keys </summary>
+    public EventHandler<FilteredKeyEventArgs>? OnConvertedKeyUp;
+
+    private Dictionary<Key, KeyStates> keyboardState = new();
+    private Dictionary<Key, KeyStates> converterdKeyboardState = new();
+
+    private static bool UpdateKeyState(Key key, KeyStates state, Dictionary<Key, KeyStates> keyboardState)
+    {
+        if (!keyboardState.ContainsKey(key))
+        {
+            keyboardState.Add(key, state);
+            return true;
+        }
+        bool result = keyboardState[key] != state;
+        keyboardState[key] = state;
+        return result;
+    }
+
+    private Key ConvertRightKeys(Key key)
+    {
+        if (key == Key.RightAlt)
+            return Key.LeftAlt;
+        if (key == Key.RightCtrl)
+            return Key.LeftCtrl;
+        if (key == Key.RightShift)
+            return Key.LeftShift;
+        return key;
+    }
+
+    public void DeactivatedInlet(object? sender, EventArgs e)
+    {
+        foreach (var (key, state) in keyboardState)
+        {
+            if (state != KeyStates.Down)
+                continue;
+
+            UpdateKeyState(key, KeyStates.None, keyboardState);
+            Key convKey = ConvertRightKeys(key);
+            bool raiseConverted = UpdateKeyState(convKey, KeyStates.None, converterdKeyboardState);
+
+            var (shift, ctrl, alt) = GetModifierStates();
+            OnAnyKeyUp?.Invoke(this, new FilteredKeyEventArgs(key, key, KeyStates.None, false, shift, ctrl, alt));
+            if (raiseConverted)
+                OnConvertedKeyUp?.Invoke(this, new FilteredKeyEventArgs(key, key, KeyStates.None, false, shift, ctrl, alt));
+        }
+    }
+
+    private (bool shift, bool ctrl, bool alt) GetModifierStates()
+    {
+        bool shift = converterdKeyboardState.TryGetValue(Key.LeftShift, out KeyStates shiftKey) ? shiftKey == KeyStates.Down : false;
+        bool ctrl = converterdKeyboardState.TryGetValue(Key.LeftCtrl, out KeyStates ctrlKey) ? ctrlKey == KeyStates.Down : false;
+        bool alt = converterdKeyboardState.TryGetValue(Key.LeftAlt, out KeyStates altKey) ? altKey == KeyStates.Down : false;
+        return (shift, ctrl, alt);
+    }
+
+    public void KeyDownInlet(KeyEventArgs args)
+    {
+        Key key = args.Key;
+        if (key == Key.System)
+            key = args.SystemKey;
+
+        if (!UpdateKeyState(key, KeyStates.Down, keyboardState))
+            return;
+
+        key = ConvertRightKeys(key);
+
+        bool raiseConverted = UpdateKeyState(key, KeyStates.Down, converterdKeyboardState);
+
+        var (shift, ctrl, alt) = GetModifierStates();
+        OnAnyKeyDown?.Invoke(this, new FilteredKeyEventArgs(key, key, KeyStates.Down, args.IsRepeat, shift, ctrl, alt));
+        if (raiseConverted)
+            OnConvertedKeyDown?.Invoke(this, new FilteredKeyEventArgs(key, key, KeyStates.Down, args.IsRepeat, shift, ctrl, alt));
+    }
+
+    public void KeyUpInlet(KeyEventArgs args)
+    {
+        Key key = args.Key;
+        if (key == Key.System)
+            key = args.SystemKey;
+
+        if (!UpdateKeyState(key, KeyStates.None, keyboardState))
+            return;
+
+        key = ConvertRightKeys(key);
+
+        bool raiseConverted = UpdateKeyState(key, KeyStates.None, converterdKeyboardState);
+
+        var (shift, ctrl, alt) = GetModifierStates();
+        OnAnyKeyUp?.Invoke(this, new FilteredKeyEventArgs(key, key, KeyStates.None, args.IsRepeat, shift, ctrl, alt));
+        if (raiseConverted)
+            OnConvertedKeyUp?.Invoke(this, new FilteredKeyEventArgs(key, key, KeyStates.None, args.IsRepeat, shift, ctrl, alt));
+    }
+}

+ 14 - 7
src/PixiEditor/Models/Controllers/MouseInputFilter.cs

@@ -4,7 +4,7 @@ using ChunkyImageLib.DataHolders;
 using PixiEditor.Models.Events;
 
 namespace PixiEditor.Models.Controllers;
-
+#nullable enable
 internal class MouseInputFilter
 {
     public EventHandler<MouseOnCanvasEventArgs> OnMouseDown;
@@ -19,8 +19,8 @@ internal class MouseInputFilter
         [MouseButton.Middle] = MouseButtonState.Released,
     };
 
-    public void MouseDown(object args) => MouseDown((MouseOnCanvasEventArgs)args);
-    public void MouseDown(MouseOnCanvasEventArgs args)
+    public void MouseDownInlet(object args) => MouseDownInlet((MouseOnCanvasEventArgs)args);
+    public void MouseDownInlet(MouseOnCanvasEventArgs args)
     {
         var button = args.Button;
 
@@ -33,11 +33,11 @@ internal class MouseInputFilter
         OnMouseDown?.Invoke(this, args);
     }
 
-    public void MouseMove(object args) => OnMouseMove?.Invoke(this, (VecD)args);
+    public void MouseMoveInlet(object args) => OnMouseMove?.Invoke(this, (VecD)args);
 
-    public void MouseUp(object args) => MouseUp((MouseButton)args);
-    public void MouseUp(object sender, Point p, MouseButton button) => MouseUp(button);
-    public void MouseUp(MouseButton button)
+    public void MouseUpInlet(object args) => MouseUpInlet((MouseButton)args);
+    public void MouseUpInlet(object? sender, Point p, MouseButton button) => MouseUpInlet(button);
+    public void MouseUpInlet(MouseButton button)
     {
         if (button is MouseButton.XButton1 or MouseButton.XButton2)
             return;
@@ -47,4 +47,11 @@ internal class MouseInputFilter
 
         OnMouseUp?.Invoke(this, button);
     }
+
+    public void DeactivatedInlet(object? sender, EventArgs e)
+    {
+        MouseUpInlet(MouseButton.Left);
+        MouseUpInlet(MouseButton.Middle);
+        MouseUpInlet(MouseButton.Right);
+    }
 }

+ 12 - 25
src/PixiEditor/Models/DocumentModels/ChangeExecutionController.cs

@@ -60,30 +60,17 @@ internal class ChangeExecutionController
         return true;
     }
 
-    public void OnKeyDown(Key key)
+    public void ConvertedKeyDownInlet(Key key)
     {
-        key = ConvertRightKeys(key);
-        currentSession?.OnKeyDown(key);
+        currentSession?.OnConvertedKeyDown(key);
     }
 
-    public void OnKeyUp(Key key)
+    public void ConvertedKeyUpInlet(Key key)
     {
-        key = ConvertRightKeys(key);
-        currentSession?.OnKeyUp(key);
+        currentSession?.OnConvertedKeyUp(key);
     }
 
-    private Key ConvertRightKeys(Key key)
-    {
-        if (key == Key.RightAlt)
-            return Key.LeftAlt;
-        if (key == Key.RightCtrl)
-            return Key.LeftCtrl;
-        if (key == Key.RightShift)
-            return Key.LeftShift;
-        return key;
-    }
-
-    public void OnMouseMove(VecD newCanvasPos)
+    public void MouseMoveInlet(VecD newCanvasPos)
     {
         //update internal state
         VecI newPixelPos = (VecI)newCanvasPos.Floor();
@@ -104,15 +91,15 @@ internal class ChangeExecutionController
         }
     }
 
-    public void OnOpacitySliderDragStarted() => currentSession?.OnOpacitySliderDragStarted();
-    public void OnOpacitySliderDragged(float newValue)
+    public void OpacitySliderDragStartedInlet() => currentSession?.OnOpacitySliderDragStarted();
+    public void OpacitySliderDraggedInlet(float newValue)
     {
         LastOpacityValue = newValue;
         currentSession?.OnOpacitySliderDragged(newValue);
     }
-    public void OnOpacitySliderDragEnded() => currentSession?.OnOpacitySliderDragEnded();
+    public void OpacitySliderDragEndedInlet() => currentSession?.OnOpacitySliderDragEnded();
 
-    public void OnLeftMouseButtonDown(VecD canvasPos)
+    public void LeftMouseButtonDownInlet(VecD canvasPos)
     {
         //update internal state
         LeftMouseState = MouseButtonState.Pressed;
@@ -121,7 +108,7 @@ internal class ChangeExecutionController
         currentSession?.OnLeftMouseButtonDown(canvasPos);
     }
 
-    public void OnLeftMouseButtonUp()
+    public void LeftMouseButtonUpInlet()
     {
         //update internal state
         LeftMouseState = MouseButtonState.Released;
@@ -130,11 +117,11 @@ internal class ChangeExecutionController
         currentSession?.OnLeftMouseButtonUp();
     }
 
-    public void OnTransformMoved(ShapeCorners corners)
+    public void TransformMovedInlet(ShapeCorners corners)
     {
         LastTransformState = corners;
         currentSession?.OnTransformMoved(corners);
     }
 
-    public void OnTransformApplied() => currentSession?.OnTransformApplied();
+    public void TransformAppliedInlet() => currentSession?.OnTransformApplied();
 }

+ 13 - 15
src/PixiEditor/Models/DocumentModels/Public/DocumentEventsModule.cs

@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Input;
+using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
@@ -19,18 +14,21 @@ internal class DocumentEventsModule
         Internals = internals;
     }
 
-    public void OnKeyDown(Key args) => Internals.ChangeController.OnKeyDown(args);
-    public void OnKeyUp(Key args) => Internals.ChangeController.OnKeyUp(args);
+    public void OnKeyDown(Key args) { }
+    public void OnKeyUp(Key args) { }
 
-    public void OnCanvasLeftMouseButtonDown(VecD pos) => Internals.ChangeController.OnLeftMouseButtonDown(pos);
+    public void OnConvertedKeyDown(Key args) => Internals.ChangeController.ConvertedKeyDownInlet(args);
+    public void OnConvertedKeyUp(Key args) => Internals.ChangeController.ConvertedKeyUpInlet(args);
+
+    public void OnCanvasLeftMouseButtonDown(VecD pos) => Internals.ChangeController.LeftMouseButtonDownInlet(pos);
     public void OnCanvasMouseMove(VecD newPos)
     {
         Document.CoordinatesString = $"X: {(int)newPos.X} Y: {(int)newPos.Y}";
-        Internals.ChangeController.OnMouseMove(newPos);
+        Internals.ChangeController.MouseMoveInlet(newPos);
     }
-    public void OnCanvasLeftMouseButtonUp() => Internals.ChangeController.OnLeftMouseButtonUp();
-    public void OnOpacitySliderDragStarted() => Internals.ChangeController.OnOpacitySliderDragStarted();
-    public void OnOpacitySliderDragged(float newValue) => Internals.ChangeController.OnOpacitySliderDragged(newValue);
-    public void OnOpacitySliderDragEnded() => Internals.ChangeController.OnOpacitySliderDragEnded();
-    public void OnApplyTransform() => Internals.ChangeController.OnTransformApplied();
+    public void OnCanvasLeftMouseButtonUp() => Internals.ChangeController.LeftMouseButtonUpInlet();
+    public void OnOpacitySliderDragStarted() => Internals.ChangeController.OpacitySliderDragStartedInlet();
+    public void OnOpacitySliderDragged(float newValue) => Internals.ChangeController.OpacitySliderDraggedInlet(newValue);
+    public void OnOpacitySliderDragEnded() => Internals.ChangeController.OpacitySliderDragEndedInlet();
+    public void OnApplyTransform() => Internals.ChangeController.TransformAppliedInlet();
 }

+ 2 - 2
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/UpdateableChangeExecutor.cs

@@ -35,8 +35,8 @@ internal abstract class UpdateableChangeExecutor
     public virtual void OnOpacitySliderDragStarted() { }
     public virtual void OnOpacitySliderDragged(float newValue) { }
     public virtual void OnOpacitySliderDragEnded() { }
-    public virtual void OnKeyDown(Key key) { }
-    public virtual void OnKeyUp(Key key) { }
+    public virtual void OnConvertedKeyDown(Key key) { }
+    public virtual void OnConvertedKeyUp(Key key) { }
     public virtual void OnTransformMoved(ShapeCorners corners) { }
     public virtual void OnTransformApplied() { }
 }

+ 33 - 0
src/PixiEditor/Models/Events/FilteredKeyEventArgs.cs

@@ -0,0 +1,33 @@
+using System.Windows.Input;
+
+namespace PixiEditor.Models.Events;
+#nullable enable
+internal class FilteredKeyEventArgs : EventArgs
+{
+    public FilteredKeyEventArgs(
+        Key unfilteredKey, Key key, KeyStates state, bool IsRepeat, bool isShiftDown, bool isCtrlDown, bool isAltDown)
+    {
+        UnfilteredKey = unfilteredKey;
+        Key = key;
+        State = state;
+        this.IsRepeat = IsRepeat;
+
+        ModifierKeys modifiers = ModifierKeys.None;
+        if (isShiftDown)
+            modifiers |= ModifierKeys.Shift;
+        if (isCtrlDown)
+            modifiers |= ModifierKeys.Control;
+        if (isAltDown)
+            modifiers |= ModifierKeys.Alt;
+        Modifiers = modifiers;
+    }
+
+    public ModifierKeys Modifiers { get; }
+    public Key UnfilteredKey { get; }
+    public Key Key { get; }
+    public KeyStates State { get; }
+    public bool IsRepeat { get; }
+    public bool IsShiftDown => (Modifiers & ModifierKeys.Shift) != 0;
+    public bool IsCtrlDown => (Modifiers & ModifierKeys.Control) != 0;
+    public bool IsAltDown => (Modifiers & ModifierKeys.Alt) != 0;
+}

+ 1 - 7
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs

@@ -1,12 +1,10 @@
 using System.IO;
-using System.Windows.Input;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
 using Models.DocumentModels.Public;
-using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.ChangeableDocument.Rendering;
@@ -15,10 +13,6 @@ using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels.Public;
-using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
-using PixiEditor.Models.DocumentPassthroughActions;
-using PixiEditor.Models.Enums;
-using PixiEditor.Models.Position;
 
 namespace PixiEditor.ViewModels.SubViewModels.Document;
 
@@ -158,7 +152,7 @@ internal class DocumentViewModel : NotifyableObject
         StructureRoot = new FolderViewModel(this, Internals, Internals.Tracker.Document.StructureRoot.GuidValue);
 
         TransformViewModel = new();
-        TransformViewModel.TransformMoved += (_, args) => Internals.ChangeController.OnTransformMoved(args);
+        TransformViewModel.TransformMoved += (_, args) => Internals.ChangeController.TransformMovedInlet(args);
 
         foreach (KeyValuePair<ChunkResolution, WriteableBitmap> bitmap in Bitmaps)
         {

+ 60 - 53
src/PixiEditor/ViewModels/SubViewModels/Main/IoViewModel.cs

@@ -12,7 +12,7 @@ using PixiEditor.ViewModels.SubViewModels.Tools.Tools;
 using PixiEditor.Views;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
-
+#nullable enable
 internal class IoViewModel : SubViewModel<ViewModelMain>
 {
     public RelayCommand MouseMoveCommand { get; set; }
@@ -22,22 +22,44 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
 
     private bool restoreToolOnKeyUp = false;
 
-    private MouseInputFilter filter = new();
+    private MouseInputFilter mouseFilter = new();
+    private KeyboardInputFilter keyboardFilter = new();
 
     public IoViewModel(ViewModelMain owner)
         : base(owner)
     {
-        MouseDownCommand = new RelayCommand(filter.MouseDown);
-        MouseMoveCommand = new RelayCommand(filter.MouseMove);
-        MouseUpCommand = new RelayCommand(filter.MouseUp);
+        MouseDownCommand = new RelayCommand(mouseFilter.MouseDownInlet);
+        MouseMoveCommand = new RelayCommand(mouseFilter.MouseMoveInlet);
+        MouseUpCommand = new RelayCommand(mouseFilter.MouseUpInlet);
         PreviewMouseMiddleButtonCommand = new RelayCommand(OnPreviewMiddleMouseButton);
-        GlobalMouseHook.OnMouseUp += filter.MouseUp;
+        GlobalMouseHook.OnMouseUp += mouseFilter.MouseUpInlet;
 
         InputManager.Current.PreProcessInput += Current_PreProcessInput;
 
-        filter.OnMouseDown += OnMouseDown;
-        filter.OnMouseMove += OnMouseMove;
-        filter.OnMouseUp += OnMouseUp;
+        mouseFilter.OnMouseDown += OnMouseDown;
+        mouseFilter.OnMouseMove += OnMouseMove;
+        mouseFilter.OnMouseUp += OnMouseUp;
+
+        keyboardFilter.OnAnyKeyDown += OnKeyDown;
+        keyboardFilter.OnAnyKeyUp += OnKeyUp;
+
+        keyboardFilter.OnConvertedKeyDown += OnConvertedKeyDown;
+        keyboardFilter.OnConvertedKeyUp += OnConvertedKeyDown;
+
+        Application.Current.Deactivated += keyboardFilter.DeactivatedInlet;
+        Application.Current.Deactivated += mouseFilter.DeactivatedInlet;
+    }
+
+    private void OnConvertedKeyDown(object? sender, FilteredKeyEventArgs args)
+    {
+        Owner.DocumentManagerSubViewModel.ActiveDocument?.EventInlet.OnConvertedKeyDown(args.Key);
+        Owner.ToolsSubViewModel.ConvertedKeyDownInlet(args);
+    }
+
+    private void OnConvertedKeyUp(object? sender, FilteredKeyEventArgs args)
+    {
+        Owner.DocumentManagerSubViewModel.ActiveDocument?.EventInlet.OnConvertedKeyUp(args.Key);
+        Owner.ToolsSubViewModel.ConvertedKeyUpInlet(args);
     }
 
     private void Current_PreProcessInput(object sender, PreProcessInputEventArgs e)
@@ -48,40 +70,35 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
 
             if (inputEvent is KeyboardEventArgs)
             {
-                KeyboardEventArgs k = inputEvent as KeyboardEventArgs;
+                KeyboardEventArgs k = (KeyboardEventArgs)inputEvent;
                 RoutedEvent r = k.RoutedEvent;
-                KeyEventArgs keyEvent = k as KeyEventArgs;
+                KeyEventArgs? keyEvent = k as KeyEventArgs;
 
-                if (keyEvent != null && keyEvent?.InputSource?.RootVisual != MainWindow.Current) return;
+                if (keyEvent is null && keyEvent?.InputSource?.RootVisual != MainWindow.Current)
+                    return;
                 if (r == Keyboard.KeyDownEvent)
                 {
-                    OnKeyDown(keyEvent);
+                    keyboardFilter.KeyDownInlet(keyEvent);
                 }
 
                 if (r == Keyboard.KeyUpEvent)
                 {
-                    OnKeyUp(keyEvent);
+                    keyboardFilter.KeyUpInlet(keyEvent);
                 }
             }
         }
     }
 
-    private void OnKeyDown(KeyEventArgs args)
+    private void OnKeyDown(object? sender, FilteredKeyEventArgs args)
     {
-        Key key = args.Key;
-        if (key == Key.System)
-            key = args.SystemKey;
-
-        ProcessShortcutDown(args.IsRepeat, key);
+        ProcessShortcutDown(args.IsRepeat, args.Key);
 
-        if (Owner.DocumentManagerSubViewModel.ActiveDocument != null)
-            Owner.DocumentManagerSubViewModel.ActiveDocument.EventInlet.OnKeyDown(key);
-        Owner.ToolsSubViewModel.OnKeyDown(key);
+        Owner.DocumentManagerSubViewModel.ActiveDocument?.EventInlet.OnKeyDown(args.Key);
 
         HandleTransientKey(args, true);
     }
 
-    private void HandleTransientKey(KeyEventArgs args, bool state)
+    private void HandleTransientKey(FilteredKeyEventArgs args, bool state)
     {
         if (ShortcutController.ShortcutExecutionBlocked)
         {
@@ -90,17 +107,11 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
 
         ShortcutController controller = Owner.ShortcutController;
 
-        Key finalKey = args.Key;
-        if (finalKey == Key.System)
-        {
-            finalKey = args.SystemKey;
-        }
-
-        Models.Commands.Commands.Command.ToolCommand tool = CommandController.Current.Commands
+        Models.Commands.Commands.Command.ToolCommand? tool = CommandController.Current.Commands
             .Select(x => x as Models.Commands.Commands.Command.ToolCommand)
-            .FirstOrDefault(x => x != null && x.TransientKey == finalKey);
+            .FirstOrDefault(x => x != null && x.TransientKey == args.Key);
 
-        if (tool != null)
+        if (tool is not null)
         {
             ChangeToolState(tool.ToolType, state);
         }
@@ -118,17 +129,12 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
         Owner.ShortcutController.KeyPressed(key, Keyboard.Modifiers);
     }
 
-    private void OnKeyUp(KeyEventArgs args)
+    private void OnKeyUp(object? sender, FilteredKeyEventArgs args)
     {
-        Key key = args.Key;
-        if (key == Key.System)
-            key = args.SystemKey;
-
-        ProcessShortcutUp(new(key, args.KeyboardDevice.Modifiers));
+        ProcessShortcutUp(new(args.Key, args.Modifiers));
 
         if (Owner.DocumentManagerSubViewModel.ActiveDocument is not null)
-            Owner.DocumentManagerSubViewModel.ActiveDocument.EventInlet.OnKeyUp(key);
-        Owner.ToolsSubViewModel.OnKeyUp(key);
+            Owner.DocumentManagerSubViewModel.ActiveDocument.EventInlet.OnKeyUp(args.Key);
 
         HandleTransientKey(args, false);
     }
@@ -139,23 +145,23 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
             Owner.ShortcutController.LastCommands.Any(x => x.Shortcut == shortcut))
         {
             restoreToolOnKeyUp = false;
-            Owner.ToolsSubViewModel.SetActiveTool(Owner.ToolsSubViewModel.LastActionTool);
+            if (Owner.ToolsSubViewModel.LastActionTool is { } tool)
+                Owner.ToolsSubViewModel.SetActiveTool(tool);
             ShortcutController.UnblockShortcutExecution("ShortcutDown");
         }
     }
 
-    private void OnMouseDown(object sender, MouseOnCanvasEventArgs args)
+    private void OnMouseDown(object? sender, MouseOnCanvasEventArgs args)
     {
         if (args.Button == MouseButton.Left)
         {
             DocumentManagerViewModel docManager = Owner.DocumentManagerSubViewModel;
-            DocumentViewModel activeDocument = docManager.ActiveDocument;
+            DocumentViewModel? activeDocument = docManager.ActiveDocument;
             if (activeDocument == null)
                 return;
 
-            //docManager.InputTarget.OnLeftMouseButtonDown(activeDocument.MouseXOnCanvas, activeDocument.MouseYOnCanvas);
-            docManager.ActiveDocument.EventInlet.OnCanvasLeftMouseButtonDown(args.PositionOnCanvas);
-            Owner.ToolsSubViewModel.OnLeftMouseButtonDown(args.PositionOnCanvas);
+            activeDocument.EventInlet.OnCanvasLeftMouseButtonDown(args.PositionOnCanvas);
+            Owner.ToolsSubViewModel.LeftMouseButtonDownInlet(args.PositionOnCanvas);
         }
     }
 
@@ -174,7 +180,10 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
     {
         if (setOn)
         {
-            bool transientToolIsActive = Owner.ToolsSubViewModel.ActiveTool.GetType() == type;
+            var tool = Owner.ToolsSubViewModel.ActiveTool;
+            if (tool is null)
+                return;
+            bool transientToolIsActive = tool.GetType() == type;
             if (!transientToolIsActive)
             {
                 Owner.ToolsSubViewModel.SetActiveTool(type);
@@ -189,22 +198,20 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
         }
     }
 
-    private void OnMouseMove(object sender, VecD pos)
+    private void OnMouseMove(object? sender, VecD pos)
     {
-        DocumentViewModel activeDocument = Owner.DocumentManagerSubViewModel.ActiveDocument;
+        DocumentViewModel? activeDocument = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (activeDocument is null)
             return;
-        //Owner.DocumentManagerSubViewModel.InputTarget.OnMouseMove(activeDocument.MouseXOnCanvas, activeDocument.MouseYOnCanvas);
         activeDocument.EventInlet.OnCanvasMouseMove(pos);
     }
 
-    private void OnMouseUp(object sender, MouseButton button)
+    private void OnMouseUp(object? sender, MouseButton button)
     {
         if (Owner.DocumentManagerSubViewModel.ActiveDocument is null)
             return;
         if (button == MouseButton.Left)
         {
-            //Owner.BitmapManager.InputTarget.OnLeftMouseButtonUp();
             Owner.DocumentManagerSubViewModel.ActiveDocument.EventInlet.OnCanvasLeftMouseButtonUp();
         }
         else if (button == MouseButton.Middle)

+ 5 - 25
src/PixiEditor/ViewModels/SubViewModels/Main/ToolsViewModel.cs

@@ -175,38 +175,18 @@ internal class ToolsViewModel : SubViewModel<ViewModelMain>
         }
     }
 
-    public void OnLeftMouseButtonDown(VecD canvasPos)
+    public void LeftMouseButtonDownInlet(VecD canvasPos)
     {
         ActiveTool?.OnLeftMouseButtonDown(canvasPos);
     }
 
-    public void OnKeyDown(Key key)
+    public void ConvertedKeyDownInlet(FilteredKeyEventArgs args)
     {
-        bool shiftIsDown = key is Key.LeftShift or Key.RightShift;
-        bool ctrlIsDown = key is Key.LeftCtrl or Key.RightCtrl;
-        bool altIsDown = key is Key.LeftAlt or Key.RightAlt;
-        if (!shiftIsDown && !ctrlIsDown && !altIsDown)
-            return;
-        this.shiftIsDown |= shiftIsDown;
-        this.ctrlIsDown |= ctrlIsDown;
-        this.altIsDown |= altIsDown;
-
-        ActiveTool?.UpdateActionDisplay(this.ctrlIsDown, this.shiftIsDown, this.altIsDown);
+        ActiveTool?.UpdateActionDisplay(args.IsCtrlDown, args.IsShiftDown, args.IsAltDown);
     }
 
-    public void OnKeyUp(Key key)
+    public void ConvertedKeyUpInlet(FilteredKeyEventArgs args)
     {
-        bool shiftIsUp = key is Key.LeftShift or Key.RightShift;
-        bool ctrlIsUp = key is Key.LeftCtrl or Key.RightCtrl;
-        bool altIsUp = key is Key.LeftAlt or Key.RightAlt;
-        if (!shiftIsUp && !ctrlIsUp && !altIsUp)
-            return;
-        if (shiftIsUp)
-            this.shiftIsDown = false;
-        if (ctrlIsUp)
-            this.ctrlIsDown = false;
-        if (altIsUp)
-            this.altIsDown = false;
-        ActiveTool?.UpdateActionDisplay(ctrlIsDown, shiftIsDown, altIsDown);
+        ActiveTool?.UpdateActionDisplay(args.IsCtrlDown, args.IsShiftDown, args.IsAltDown);
     }
 }