
Introduction
When I first began developing, I was especially annoyed by the lack of a © symbol on the keyboard. In fact, there were several symbols that I commonly used – but found frustratingly hard to use quickly. This application presents the solution I eventually created for this problem.
When I wrote this, I first created a visual interface and then plugged code into the background to make it work – thus I am presenting this article with this format.
Goals for the Application
The basic goals for the application are as follows:
- Try to replicate operating system look-and-feel.
- Implement hands-on-keyboard functionality. This means registering a HotKey for the application on the keyboard,
and using the number keys on the keyboard to select a symbol, close the application, and insert the symbol into your document, code, etc.
- Allow the user to customize the symbols.
- Automatically run the application when the user logs in so that one is spared the pain of starting it all the time.
- Keep a notification icon in the tasktray to allow the user to close the application.
This is the summary of a single use of the application:

Creating the Visual Interface
Command Links & emulating OP look-and-feel

These controls can be found in the Microsoft API Code Pack. Simply download them and place them in your toolbox. The gray bar along the bottom of the application consists of two panels with dock set to bottom. The colors were obtained by using Paint's 'pick a color' tool on a screenshot of IE9's download dialog.
The Settings dialog

In the settings dialog, the user can change what's in their symbol collection and the order they are in. They can also set the application to start when they login.
The code here is pretty straightforward. Perhaps the only part that can be commented on is moving the symbols up and down:
private void btnUp_Click(object sender, EventArgs e)
{
if (lstCollection.SelectedIndex != 0 && lstCollection.SelectedIndex != -1)
{
int point = lstCollection.SelectedIndex;
char s = (char)lstCollection.SelectedItem;
lstCollection.Items.RemoveAt(point);
lstCollection.Items.Insert(point - 1, s);
lstCollection.SelectedIndex = point - 1;
}
}
private void btnDown_Click(object sender, EventArgs e)
{
if (lstCollection.SelectedIndex != lstCollection.Items.Count - 1 &&
lstCollection.SelectedIndex != -1)
{
int point = lstCollection.SelectedIndex;
char s = (char)lstCollection.SelectedItem;
lstCollection.Items.RemoveAt(point);
lstCollection.Items.Insert(point + 1, s);
lstCollection.SelectedIndex = point + 1;
}
}The Tasktray Icon

This is fairly basic. This code is in the form's constructor.
icon.Icon = Properties.Resources.Symbol;
icon.Visible = true;
icon.ContextMenu = new ContextMenu();
icon.ContextMenu.MenuItems.Add("Show Dialog", ShwDlg);
icon.ContextMenu.MenuItems.Add("About", Abt);
icon.ContextMenu.MenuItems.Add("-");
icon.ContextMenu.MenuItems.Add("Exit", Exit);
icon.MouseUp += new MouseEventHandler(icon_MouseUp);
Note how a line break can be created by inserting '-' as a menuitem. A word of warning about using NotifyIcon is that when you close the application,
the Icon may hover around in your tasktray until you mouseover. This issue can be resolved by this override:
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing && !AppClosingDown)
{
e.Cancel = true;
btnCancel_Click(this, e);
}
else
{
icon.Visible = false;
icon.Dispose();
}
base.OnFormClosing(e);
}
Also, note how the form rejects the close call and hides instead if the user clicks the form's close button.
Loading the RadioButtons and handling the Main Form

Loading the radiobuttons is pretty straightforward. Here is the basic code run in the form's constructor. The radiobuttons were prexistent from Designer.
int foundsofar = 0;
foreach (Control c in this.Controls)
{
if (c.ToString().Contains("System.Windows.Forms.RadioButton"))
{
c.Click += new EventHandler(c_Click);
c.Text = Properties.Settings.Default.Symbols[foundsofar].ToString();
if (c.Text == "π")
c.Font = new Font("Arial Rounded MT Bold", c.Font.Size);
++foundsofar;
}
}
Then, the code for c_Click is this:
void c_Click(object sender, EventArgs e)
{
tmAnim.Start();
}
And the timer's tick event is this:
private void tmAnim_Tick(object sender, EventArgs e)
{
if (this.Height != 318)
{
this.Top -= 5;
this.Height += 10;
}
else
{
tmAnim.Stop();
}
}
Thus, when the user clicks any of the radiobuttons, the form slides out and looks like the picture above.
Creating Action
That's the visual interface covered! Now I will summarize how to make the application work.
Starting when the User logs in
This requires some Registry editing. This article was my inspiration.
First, you will need these values:
private const string RegistryPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
private const string KeyName = "JohnsonSymbolInserter";
You can change KeyName to whatever you wish, of course. Here is the basic code summary:
RegistryKey rk = Registry.CurrentUser.OpenSubKey(RegistryPath);
bool isRunningOnLogin = (rk.GetValue(KeyName) != null);
RegistryKey rk = Registry.CurrentUser.OpenSubKey(RegistryPath, true);
rk.SetValue(KeyName, Application.ExecutablePath);
RegistryKey rk = Registry.CurrentUser.OpenSubKey(registryPath, true);
rk.DeleteValue(KeyName);
RegistryKey rk = Registry.CurrentUser.OpenSubKey(registryPath, true);
if (rk.GetValue(KeyName) == null)
rk.SetValue(KeyName, Application.ExecutablePath);
else
rk.DeleteValue(KeyName);
Registering a HotKey
This article (again!) was my source for implementing
HotKeys. Basically, we need these external calls:
[DllImport("user32.dll")]
private static extern int RegisterHotKey(IntPtr hwnd, int id, uint mod, Keys k);
[DllImport("user32.dll")]
private static extern int UnregisterHotKey(IntPtr hwnd, int id);
And we will also need these constants: (You can also register HotKeys for Ctrl, Alt, etc. See here
for more info on RegisterHotKey.)
private const int ID = 0xFDAE;
private const int WindowsKey = 0x0008;
You then override OnHandleCreated, OnHandleDestroyed, and WndProc as below:
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
try
{
RegisterHotKey(this.Handle, ID, WindowsKey, Keys.S);
}
catch
{
MessageBox.Show("The application failed to register the Windows+S HotKey. " +
"The application will now exit.", "Register Failed",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
Application.Exit();
}
}
protected override void OnHandleDestroyed(EventArgs e)
{
base.OnHandleDestroyed(e);
try
{
UnregisterHotKey(this.Handle, ID);
}
catch
{
}
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312)
{
this.ShowForm();
}
base.WndProc(ref m);
}
Sending Symbols - Method One
To insert a symbol is the main objective of this application. How will we go about it?
The easiest method to implement is to copy your selected symbol to the clipboard, like this.
this.HideForm();
string selected = "";
foreach (Control c in this.Controls)
{
if (c.ToString().Contains("System.Windows.Forms.RadioButton"))
{
if (((RadioButton)c).Checked)
{
selected = c.Text;
((RadioButton)c).Checked = false;
}
}
}
Clipboard.SetText(selected);
Sending Symbols - Method Two
However, having to paste the symbol yourself all the time becomes tiresome. I know this because I was initially using a much-less-polished version of this application;
pulling it up one time, I decided I would re-write it and publish it here on CodeProject.
So, I've also used SendKeys in this Application.
SendKeys can be used to send strings between applications as keyboard input. For example,
SendKeys.Send("Hello World!");
In this example, the application with current focus would receive simulated keyboard input as if someone had just typed intstaneously "Hello World!".
The avantage of simulated keyboard input is that the keyboard input can be anything, even a symbol. This method is slightly more work to implement - it requires
a few more external calls - but the result is far easier to use.
Because SendKeys sends keystrokes to the currently active window, if we simply
call SendKeys while our application is focused, the symbol will simply be sent to our application.
We will use these external calls to solve this issue.
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hwnd);
When the form is shown, the application grabs the previously active application, as you can see in ShowForm()
private void ShowForm()
{
previousApp = GetForegroundWindow();
this.Opacity = 1;
this.Show();
SetForegroundWindow(this.Handle);
if (!btnCancel.Focused)
btnCancel.Focus();
}
When the user clicks the "Insert Now" button, this is what happens...
this.HideForm();
string selected = "";
foreach (Control c in this.Controls)
{
if (c.ToString().Contains("System.Windows.Forms.RadioButton"))
{
if (((RadioButton)c).Checked)
{
selected = c.Text;
((RadioButton)c).Checked = false;
}
}
}
try
{
SetForegroundWindow(previousApp);
SendKeys.Send(selected);
}
catch
{
MessageBox.Show("The symbol could not be sent to your document.");
this.ShowForm();
}
...and you should be able to see how the process works. Another look at the flowchart diagram should help explain:

Method Three - An Improvement on Method Two
I promised that you would be able to insert symbols without your fingers leaving the keyboard. Implementing this would save
having to stop typing, use your mouse/keypad, and then resume typing.
Because there are ten symbols available, we can use the number keys to select our desired symbol, with 0 respresenting 10.
When this application displays itself, the control which automatically receives focus is the Cancel button (Take a look above at the code for ShowForm()). All we need to do is add a KeyUp event handler to this control:
private void btnCancel_KeyUp(object sender, KeyEventArgs e)
{
int j = 0;
if (e.KeyData.ToString().Length == 2)
{
if (int.TryParse(e.KeyData.ToString().Substring(1, 1), out j))
{
if (j == 0)
j = 10;
this.HideForm();
try
{
SetForegroundWindow(previousApp);
SendKeys.Send(Properties.Settings.Default.Symbols[j - 1].ToString());
}
catch
{
MessageBox.Show("The symbol could not be sent to your document.");
this.ShowForm();
}
}
}
}
Conclusion
I hope you enjoyed this article and that at least a few people enjoy using it. Happy Typing!
History
- 9/03/2012
Made a few polishes to the article text
- 4/08/2012 Realized that the "Edit Symbol" dialog was displaying its icon in the taskbar. Removed that.
- 31/07/2012 Fixed a bug where the cancel button was not being focussed. Also fixed a bug where the radiobuttons were not being cleared.
- 30/07/2012 Initial Public Release