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

Pls add option for align #285

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
815f75d
Register alt key without another key
bfritscher Jul 14, 2017
6f2ae82
Replacement text for Alt and Ctrl standalone
bfritscher Jul 14, 2017
83d7c76
Support to show keyboard keys based on locales
bfritscher Jul 15, 2017
51c5c44
Show mouse actions as keys with a symbol
bfritscher Jul 16, 2017
53d744f
Visual circles arround mouse cursor and preferences menu
bfritscher Jul 16, 2017
e10b7ae
use mousehook directly without InerceptMouse
bfritscher Jul 16, 2017
c3e04a8
Support showing ctrl, alt, win keys pressed down without any other key
bfritscher Jul 14, 2017
2a4649c
fix special cases key getting transformed to empty string
bfritscher Jul 17, 2017
c6b2be5
Better support for mouse aggregation and show shift + mouse
bfritscher Jul 17, 2017
32895ad
Refactor to transform a list of special keys into keycapborder visuals
bfritscher Jul 17, 2017
6739401
better repeat logic for text and ...
bfritscher Jul 17, 2017
d582c92
Merge branch 'hide-overlay-window' into beta
bfritscher Jul 17, 2017
1c09620
Merge branch 'locale-keyboard-support' into beta
bfritscher Jul 17, 2017
54b87d0
Merge branch 'option-for-auto-update' into beta
bfritscher Jul 17, 2017
6fd93b0
Merge branch 'show-all-modifiers' into beta
bfritscher Jul 17, 2017
a8baf98
Merge show-modifier-keys-while-down
bfritscher Jul 17, 2017
35c2747
merge mouse-click-highlight
bfritscher Jul 17, 2017
b10fcda
merge KeyCapBorder-for-all-special-keys
bfritscher Jul 17, 2017
4e7bcde
fix missing reference in project file
bfritscher Jul 17, 2017
42d6d3b
ensure the mouse hook is disposed on exit
gdh1995 Jul 20, 2017
2c2da94
Merge pull request #4 from gdh1995/ensure-hooks-are-disposed
bfritscher Jul 20, 2017
78a8385
Add scroll button click color and allow multiple modifiers for clicks
tkozono Jun 10, 2018
7f6d61e
Register alt key without another key
bfritscher Jul 14, 2017
efdf520
Replacement text for Alt and Ctrl standalone
bfritscher Jul 14, 2017
eabc121
Support to show keyboard keys based on locales
bfritscher Jul 15, 2017
0471dbd
Show mouse actions as keys with a symbol
bfritscher Jul 16, 2017
c1d8417
Visual circles arround mouse cursor and preferences menu
bfritscher Jul 16, 2017
5772673
use mousehook directly without InerceptMouse
bfritscher Jul 16, 2017
4f10ff4
Support showing ctrl, alt, win keys pressed down without any other key
bfritscher Jul 14, 2017
8966da4
fix special cases key getting transformed to empty string
bfritscher Jul 17, 2017
0387dac
Better support for mouse aggregation and show shift + mouse
bfritscher Jul 17, 2017
5af9005
Refactor to transform a list of special keys into keycapborder visuals
bfritscher Jul 17, 2017
859e17d
better repeat logic for text and ...
bfritscher Jul 17, 2017
d52b11b
fix missing reference in project file
bfritscher Jul 17, 2017
99d3acc
ensure the mouse hook is disposed on exit
gdh1995 Jul 20, 2017
6ed6d5c
Fix missing code after rebase merge
bfritscher Apr 20, 2020
6bfa3a7
Add slider to adjuste mouse key display size
bfritscher Apr 20, 2020
67b1f39
Merge branch 'beta' of https://github.com/bfritscher/carnac into beta
bfritscher Apr 20, 2020
0497ff2
Fix merge rebase
bfritscher Apr 20, 2020
7b578b8
Merge pull request #5 from tkozono/beta
bfritscher Apr 20, 2020
1ed340a
Feature: Additional colors options for ScrollClick, XButton1, XButton2
bfritscher Apr 20, 2020
de28bca
Feature: Mouse icon displays icon higlight in same color as click cir…
bfritscher Apr 20, 2020
f67d601
Feature: Add possibility to show/hide mouse clicks or scroll as keys
bfritscher Apr 20, 2020
494dbb2
small info in readme
bfritscher Apr 20, 2020
d3b2dc3
Update README.md
bfritscher Aug 15, 2021
a21487a
Fix typo in readme
MiYanni Nov 6, 2021
19f8b86
Merge pull request #49 from MiYanni/patch-1
bfritscher Nov 6, 2021
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
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
## Carnac the Magnificent Keyboard Utility
## Carnac the Magnificent Keyboard Utility & Mouse Highlighter*

This is a Fork of Carnac which adds mouse click highlights with circles, as well as key icons. The current version can be manually downloaded and tested from the [release page](https://github.com/bfritscher/carnac/releases). This project is not actively maintained, but patched together in my spare time and based on my needs when giving tutorials.


## Original Readme


[![Join the chat at https://gitter.im/Code52/carnac](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Code52/carnac?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

Expand All @@ -21,7 +27,7 @@ Alternatively, you can grab the latest zip file from [here](https://github.com/C

### Updating

We use `Squirrel.Windows` to update your `carnac` application.
We use `Squirrel.Windows` to update your `carnac` application.

The application will check for updates in the background, if a new version has been released, it will automatically install the new version and once you restart `carnac` you will be up-to-date.

Expand All @@ -40,13 +46,13 @@ If you want to stop `Carnac` from recording certain key strokes, you can enter _
* [The simple guide to GIT guide](http://rogerdudler.github.com/git-guide/)
* [Open an issue](https://github.com/Code52/carnac/issues) if you encounter a bug or have a suggestion for improvements/features

Once you're familiar with Git and GitHub, clone the repository and run the ```.\build.cmd``` script to compile the code and run all the unit tests. You can use this script to test your changes quickly.
Once you're familiar with Git and GitHub, clone the repository and run the `.\build.cmd` script to compile the code and run all the unit tests. You can use this script to test your changes quickly.

### Resources
This blog series covers a series of refactorings which have recently happened in Carnac to make better use of Rx.
If you are learning Rx and want to be shown through Carnac's codebase then this blog series may help you.

[Part 1 - Refactoring the InterceptKeys class ](http://jake.ginnivan.net/blog/carnac-improvements/part-1/)
[Part 2 - Refactoring the MessageProvider class](http://jake.ginnivan.net/blog/carnac-improvements/part-2/)
[Part 3 - Introducing the MessageController class](http://jake.ginnivan.net/blog/carnac-improvements/part-3/)
[Part 1 - Refactoring the InterceptKeys class ](http://jake.ginnivan.net/blog/carnac-improvements/part-1/)
[Part 2 - Refactoring the MessageProvider class](http://jake.ginnivan.net/blog/carnac-improvements/part-2/)
[Part 3 - Introducing the MessageController class](http://jake.ginnivan.net/blog/carnac-improvements/part-3/)

6 changes: 5 additions & 1 deletion src/Carnac.Logic/Carnac.Logic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Gma.System.MouseKeyHook, Version=5.4.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\MouseKeyHook.5.4.0\lib\net40\Gma.System.MouseKeyHook.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="PropertyChanged, Version=1.52.1.0, Culture=neutral, PublicKeyToken=ee3ee20bcf148ddd, processorArchitecture=MSIL">
Expand Down Expand Up @@ -93,6 +96,7 @@
<Compile Include="KeysController.cs" />
<Compile Include="Models\Processinfo.cs" />
<Compile Include="AssociatedProcessUtilities.cs" />
<Compile Include="MouseMonitor\InterceptMouse.cs" />
<Compile Include="ShortcutAccumulator.cs" />
<Compile Include="KeyPressDefinition.cs" />
<Compile Include="KeyShortcut.cs" />
Expand Down Expand Up @@ -151,7 +155,7 @@
</PropertyGroup>
<Error Condition="!Exists('..\packages\Fody.1.29.4\build\portable-net+sl+win+wpa+wp\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.1.29.4\build\portable-net+sl+win+wpa+wp\Fody.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
Expand Down
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
50 changes: 32 additions & 18 deletions src/Carnac.Logic/KeyProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
using System.Windows.Media;
using SettingsProviderNet;
using System.Text.RegularExpressions;
using Carnac.Logic.MouseMonitor;


namespace Carnac.Logic
{
Expand All @@ -23,7 +25,7 @@ public class KeyProvider : IKeyProvider
readonly PopupSettings settings;
string currentFilter = null;

private readonly IList<Keys> modifierKeys =
private static readonly IList<Keys> modifierKeys =
new List<Keys>
{
Keys.LControlKey,
Expand Down Expand Up @@ -96,9 +98,12 @@ public IObservable<KeyPress> GetKeyStream()
winKeyPressed = false;
}, observer.OnError);

var keyStreamSubsription = interceptKeysSource.GetKeyStream()
var keyStreamSubsription = Observable.Merge(
new IObservable<InterceptKeyEventArgs>[2] {
interceptKeysSource.GetKeyStream(),
InterceptMouse.Current.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 @@ -121,7 +126,7 @@ InterceptKeyEventArgs DetectWindowsKey(InterceptKeyEventArgs interceptKeyEventAr
return interceptKeyEventArgs;
}

bool IsModifierKeyPress(InterceptKeyEventArgs interceptKeyEventArgs)
public static bool IsModifierKeyPress(InterceptKeyEventArgs interceptKeyEventArgs)
{
return modifierKeys.Contains(interceptKeyEventArgs.Key);
}
Expand All @@ -141,6 +146,16 @@ KeyPress ToCarnacKeyPress(InterceptKeyEventArgs interceptKeyEventArgs)
return null;
}

if (!settings.ShowMouseClickKeys && (interceptKeyEventArgs.Key == Keys.LButton || interceptKeyEventArgs.Key == Keys.MButton || interceptKeyEventArgs.Key == Keys.RButton || interceptKeyEventArgs.Key == Keys.XButton1 || interceptKeyEventArgs.Key == Keys.XButton2))
{
return null;
}

if (!settings.ShowMouseScrollKeys && (interceptKeyEventArgs.Key == Keys.VolumeUp || interceptKeyEventArgs.Key == Keys.VolumeDown))
{
return null;
}

var isLetter = interceptKeyEventArgs.IsLetter();
var inputs = ToInputs(isLetter, winKeyPressed, interceptKeyEventArgs).ToArray();
try
Expand All @@ -160,35 +175,34 @@ 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;
}

var mouseAction = InterceptMouse.MouseKeys.Contains(interceptKeyEventArgs.Key);
if (controlPressed)
yield return "Ctrl";
if (altPressed)
yield return "Alt";
if (isWinKeyPressed)
yield return "Win";

if (controlPressed || altPressed)
if (controlPressed || altPressed || mouseAction)
{
//Treat as a shortcut, don't be too smart
if (shiftPressed)
yield return "Shift";

yield return interceptKeyEventArgs.Key.Sanitise();
yield return interceptKeyEventArgs.Key.SanitiseLower();
}
else
{
string input;
var shiftModifiesInput = interceptKeyEventArgs.Key.SanitiseShift(out input);

if (!isLetter && !shiftModifiesInput && shiftPressed)
yield return "Shift";

if (interceptKeyEventArgs.ShiftPressed && shiftModifiesInput)
yield return input;
else if (isLetter && !interceptKeyEventArgs.ShiftPressed)
yield return interceptKeyEventArgs.Key.ToString().ToLower();
else
yield return interceptKeyEventArgs.Key.Sanitise();
yield return interceptKeyEventArgs.Key.Sanitise();
}
}
}
Expand Down
59 changes: 51 additions & 8 deletions src/Carnac.Logic/Models/Message.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Carnac.Logic.MouseMonitor;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
Expand Down Expand Up @@ -50,6 +51,7 @@ public Message(IEnumerable<KeyPress> keys, KeyShortcut shortcut, Boolean isShort
processName = distinctProcessName.Single();
processIcon = allKeys.First().Process.ProcessIcon;
shortcutName = shortcut.Name;

this.isShortcut = isShortcut;
this.isModifier = allKeys.Any(k => k.HasModifierPressed);
canBeMerged = false;
Expand Down Expand Up @@ -77,6 +79,12 @@ 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; } }
Expand All @@ -102,21 +110,41 @@ 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 ||
KeyProvider.IsModifierKeyPress(current.keys[0].InterceptKeyEventArgs) ||
// accumulate also same modifier shortcuts
(previous.keys[0].HasModifierPressed && !previous.keys[0].Input.SequenceEqual(current.keys[0].Input)) ||
!previous.CanBeMerged ||
!current.CanBeMerged;
!current.CanBeMerged ||
// new message for different mouse keys;
((InterceptMouse.MouseKeys.Contains(current.keys[0].Key) ||
(previous.keys != null && InterceptMouse.MouseKeys.Contains(previous.keys[0].Key)))
&& !previous.keys[0].Input.SequenceEqual(current.keys[0].Input));
}

public Message FadeOut()
Expand All @@ -137,10 +165,25 @@ static IEnumerable<string> CreateTextSequence(IEnumerable<KeyPress> keys)
if (acc.Any())
{
var last = acc.Last();
if (last.IsRepeatedBy(curr))
var secondLast = acc.Count() > 1 ? acc.SkipLast(1).Last() : null;
var thirdLast = acc.Count() > 2 ? acc.SkipLast(2).Last() : null;
if (last.IsRepeatedBy(curr) &&
// not a letter or a letter with a modifier or repeated letter
(!(curr.InterceptKeyEventArgs.IsLetter() || curr.GetTextParts().First() == ".") || curr.HasModifierPressed || last.RepeatCount > 2))
{
last.IncrementRepeat();
}
else if (last.IsRepeatedBy(curr) &&
// a letter is repeated 4 times now count it x times
(curr.InterceptKeyEventArgs.IsLetter() || curr.GetTextParts().First() == ".") && secondLast != null && secondLast.IsRepeatedBy(curr)
&& thirdLast != null && thirdLast.IsRepeatedBy(curr))
{
acc.Remove(last);
acc.Remove(secondLast);
thirdLast.IncrementRepeat();
thirdLast.IncrementRepeat();
thirdLast.IncrementRepeat();
}
else
{
acc.Add(new RepeatedKeyPress(curr, last.NextRequiresSeperator));
Expand Down Expand Up @@ -177,6 +220,8 @@ public RepeatedKeyPress(KeyPress keyPress, bool requiresPrefix = false)

public bool NextRequiresSeperator { get { return nextRequiresSeperator; } }

public int RepeatCount { get { return repeatCount; } }

public void IncrementRepeat()
{
repeatCount++;
Expand Down Expand Up @@ -209,7 +254,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 @@ -232,7 +276,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
49 changes: 49 additions & 0 deletions src/Carnac.Logic/Models/PopupSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,54 @@ public string SortDescription
public bool SettingsConfigured { get; set; }
public bool ShowOnlyModifiers { get; set; }
public bool ShowSpaceAsUnicode { get; set; }

[DefaultValue(true)]
public bool ShowMouseClicks { get; set; }

[DefaultValue(true)]
public bool ShowMouseClickKeys { get; set; }

[DefaultValue(true)]
public bool ShowMouseScrollKeys { get; set; }

[DefaultValue(40)]
public int MouseKeySize { get; set; }

[DefaultValue("OrangeRed")]
public string LeftClickColor { get; set; }

[DefaultValue("RoyalBlue")]
public string RightClickColor { get; set; }

[DefaultValue("Gold")]
public string ScrollClickColor { get; set; }

[DefaultValue("Peru")]
public string XButton1ClickColor { get; set; }

[DefaultValue("Plum")]
public string XButton2ClickColor { get; set; }

[DefaultValue(1)]
public double ClickStartScale { get; set; }

[DefaultValue(4)]
public double ClickStopScale { get; set; }

[DefaultValue(3700)]
public int ClickFadeDelay { get; set; }

[DefaultValue(1)]
public double ClickStartBorder { get; set; }

[DefaultValue(0.8)]
public double ClickStartOpacity { get; set; }

[DefaultValue(2)]
public double ClickStopBorder { get; set; }

[DefaultValue(0)]
public double ClickStopOpacity { get; set; }
public string ClickColor { get; set; }
}
}
Loading