Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support showing ctrl, alt, win keys pressed down without any other key #160

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Carnac.Logic/KeyMonitor/InterceptKeys.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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,
Expand Down
15 changes: 12 additions & 3 deletions src/Carnac.Logic/KeyProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class KeyProvider : IKeyProvider
readonly IPasswordModeService passwordModeService;
readonly IDesktopLockEventService desktopLockEventService;

private readonly IList<Keys> modifierKeys =
private static readonly IList<Keys> modifierKeys =
new List<Keys>
{
Keys.LControlKey,
Expand Down Expand Up @@ -68,7 +68,7 @@ public IObservable<KeyPress> 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))
Expand All @@ -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);
}
Expand Down Expand Up @@ -123,6 +123,15 @@ static IEnumerable<string> 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)
Expand Down
40 changes: 26 additions & 14 deletions src/Carnac.Logic/Models/Message.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,7 +28,6 @@ public Message(KeyPress key)
{
processName = key.Process.ProcessName;
processIcon = key.Process.ProcessIcon;
canBeMerged = !key.HasModifierPressed;

keys = new ReadOnlyCollection<KeyPress>(new[] { key });
textCollection = new ReadOnlyCollection<string>(CreateTextSequence(key).ToArray());
Expand All @@ -49,7 +47,6 @@ public Message(IEnumerable<KeyPress> keys, KeyShortcut shortcut)
processIcon = allKeys.First().Process.ProcessIcon;
shortcutName = shortcut.Name;
isShortcut = true;
canBeMerged = false;

this.keys = new ReadOnlyCollection<KeyPress>(allKeys);

Expand All @@ -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)
Expand All @@ -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; } }
Expand All @@ -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()
Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand Down
4 changes: 4 additions & 0 deletions src/Carnac.Logic/ReplaceKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down