diff --git a/src/Carnac.Logic/KeyMonitor/InterceptKeys.cs b/src/Carnac.Logic/KeyMonitor/InterceptKeys.cs index 6a621938..322c067b 100644 --- a/src/Carnac.Logic/KeyMonitor/InterceptKeys.cs +++ b/src/Carnac.Logic/KeyMonitor/InterceptKeys.cs @@ -62,6 +62,7 @@ static InterceptKeyEventArgs CreateEventArgs(IntPtr wParam, IntPtr lParam) bool keyUp = wParam == (IntPtr)Win32Methods.WM_KEYUP; int vkCode = Marshal.ReadInt32(lParam); var key = (Keys)vkCode; + //http://msdn.microsoft.com/en-us/library/windows/desktop/ms646286(v=vs.85).aspx if (key != Keys.RMenu && key != Keys.LMenu && wParam == (IntPtr)Win32Methods.WM_SYSKEYDOWN) { @@ -73,6 +74,10 @@ static InterceptKeyEventArgs CreateEventArgs(IntPtr wParam, IntPtr lParam) alt = true; keyUp = true; } + if (wParam == (IntPtr)Win32Methods.WM_SYSKEYDOWN && key == Keys.LMenu) + { + keyDown = true; + } return new InterceptKeyEventArgs( key, diff --git a/src/Carnac.Logic/KeyProvider.cs b/src/Carnac.Logic/KeyProvider.cs index d5272adb..946caed6 100644 --- a/src/Carnac.Logic/KeyProvider.cs +++ b/src/Carnac.Logic/KeyProvider.cs @@ -20,7 +20,7 @@ public class KeyProvider : IKeyProvider readonly IPasswordModeService passwordModeService; readonly IDesktopLockEventService desktopLockEventService; - private readonly IList modifierKeys = + private static readonly IList modifierKeys = new List { Keys.LControlKey, @@ -68,7 +68,7 @@ public IObservable GetKeyStream() var keyStreamSubsription = interceptKeysSource.GetKeyStream() .Select(DetectWindowsKey) - .Where(k => !IsModifierKeyPress(k) && k.KeyDirection == KeyDirection.Down) + .Where(k => k.KeyDirection == KeyDirection.Down) .Select(ToCarnacKeyPress) .Where(keypress => keypress != null) .Where(k => !passwordModeService.CheckPasswordMode(k.InterceptKeyEventArgs)) @@ -91,7 +91,7 @@ InterceptKeyEventArgs DetectWindowsKey(InterceptKeyEventArgs interceptKeyEventAr return interceptKeyEventArgs; } - bool IsModifierKeyPress(InterceptKeyEventArgs interceptKeyEventArgs) + public static bool IsModifierKeyPress(InterceptKeyEventArgs interceptKeyEventArgs) { return modifierKeys.Contains(interceptKeyEventArgs.Key); } @@ -123,6 +123,15 @@ static IEnumerable ToInputs(bool isLetter, bool isWinKeyPressed, Interce var controlPressed = interceptKeyEventArgs.ControlPressed; var altPressed = interceptKeyEventArgs.AltPressed; var shiftPressed = interceptKeyEventArgs.ShiftPressed; + + if (IsModifierKeyPress(interceptKeyEventArgs)) + { + controlPressed = false; + altPressed = false; + shiftPressed = false; + isWinKeyPressed = false; + } + if (controlPressed) yield return "Ctrl"; if (altPressed) diff --git a/src/Carnac.Logic/Models/Message.cs b/src/Carnac.Logic/Models/Message.cs index 415492b0..ca843b4b 100644 --- a/src/Carnac.Logic/Models/Message.cs +++ b/src/Carnac.Logic/Models/Message.cs @@ -13,7 +13,6 @@ public sealed class Message readonly string processName; readonly ImageSource processIcon; readonly string shortcutName; - readonly bool canBeMerged; readonly bool isShortcut; readonly bool isDeleting; readonly DateTime lastMessage; @@ -29,7 +28,6 @@ public Message(KeyPress key) { processName = key.Process.ProcessName; processIcon = key.Process.ProcessIcon; - canBeMerged = !key.HasModifierPressed; keys = new ReadOnlyCollection(new[] { key }); textCollection = new ReadOnlyCollection(CreateTextSequence(key).ToArray()); @@ -49,7 +47,6 @@ public Message(IEnumerable keys, KeyShortcut shortcut) processIcon = allKeys.First().Process.ProcessIcon; shortcutName = shortcut.Name; isShortcut = true; - canBeMerged = false; this.keys = new ReadOnlyCollection(allKeys); @@ -63,7 +60,6 @@ private Message(Message initial, Message appended) : this(initial.keys.Concat(appended.keys), new KeyShortcut(initial.ShortcutName)) { previous = initial; - canBeMerged = true; } private Message(Message initial, bool isDeleting) @@ -74,14 +70,18 @@ private Message(Message initial, bool isDeleting) lastMessage = initial.lastMessage; } + private Message(Message initial, Message replacer, bool replace) + : this(replacer.keys, new KeyShortcut(replacer.ShortcutName)) + { + previous = initial; + } + public string ProcessName { get { return processName; } } public ImageSource ProcessIcon { get { return processIcon; } } public string ShortcutName { get { return shortcutName; } } - public bool CanBeMerged { get { return canBeMerged; } } - public bool IsShortcut { get { return isShortcut; } } public Message Previous { get { return previous; } } @@ -97,21 +97,35 @@ public Message Merge(Message other) return new Message(this, other); } - static readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1); + public Message Replace(Message newMessage) + { + return new Message(this, newMessage, true); + } + + static readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1); public static Message MergeIfNeeded(Message previousMessage, Message newMessage) { - return ShouldCreateNewMessage(previousMessage, newMessage) - ? newMessage - : previousMessage.Merge(newMessage); + // replace key was after standalone modifier keypress, replace by new Message + if (previousMessage.keys != null && KeyProvider.IsModifierKeyPress(previousMessage.keys[0].InterceptKeyEventArgs)) + { + return previousMessage.Replace(newMessage); + } + + if (ShouldCreateNewMessage(previousMessage, newMessage)) + { + return newMessage; + } + return previousMessage.Merge(newMessage); } static bool ShouldCreateNewMessage(Message previous, Message current) { return previous.ProcessName != current.ProcessName || current.LastMessage.Subtract(previous.LastMessage) > OneSecond || - !previous.CanBeMerged || - !current.CanBeMerged; + KeyProvider.IsModifierKeyPress(current.keys[0].InterceptKeyEventArgs) || + // accumulate also same modifier shortcuts + (previous.keys[0].HasModifierPressed && !previous.keys[0].Input.SequenceEqual(current.keys[0].Input)); } public Message FadeOut() @@ -204,7 +218,6 @@ bool Equals(Message other) && string.Equals(processName, other.processName) && Equals(processIcon, other.processIcon) && string.Equals(shortcutName, other.shortcutName) - && canBeMerged.Equals(other.canBeMerged) && isShortcut.Equals(other.isShortcut) && isDeleting.Equals(other.isDeleting) && lastMessage.Equals(other.lastMessage); @@ -227,7 +240,6 @@ public override int GetHashCode() hashCode = (hashCode * 397) ^ (processName != null ? processName.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (processIcon != null ? processIcon.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (shortcutName != null ? shortcutName.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ canBeMerged.GetHashCode(); hashCode = (hashCode * 397) ^ isShortcut.GetHashCode(); hashCode = (hashCode * 397) ^ isDeleting.GetHashCode(); hashCode = (hashCode * 397) ^ lastMessage.GetHashCode(); diff --git a/src/Carnac.Logic/ReplaceKey.cs b/src/Carnac.Logic/ReplaceKey.cs index 6905a56d..c1f927a2 100644 --- a/src/Carnac.Logic/ReplaceKey.cs +++ b/src/Carnac.Logic/ReplaceKey.cs @@ -78,6 +78,10 @@ public static class ReplaceKey {Keys.RShiftKey, "Shift"}, {Keys.LWin, "Win"}, {Keys.RWin, "Win"}, + {Keys.LControlKey, "Ctrl"}, + {Keys.RControlKey, "Ctrl"}, + {Keys.Alt, "Alt"}, + {Keys.LMenu, "Alt"}, }; public static Keys? ToKey(string keyText)