This is a coincidence, I'm working on an article to be published on CP on a "lightweight" custom hotkey utility (lightweight compared to using a GlobalHook in C#). The version in-progress has many more features than I'll show here including the ability to disable and restore any given macro (or delete it), to allow or block key-repeat when the same keys are held down, defining key macros for a single control, all controls of the same type, or all controls on a form, etc.
Here's a simple proof-of-concept version that makes the assumptions:
1. the programmer will want to override key behavior for specific controls: will want over-rides only in certain elements of the UI.
2. specific to your question: will use single-keys only (no modifiers pressed)
3. the code you want to execute when a key is pressed can be expressed with an Action that has no parameters and returns no value.
4. example:
private Dictionary<keys,> dctKeysToAction;
private List<control> KeyOverRideControls;
private Action KeyAction;
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (KeyOverRideControls.Contains(ActiveControl))
{
if (dctKeysToAction.TryGetValue(keyData, out KeyAction))
{
KeyAction();
return true;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void Form1_Load(object sender, EventArgs e)
{
KeyOverRideControls = new List<control>
{
dateTimePicker1,
userControl11
};
dctKeysToAction = new Dictionary<keys,>
{
{
Keys.E, () =>
{
Console.WriteLine("E");
}
},
Keys.B, () =>
{
if (ActiveControl == dateTimePicker1)
{
dateTimePicker1.Value = DateTime.Now;
}
else
{
MessageBox.Show("B in userControl1");
}
}
};
}</control></control>
Discussion:
0. since we use the unique Keys value as the Key in the Dictionary that maps to the Action, I believe this is performant enough for this scenario.
1. Since the 'KeyData value (a Keys enum value) received as a parameter in the ProcessCmdKey override is unique for any/all keys held down, we do not need to check to see if control/alt/shift keys are down.
2. The Form here has a UserControl instance, 'userControl1, and a DateTimePicker, 'dateTimePicker1 sited on the Form at design-time: only those Controls will handle the modified key-evaluation behavior enforced by the ProcessCmdKey override.
3. Since the UserControl ... unlike a Panel, for example ... will "eat first" all keystrokes: if you have a TextBox inside the UserControl, and the 'b/B key is pressed here: that key will not be received by the UserControl ... unless you modified the code in ProcessCmdKey to allow it to "go through."
4. what is shown here just "scratches the surface" of what
can be done.