Picking up keystrokes Ctrl-Alt-Q - c#

What's the 'correct/best' way to pick up a keystroke combination? The keys in question are Ctrl+Alt+Q, I want the user to press them all at the same time, at which point I am going to open a window. I'm currently doing it by have an array and then catching each keystroke individually, but my results are inconsistent, especially on a particular make of Dell laptop/windows 7 combination, but that's another story.
So after spending five minutes with google, this is just a rough version after looking at the msdn, but as I stated earlier is this version (untested) the correct/best way of doing it?
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
const int WM_SYSKEYDOWN = 0x104;
if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
{
switch(keyData)
{
case Keys.Control | Keys.Alt | Keys.Q:
this.Parent.Text="<CTRL> + Alt + Q Captured";
break;
}
}
return base.ProcessCmdKey(ref msg,keyData);
}

Ignore msg.Msg, only look at keyData. And return true without calling base if you use the keystroke. Which simplifies it to:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.Alt | Keys.Q)) {
this.Parent.Text="<CTRL> + Alt + Q Captured";
return true;
}
return base.ProcessCmdKey(ref msg,keyData);
}
This should probably be an override of the form's method so you don't depend on the control having the focus. You'd use this.Text instead.

Yes, that's how I would do it if I wish to listen for key events globally.
But if you are interested in keyboard inputs ONLY when your program is the focused window (in the front on Windows), you might want to use the KeyDown event:
private void textBox1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
// your code goes here
}

According to the documentation for System.Windows.Forms.Keys, you cannot use a bitwise OR to check for key combinations. The documentation states: "For finer control, use the Win32 API functions GetKeyState, GetAsyncKeyState, or GetKeyboardState defined in user32.dll...". But it appears that Shift, Alt and Control can be used as bitwise flags.

For those who wants open a windows or make visible/invisible with the combination of three keys (with two modifiers) by the light of #Hans Passant i found finally an answer to my problem. I was beware of | operand, putting instead && operand which was not working. It can be assigned to WFA properties to Keydown
private void ShowHidden_Click(object sender, KeyEventArgs e)
{
if (e.KeyData == (Keys.Control | Keys.Alt | Keys.M) )
{
OldBisProdId.Visible = true;
OldGanProdId.Visible = true;
}
if (e.KeyData == (Keys.Control | Keys.Alt | Keys.C))
{
OldBisProdId.Visible = false;
OldGanProdId.Visible = false;
}
}

Related

How to override natural navigation in c# winforms

Domain understanding
I'm making an application for dentists and at one point I have to show the teeth of the patient and allow the dentist to register information about several points around each tooth.
To make the application dynamic I create the teeth depending on the patient (some have more or fewer teeth).
So the mouth has a number of teeth and depending on the settings each tooth has a number of measurement points.
The dentists register the points in different orders depending on preference (set in settings). Some register all points on a tooth and then move to the next, others register all points along the front of all teeth and then all the points along the back of the teeth.
The issue
As I create each tooth and add the measurement points to it, the natural tab order is: all the points on one tooth, move to next tooth [repeat].
I need to control this in a different way.
I need to be able to navigate (tab) to a control in another usercontrol and then return later for the rest of the points.
Both tab and the arrow keys cause navigation, so I have to deal with both (well all navigation, but these are the ones I've discovered to far)
Trial and error
I tried to override OnKeyUp/Down/Press and handle the events for the key press, but to no avail.
In stead I get a double effect; both my navigation AND the natural navigation.
What is the smartest and easiest way to be in complete control of the navigation?
For Tab there is a ContainerControl function called ProcessTabKey. This is where the natural navigation for Tab happens. If you override this you can provide our own navigation: (or just return true and do it somewhere else)
protected override bool ProcessTabKey(bool forward)
{
return forward ? this.NextPoint() : this.PreviousPoint();
}
As for the arrow-navigation, I've found that to be a little trickier. There are a number of overridable functions that register key presses.
I think the best one is ProcessCmdKey. This function must return "true if the character was processed by the control; otherwise, false":
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Right)
{
this.NextField();
return true;
}
if (keyData == Keys.Left)
{
this.PreviousField();
return true;
}
if (keyData == Keys.Down) return true;
if (keyData == Keys.Up) return true;
return base.ProcessCmdKey(ref msg, keyData);
}
This will cause my own navigation to happen and let the framework know 'I already dealt with this' (or I could just return true and handle it somewhere else). Any other 'command' keys can be handled the same (like Tab), however this does not handle the modifiers!
Both Tab and the Arrow keys navigate if Shift is pressed. If I want to handle all my navigation here it should look something like this:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
switch (keyData)
{
case Keys.Right:
case Keys.Right|Keys.Shift:
case Keys.Enter:
// move to next field
this.NextField();
return true;
case Keys.Left:
case Keys.Left|Keys.Shift:
// move to previous field
this.PreviousField();
return true;
case Keys.Down:
case Keys.Down|Keys.Shift:
case Keys.Up:
case Keys.Up|Keys.Shift:
// disable native navigation
return true;
case Keys.Tab:
// move to next point
return this.NextPoint();
case Keys.Tab|Keys.Shift:
// move to previous point
return this.PreviousPoint();
}
return base.ProcessCmdKey(ref msg, keyData);
}
Handling Tab in ProcessCmdKey negates the need to override ProcessTabKey .

How can i fix this Esc Key error?

I have this chunk of code in my Notepad clone program, it is to track my carat location in my RichTextBox and has been working fine for me.
private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
Curpos();
}
private static int EM_LINEINDEX = 0xbb;
[DllImport("user32.dll")]
extern static int SendMessage(IntPtr hwnd, int message, int wparam, int lparam);
private void Curpos()
{
{
int line, col, index;
index = richTextBox1.SelectionStart;
line = richTextBox1.GetLineFromCharIndex(index);
col = index - SendMessage(richTextBox1.Handle, EM_LINEINDEX, -1, 0);
Lblcurpos.Text = "Line: " + (++line).ToString() + ", Column:" + (++col).ToString();
}
}
It has been working perfectly for me, until i added some code so that i could close my program with the Esc Key.
Here is the code for my Esc Key:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
this.Close();
}
}
EDIT: This is where it has the problem:
index = richTextBox1.SelectionStart;
When i am doing this, i can run my program fine, type text in my RichTextBox and everything but when i press the Esc Key it says:
Cannot Access disposed object
Object name: 'RichTextBox'
Then is says:
Trouble Shooting Tips:
Make sure you have not released a resource before attempting to use this.
Get general help for this exception
Any ideas on what i can do? I tried to use the shortcut keys but it doesn't have a Esc key you can use for the shortcut. Any help with either doing a different shortcut or a fix to this problem, i would like it!!
Try:
Application.Exit();
instead of
this.Close();
From MSDN:
Application.Exit
Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed. This is the code to use if you are have called Application.Run (WinForms applications), this method stops all running message loops on all threads and closes all windows of the application.
Do note that Application.Exit() is not a substitute for this.Close(). Exit() terminates the entire application, Close() just close the form.
There are better ways to avoid accidents like this. When you handle shortcut keystrokes like you did, you should always set e.Handled and e.SuppressKeyPress to true so the keystroke will be completely dismissed and not generate any additional events. Like the one that bombed your code.
By far the best way is to use the dedicated method for this in Winforms, ProcessCmdKey(). It implements true shortcut keystroke behavior, the KeyPreview property is a VB6 compatibility feature which is close but not equivalent. Make it look like this:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.Escape) {
this.Close();
return true; // Used, don't process any further
}
return base.ProcessCmdKey(ref msg, keyData);
}

How to Disable Shortkeys on ComboBox In C# using Windows Application?

In Main Form i have Short Cut Keys(ctrl + S ) for saving the data in DataBase. For combobox (ctrl + Alphabets) is the default Operation. How can I disable shortcut keys for Combobox?
UPDATE:
On keyPress event we can Do this
if (ModifierKeys == Keys.Control)
{
e.Handled = true;
}
You can try overriding ProcessCmdKey method of the Main Form:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
const int WM_KEYDOWN = 0x100;
if (keyData == (Keys.Control | Keys.S)) {
if (msg.Msg == WM_KEYDOWN)
MySaveDataToDatabase(); // <- Do your save command
return true; // <- Stop processing the WM_KeyDown message for Ctrl + S (and shortcut as well)
}
// All other key messages process as usual
return base.ProcessCmdKey(ref msg, keyData);
}
I get the feeling that your problem is actually that the combobox is getting keypresses before your form. Be sure to set the Form's KeyPreview property to true if you want to handle keypresses before your controls.
More information about the KeyPreview property:
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview(v=vs.100).aspx
If you are getting issues like overriding the F4 key (which in a combobox shows all options available by default), note the bit about setting the KeyPressEventArgs.Handled property in the form's KeyPress event handler to true.
For most hot keys you can override the PreviewKeyDown event specify what to allow or not, eg:
void comboBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
var keysToIgnore = new []{
Keys.S,
Keys.X,
Keys.F4,
Keys.Space,
}.ToList();
if (keysToIgnore.Contains(e.KeyCode)) {
if(e.Modifiers == Keys.Alt) ; // Do stuff (or don't) here
}
}
There's all sorts of ways you can structure your logic depending on what your actual use case is but hopefully you get the idea.
You might find some hot key combinations aren't possible to disable this way, in which case you'll need to use the Win32API: UnregisterHotKey. More info here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646327%28v=vs.85%29.aspx
The main advantage of using the PreviewKeyDown event is you can also easily replace behaviour instead of just disabling it. The main advantage of using UnregisterHotKey is it operates at a lower level and is a far more robust and reliable way of disabling hot keys.
EDIT:
If you need to get a contiguous range of values you can try something like:
int keyCode = (int) (e.KeyCode);
if(keyCode >= (int)(Keys.A) && keyCode <= (int)(Keys.Z)) { /* do stuff */ }
but again, an ideal solution really depends on the specifics of your use case. There's no generic 'right answer'.

C# Key hooks key down event

Creating a key hook so that when the combination is pressed, the application will open again.
I have looked into various ways of doing it, however I do not know what the input combination will be unlike this example:
if (e.KeyCode == Keys.C && e.Modifiers == Keys.Control && e.Modifiers == Keys.Shift)
{
//Do work
}
else if (e.KeyCode == Keys.V && e.Modifiers == Keys.Control)
{
//Paste
}
Our input combination is from the user, where they select which combination they want to input from a combo box.
public void KeyboardHooks_OnKeyPress(object sender, KeyPressArgs e)
{
//The first input
if (LastKey != Keys.None)
{
Keys combinationOne = (Keys)cmbCombinationOne.SelectedValue;
Keys combinationTwo = (Keys)cmbCombinationTwo.SelectedValue;
}
LastKey = e.Key;
MessageBox.Show("KeyPressed");
}
Not sure on how to go about setting our values to the combo box's
From your code snippets it looks like you're going the route of WinForms key events. If the user does a key combination in your application and you do this 'open' of something else, you're on the right path. You'll just need to make it dynamic to see if the user-defined items are pressed.
So when you save the user settings, convert it to a keycode so you can do the generic
if(e.KeyCode == Settings.FirstModKey && e.KeyCode == Settings.SecondModKey && e.KeyCode == Settings.FirstKey)
You'll need to consider the multiple scenarios, the modifiers Shift, Alt and Control could be none, one, two, or all three. In my above, you could have FirstModKey and SecondModKey the same value if the user chose Ctrl only, or they could be handling if they did Ctrl and Shift both. Then FirstKey is the non-mod key, like 'A'.
the application will open again
However, from the quote it sounds like you want a global hook, that wherever the user is in any application, with yours not running, you want to listen and do work if its your keycode. You need to look into a service and low level hooks. This can come close to keylogging and you need to be careful who your audience is, security risks and concerns that you might be breaking compliance.
{
//The first input
if (LastKey != Keys.None)
{
int combination1 = (int)Enum.Parse(typeof(Keys), cmbCombinationOne.SelectedValue.ToString());
int combination2 = (int)Enum.Parse(typeof(Keys), cmbCombinationTwo.SelectedValue.ToString());
int LastKeyPress = (int)Enum.Parse(typeof(Keys), LastKey.ToString());
ThisKey = e.Key;
if (combination1 == LastKeyPress && combination2 == Convert.ToInt32(ThisKey))
{
MessageBox.Show("Key pressed");
}
}
LastKey = e.Key;
}
This worked with my original existing code

Hotkeys override

Difficult question. The answer is probably no, if all I found in the Intertubes is right, but it is worth a try. I need to override the Ctrl + Shift + Esc and the Ctrl + Esc combinations. It would be good to be able to override the Win key combinations, but I have a low level hook that does such, I only wish I didn't need it. If I can manage to block the start menu and the task manager entirely by policy, the overrides will no longer be needed but I couldn't find the correct policy to do so.
You can override Ctrl + Esc (I just tried in AutoHotkey, it works), but not Ctrl + Shift + Esc, no more than Ctrl + Alt + Del.
So using policies is probably the way to go... No experience in this field, I fear.
In case someone comes here looking for a non-AutoHotKey, here is a c# way.
It is possible to do this using a keyboard hook. A good hook class for this can be found on this CodeProject Article
Using the below code will prevent the WIN+LEFT or WIN+RIGHT from occurring. You can use this to override whichever keys you'd like.
This will even override hotkeys which you added via RegisterHotKey Win API.
Once you have those classes in your project you can add handlers to the static HookManager class like below.
//It's worth noting here that if you subscribe to the Key_Press event then it will break the international accent keys.
HookManager.KeyPress += HookManager_KeyPress;
HookManager.KeyDown += HookManager_KeyDown;
HookManager.KeyUp += HookManager_KeyUp;
You can also add mouse events, but for simplicity I'm just showing the keyboard hook.
I've also created a generic list so that I know which keys are currently down and I remove those keys from the list on the KeyUp event.
public static List<Keys> keysDown = new List<Keys>();
private static void HookManager_KeyDown(object sender, KeyEventArgs e)
{
//Used for overriding the Windows default hotkeys
if(keysDown.Contains(e.KeyCode) == false)
{
keysDown.Add(e.KeyCode);
}
if (e.KeyCode == Keys.Right && WIN())
{
e.Handled = true;
//Do what you want when this key combination is pressed
}
else if (e.KeyCode == Keys.Left && WIN())
{
e.Handled = true;
//Do what you want when this key combination is pressed
}
}
private static void HookManager_KeyUp(object sender, KeyEventArgs e)
{
//Used for overriding the Windows default hotkeys
while(keysDown.Contains(e.KeyCode))
{
keysDown.Remove(e.KeyCode);
}
}
private static void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
//Used for overriding the Windows default hotkeys
}
public static bool CTRL()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.LControlKey) ||
keysDown.Contains(Keys.RControlKey) ||
keysDown.Contains(Keys.Control) ||
keysDown.Contains(Keys.ControlKey))
{
return true;
}
else
{
return false;
}
}
public static bool SHIFT()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.LShiftKey) ||
keysDown.Contains(Keys.RShiftKey) ||
keysDown.Contains(Keys.Shift) ||
keysDown.Contains(Keys.ShiftKey))
{
return true;
}
else
{
return false;
}
}
public static bool WIN()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.LWin) ||
keysDown.Contains(Keys.RWin))
{
return true;
}
else
{
return false;
}
}
public static bool ALT()
{
//return keysDown.Contains(Keys.LShiftKey)
if (keysDown.Contains(Keys.Alt))
{
return true;
}
else
{
return false;
}
}
So you need do override Hotkeys on your application?
Then the answer is probably yes, how?
No idea, but if this(http://www.inchwest.com/mapkeyboard.aspx) program can, so can you

Categories

Resources