Skip to content

Commit

Permalink
Refactor HotKey stuff to use user settings and not app settings.
Browse files Browse the repository at this point in the history
Switch all settings to a UI form.
Manage HotKey starting/stopping better (including don't listen for keys when typing keys)
  • Loading branch information
Greg committed Nov 23, 2023
1 parent d207617 commit 5e58654
Show file tree
Hide file tree
Showing 13 changed files with 2,325 additions and 65 deletions.
8 changes: 6 additions & 2 deletions App.config
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
<appSettings>
<add key="SendKeys" value="SendInput" />
<add key="ClientSettingsProvider.ServiceUri" value="" />
<add key="HotKey" value="V" />
<add key="HotKeyModifer" value="3" />
</appSettings>
<userSettings>
<ClickPaste.Properties.Settings>
Expand All @@ -25,6 +23,12 @@
<setting name="KeyDelayMS" serializeAs="String">
<value>5</value>
</setting>
<setting name="HotKey" serializeAs="String">
<value>V</value>
</setting>
<setting name="HotKeyModifier" serializeAs="String">
<value>3</value>
</setting>
</ClickPaste.Properties.Settings>
</userSettings>
<system.web>
Expand Down
10 changes: 10 additions & 0 deletions ClickPaste.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,17 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="HotKeyManager.cs" />
<Compile Include="Native.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings.cs" />
<Compile Include="SettingsForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="SettingsForm.Designer.cs">
<DependentUpon>SettingsForm.cs</DependentUpon>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
Expand All @@ -77,6 +84,9 @@
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<EmbeddedResource Include="SettingsForm.resx">
<DependentUpon>SettingsForm.cs</DependentUpon>
</EmbeddedResource>
<None Include="app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
Expand Down
103 changes: 45 additions & 58 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Media;
using System.Reflection;
Expand Down Expand Up @@ -68,27 +67,18 @@ public enum TypeMethod
Forms_SendKeys = 0,
AutoIt_Send
}
public enum KeyDelays
{
Five_ms = 5,
Ten_ms = 10,
Twenty_ms = 20,
Thirty_ms = 30,
Forty_ms = 40
}

public class TrayApplicationContext : ApplicationContext
{
NotifyIcon _notify = null;
IKeyboardMouseEvents _hook = null;
MenuItem[] _typeMethods; // these are just sequential 0-based integers so don't need to map them like...
Dictionary<int, MenuItem> _keyDelayMS;// we do here
int? _usingHotKey;
bool _settingsOpen = false;
public TrayApplicationContext()
{
Keys HotKey = (Keys)Enum.Parse(typeof(Keys), ConfigurationManager.AppSettings["HotKey"]);
KeyModifiers HotKeyModifer = (KeyModifiers)Int32.Parse(ConfigurationManager.AppSettings["HotKeyModifer"]);
HotKeyManager.RegisterHotKey(HotKey, HotKeyModifer);
HotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyManager_HotKeyPressed);
StartHotKey();
bool darkTray = true;
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"))
{
Expand All @@ -100,28 +90,6 @@ public TrayApplicationContext()
}
var traySize = SystemInformation.SmallIconSize;

_typeMethods = new MenuItem[typeof(TypeMethod).Count()];
ushort i = 0;
foreach(var name in typeof(TypeMethod).Names())
{
_typeMethods[i] = new MenuItem(name.Replace('_',' '), ChangeTypeMethod);
_typeMethods[i].RadioCheck = true;
_typeMethods[i].Tag = typeof(TypeMethod).Value(name);
i++;
};
_typeMethods[Properties.Settings.Default.TypeMethod].Checked = true;

_keyDelayMS = new Dictionary<int, MenuItem>();
foreach(var name in typeof(KeyDelays).Names())
{
var kd = new MenuItem(name.Replace('_', ' '), ChangeKeyDelayMethod);
kd.RadioCheck = true;
var val = (int)typeof(KeyDelays).Value(name);
kd.Tag = val;
_keyDelayMS[val] = kd;
}
_keyDelayMS[Properties.Settings.Default.KeyDelayMS].Checked = true;

_notify = new NotifyIcon
{
Icon = new System.Drawing.Icon(darkTray ? Properties.Resources.Target : Properties.Resources.TargetDark, traySize.Width, traySize.Height),
Expand All @@ -130,8 +98,7 @@ public TrayApplicationContext()
new ContextMenu(
new MenuItem[]
{
new MenuItem("Typing method", _typeMethods),
new MenuItem("Delay between keys", _keyDelayMS.Values.ToArray()),
new MenuItem("Settings", Settings),
new MenuItem("-"),
new MenuItem("Exit", Exit),
}
Expand All @@ -144,26 +111,6 @@ private void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
{
StartTrack();
}
private void ChangeTypeMethod(object sender, EventArgs e)
{
Properties.Settings.Default.TypeMethod = (int)((sender as MenuItem).Tag);
Properties.Settings.Default.Save();
foreach(var item in _typeMethods)
{
item.Checked = false;
}
_typeMethods[Properties.Settings.Default.TypeMethod].Checked = true;
}
private void ChangeKeyDelayMethod(object sender, EventArgs e)
{
Properties.Settings.Default.KeyDelayMS = (int)((sender as MenuItem).Tag);
Properties.Settings.Default.Save();
foreach(var item in _keyDelayMS.Values)
{
item.Checked = false;
}
_keyDelayMS[Properties.Settings.Default.KeyDelayMS].Checked = true;
}
void StartTrack()
{
if (_hook == null)
Expand Down Expand Up @@ -232,6 +179,8 @@ private void _hook_MouseUp(object sender, MouseEventArgs e)
else
{
Thread.Sleep(100);
// don't listen to our own typing
StopHotKey();
// left click has selected the thing we want to paste, and placed the cursor
// so all we have to do is type
int keyDelayMS = Properties.Settings.Default.KeyDelayMS;
Expand All @@ -250,6 +199,7 @@ private void _hook_MouseUp(object sender, MouseEventArgs e)
}
break;
}
StartHotKey();
}
});
break;
Expand All @@ -272,14 +222,51 @@ IList<string> ProcessSendKeys(string raw)
}
return list;
}
void StartHotKey()
{
var hotkeyLetter = Properties.Settings.Default.HotKey;
if (!string.IsNullOrEmpty(hotkeyLetter))
{
try
{
Keys HotKey = (Keys)Enum.Parse(typeof(Keys), hotkeyLetter);
_usingHotKey = HotKeyManager.RegisterHotKey(HotKey, (KeyModifiers)Properties.Settings.Default.HotKeyModifier);
HotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyManager_HotKeyPressed);
}
catch(Exception e)
{
MessageBox.Show("Could not register hot key: " + e.Message);
}
}
}
void StopHotKey()
{
if(_usingHotKey.HasValue)
{
HotKeyManager.HotKeyPressed -= HotKeyManager_HotKeyPressed;
HotKeyManager.UnregisterHotKey(_usingHotKey.Value);
}
_usingHotKey = null;
}
void Settings(object sender, EventArgs e)
{
if (!_settingsOpen)
{
_settingsOpen = true;
}
StopHotKey();
var settings = new SettingsForm();
settings.ShowDialog();
StartHotKey();
}

void Exit(object sender, EventArgs e)
{
EndTrack();
// Hide tray icon, otherwise it will remain shown until user mouses over it
_notify.Visible = false;
_notify.Dispose();

StopHotKey();
Application.Exit();
}
}
Expand Down
6 changes: 3 additions & 3 deletions Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ClickPaste")]
[assembly: AssemblyCopyright("Copyright © 2020 Collective Software, LLC")]
[assembly: AssemblyCopyright("Copyright © 2023 Collective Software, LLC")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Expand All @@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]
24 changes: 24 additions & 0 deletions Properties/Settings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Properties/Settings.settings
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,11 @@
<Setting Name="KeyDelayMS" Type="System.Int32" Scope="User">
<Value Profile="(Default)">5</Value>
</Setting>
<Setting Name="HotKey" Type="System.String" Scope="User">
<Value Profile="(Default)">V</Value>
</Setting>
<Setting Name="HotKeyModifier" Type="System.Int32" Scope="User">
<Value Profile="(Default)">3</Value>
</Setting>
</Settings>
</SettingsFile>
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# ClickPaste
Windows 10 notification area app in C# that can paste clipboard contents as keystrokes to whatever location you click.
Windows 10/11 notification area app in C# that can paste clipboard contents as keystrokes to whatever location you click.

## Starting

Expand All @@ -23,7 +23,18 @@ First of course, you need to have some text in your clipboard. Then:
3. Your clipboard contents should be typed as keystrokes onto the window you selected:

![Your clipboard is typed as keystrokes onto the window you selected](./doc/Pasted.png)


## Settings

Right-click the notification icon and select Settings.

* You can change between key typing modes,
* Set how much delay there is between keystrokes,
* Configure what "hot key" combination will invoke the target selector to pick a paste location. Clear the key textbox with delete or backspace if you wish to have *no* hotkey.

![How to change settings](./doc/RightClickForSettings.png)
![Settings dialog](./doc/Settings.png)

## Stopping

* Right-click the notification icon and select Exit.
Expand Down
Loading

0 comments on commit 5e58654

Please sign in to comment.