This is not a duplicate. Many similar threads discuss capturing a combination involving a modifier key.
I need to get something triggered when a shortcut key (a combination of Insert+Tab) is pressed from a control, say Button.
Catch:
This involves no modifier key like Alt or Shift for which .NET has built in checking.
This has Tab key which is not caught so easily.
What I tried and came close:
1) KeyDown Event but doesnt capture Tabs..
[DllImport("user32.dll")]
public static extern int GetKeyboardState(byte[] keystate);
static void form_KeyDown(object sender, KeyEventArgs e)
{
if (!(((Form)sender).ActiveControl is Button))
return;
byte[] keys = new byte[255];
GetKeyboardState(keys);
if (keys[(int)Keys.Insert] == 129 && keys[(int)Keys.Tab] == 129)
{
// doesn't work
}
if (keys[(int)Keys.Insert] == 129 && keys[(int)Keys.J] == 129)
{
// works, since here this doesnt involve Tab
}
}
This works with regular combinations, doesnt fire along with Tab.
2) KeyPreview Event which captures Tab key, but I do not know how to get a combination of keys pressed
static void form_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (!(((Form)sender).ActiveControl is Button))
return;
if (e.KeyCode == Keys.Tab)
//works
if (e.KeyCode == Keys.Insert && e.KeyCode == Keys.Tab)
//doesn't hit.
}
Requirement:
1) I am not registering the event from Form class. Instead I have a utility class which creates all required events (along with other shortcuts). I just pass the instance of form to a static function. So I am quite unsure how I should utilize the various key overriding calls. Here is how I do it:
public frmLogin()
{
InitializeComponent();
Utility.SetFormEvents(this);
}
static void SetFormEvents(Form f){
//foreach control...........
}
But I can give up on this..
Thanks..
Tab is considered a command key, you don't actually get notified of it being pressed directly. You could PInvoke the GetKeyState method, but I think it's just easier to recognize that tab is a command key (and override ProcessCmdKey) and keep track of whether the Insert key is up or down. For example:
static bool insertPressed;
static bool tabPressed;
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(keyData == Keys.Tab)
{
tabPressed = true;
CheckForTabAndInsert();
}
return base.ProcessCmdKey(ref msg, keyData);
}
static void form_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Insert)
{
insertPressed = true;
CheckForTabAndInsert();
insertPressed = false;
}
}
static void form_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Insert) insertPressed = false;
}
The drawback is that you only really get a KeyPress for tab with ProcessCmdKey, so you can only really support Insert+Tab (not Tab+Insert). This is because Tab is used to switch context from one control to another. Depending on your situation (i.e. in the context of a text box), you could make use of the AcceptTab property to possibly just use KeyUp and KeyDown... But, from what you posted, that doesn't appear to be the case.
Related
I'm asking the question already asked (and even answered) here:
Why are some textboxes not accepting Control + A shortcut to select all by default
But that answer doesn't work for me. I have this code:
public class LoginForm : Form
{
private TextBox tbUsername;
public LoginForm()
{
tbUsername = new TextBox();
tbUsername.ShortcutsEnabled = true;
tbUsername.Multiline = false;
Controls.Add(tbUsername);
}
}
The textbox shows up, I can write on it, I can cut, copy and paste text on it without any problems.
But when I try to press Ctrl+A I only hear a "bling" similar to the bling that you hear if you try to erase text from an empty textbox (try it with your browser's address bar).
Like other answers indicate, Application.EnableVisualStyles() should be called. Also the TextBox.ShortcutsEnabled should be set to true. But if your TextBox.Multiline is enabled then Ctrl+A will not work (see MSDN documentation). Using RichTextBox instead will get around the problem.
Just create a keydown event for that TextBox in question and include this code:
private void tbUsername_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.A)
{
if (sender != null)
((TextBox)sender).SelectAll();
}
}
You could always override the process command keys to get the desired result
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
var keyCode = (Keys) (msg.WParam.ToInt32() &
Convert.ToInt32(Keys.KeyCode));
if ((msg.Msg == WM_KEYDOWN && keyCode == Keys.A)
&& (ModifierKeys == Keys.Control)
&& tbUsername.Focused)
{
tbUsername.SelectAll();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
Quick answer is that if you are using multiline true you have to explicitly call the select all.
private void tbUsername_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.A && e.Control)
{
tbUsername.SelectAll();
}
}
This happened to me once too, I'm assuming you removed the call for Application.EnableVisualStyles(); from your program? Add it back to the Main() function and everything should work fine.
Textbox has a method SelectAll() and worked well for me. (.net 4.5)
No need to handle WM_KEYDOWN! I know that most examples here (and CodeProject and many other places) all say there is, but it does not cure the beep that results whenever a WM_CHAR arises that is not handled.
Instead, try this:
LRESULT CALLBACK Edit_Prc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
if(msg==WM_CHAR&&wParam==1){SendMessage(hwnd,EM_SETSEL,0,-1); return 1;}
else return CallWindowProc((void*)WPA,hwnd,msg,wParam,lParam);
}
Remember to subclass the EDIT control to this Edit_Prc() using WPA=SetWindowLong(...) where WPA is the window procedure address for CallWindowProc(...)
I figured this out by experiment, after finding that all the answers I found online insisted on handling WM_KEYDOWN, using GetKeyState(), and ended up with bigger code that failed to stop that annoying beep!
While this answer doesn't deal with dotnet, in cases like this it's usually better to cut to the chase and solve it rather than agonise over which version of a large code wrapper system may or may not do it for you, especially if you want to avoid the risk of fighting against inbuilt behaviour.
Throwing in my two cents. Calling this under keypress is just another option.
private void TxtBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '\x1')
{
TxtBox.SelectAll();
e.Handled = true;
}
}
This is my code, it is working fine
private void mainSimPlus_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
if (e.Control == true && e.KeyCode == Keys.A)
{
if (SelectAllTextBox(txt1))
return;
if (SelectAllTextBox(txt2))
return;
}
}
private bool SelectAllTextBox(TextBox txt)
{
if (txt.Focused)
{
txt.SelectAll();
return true;
}
else
return false;
}
I want to give a textbox focus when the user starts typing anywhere in my app.
My page inherits from LayoutAwarePage.
Can this be achieved ?
Edit:
I got this code:
// In constructor
Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
// Somewhere else in class
void CoreWindow_KeyDown(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs args)
{
this.setSearchboxFocus((int)args.VirtualKey);
}
private void setSearchboxFocus(int keyCode)
{
if (keyCode == 38)
return;
if (keyCode == 40)
return;
if (this.searchBox.FocusState == Windows.UI.Xaml.FocusState.Unfocused)
{
this.searchBox.Text = "";
this.searchBox.Focus(Windows.UI.Xaml.FocusState.Keyboard);
}
}
For anyone reading this thread in the future, it is because of the webview. I asked a similar question on the msdn forum here. As of Windows 8.1, the webview is implemented as a separate window and completely steals all keyboard input when it has focus without passing any of it up to the controlling application. If you are able to change the HTML in the website being called it may be possible to use javascript listeners to pass events between the application and webview, but I did not test this myself. Unfortunately there does not seem to be any other workaround at this time.
You can handle the KeyDown/KeyUp event for the whole page by subscribing to these events
Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
Window.Current.CoreWindow.KeyUp += CoreWindow_KeyUp
This might help
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
textBox1.Focus();//sets focus to textBox1 when user presses a key on form
}
How about something like this?
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (!textBox1.Focused)
{
textBox1.Focus();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
How about, on the Windows.UI.Xaml.Controls.Page:
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
textBox1.Focus(Windows.UI.Xaml.FocusState.Keyboard);
base.OnKeyDown(e);
}
Basically, I want to be able to trigger an event when the ENTER key is pressed. I tried this already:
private void input_KeyDown(object sender, KeyEventArgs e)
{
if (e.Equals("{ENTER}"))
{
MessageBox.Show("Pressed enter.");
}
}
But the MessageBox never shows up. How can I do this?
Give this a shot...
private void input_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyData == Keys.Enter)
{
MessageBox.Show("Pressed enter.");
}
}
To add to #Willy David Jr answer: you also can use actual Key codes.
private void input_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyChar == 13)
{
MessageBox.Show("Pressed enter.");
}
}
You can actually just say
private void input_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
MessageBox.Show("Pressed enter.");
}
}
You can use the Keypress event. If you are just looking for the "Enter" keypress, then you probably don't care about modifier keys (such as Shift and/or Ctrl), which is why most would use KeyDown instead of Keypress. A second benefit is to answer the question that is almost always asked after implementing any of the other answers: "When I use the referenced code, why does pressing "Enter" cause a beep?" It is because the Keypress event needs to be handled. By using Keypress, you solve both in one place:
private void input_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
// Your logic here....
e.Handled = true; //Handle the Keypress event (suppress the Beep)
}
}
If your Form has AcceptButton defined, you won't be able to use KeyDown to capture the Enter.
What you should do is to catch it at the Form level. Add this code to the Form:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((this.ActiveControl == myTextBox) && (keyData == Keys.Return))
{
//do something
return true;
}
else
{
return base.ProcessCmdKey(ref msg, keyData);
}
}
You can also do this:
private void input_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode== Keys.Enter)
{
//Your business logic here.
}
}
The only difference with KeyCode vs KeyData is that KeyCode can detect modifiers combination with KeyCode (e.g. CTRL, Shift + A) which you don't need here.
Fast forward 2022, the following statement above is completely other way around.
"The only difference with KeyCode vs KeyData is that KeyCode can detect modifiers combination with KeyCode (e.g. CTRL, Shift + A) which you don't need here."
the KeyDown event e.KeyCode does not trigger Keys.Enter
I want to have the Esc key undo any changes to a textbox since it got focus.
I have the text, but can't seem to figure out how to capture the Esc key. Both KeyUp and KeyPressed don't seem to get it.
This should work. How are you handling the event?
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
MessageBox.Show("Escape Pressed");
}
}
Edit in reply to comment - Try overriding ProcessCmdKey instead:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Escape && myTextBox.Focused)
{
MessageBox.Show("Escape Pressed");
}
return base.ProcessCmdKey(ref msg, keyData);
}
is this what you're looking for?
string origStr = String.Empty;
private void txtOrig_Enter(object sender, EventArgs e)
{
origStr = txtOrig.Text;
}
private void txtOrig_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == Convert.ToChar(Keys.Escape))
{
txtOrig.Text = origStr;
}
}
Supposedly some keys are not considered "input keys" and so are not listened to by default. You need to handle PreviewKeyDown first to enable it.
myTextBox.PreviewKeyDown += (s, e) => {
if (e.KeyCode == Keys.Escape) {
e.IsInputKey = true;
Debug.Print("ESC should get handled now.");
}
};
However, results from testing say otherwise, so it may depend on framework version. For me, whether I do that or not, KeyDown does not get called for ESC, and whether I do that or not, KeyPress DOES get called for ESC. This is while a TextBox has focus, so it may also depend on the control.
I am creating a small game, the game is printed onto a panel on a windows form. Now i want to capture the keydown event to see if its the arrow keys that has been pressed, the problem however is that i can't seem to capture it.
Let me explain, on the form i have 4 buttons and various other controls and if the user for instance press one of the buttons (to trigger a game event) then the button has focus and i can't capture the movements with the arrow keys.
I tried something like
private void KeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Left)
{
game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.E);
game.DrawObjects(panel1.CreateGraphics());
}
else if (e.KeyCode == Keys.Right)
{
game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.W);
game.DrawObjects(panel1.CreateGraphics());
}
else if (e.KeyCode == Keys.Up)
{
game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.N);
game.DrawObjects(panel1.CreateGraphics());
}
else if (e.KeyCode == Keys.Down)
{
game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.S);
game.DrawObjects(panel1.CreateGraphics());
}
}
and then when the form key down event was pressed, i used this
private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
KeyDown(e);
}
I also added keydown for the buttons and the various other controls on the windows form, but i am not getting any response back. I have setup a breakpoint inside the function to see if it's being called, but that breakpoint never triggers?
Any ideas?
The most optimal was to have a general KeyDown event that triggers (regardless of what control that currently has focus) and then calls the KeyDown method.
Have you set the KeyPreview property of the form to true? That will cause the form to get a "first look" at key events.
Update: getting this to work properly when a Button has focus seems to be a bit tricky. The Button control intercepts the arrow key presses and moves focus to the next or previous control in the tab order in a manner so that the KeyDown, KeyUp and KeyPress events are not raised. However, the PreviewKeyDown event is raised, so that can be used:
private void Form_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = ProcessKeyDown(e.KeyCode);
}
// event handler for the PreViewKeyDown event for the buttons
private void ArrowButton_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
ProcessKeyDown(e.KeyCode);
}
private bool ProcessKeyDown(Keys keyCode)
{
switch (keyCode)
{
case Keys.Up:
{
// act on up arrow
return true;
}
case Keys.Down:
{
// act on down arrow
return true;
}
case Keys.Left:
{
// act on left arrow
return true;
}
case Keys.Right:
{
// act on right arrow
return true;
}
}
return false;
}
Still, the focus moves around in a rather ugly manner...
I believe the easiest way of solving this problem is through overriding the ProcessCmdKey() method of the form. That way, your key handling logic gets executed no matter what control has focus at the time of keypress. Beside that, you even get to choose whether the focused control gets the key after you processed it (return false) or not (return true).
Your little game example could be rewritten like this:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Left)
{
MoveLeft(); DrawGame(); DoWhatever();
return true; //for the active control to see the keypress, return false
}
else if (keyData == Keys.Right)
{
MoveRight(); DrawGame(); DoWhatever();
return true; //for the active control to see the keypress, return false
}
else if (keyData == Keys.Up)
{
MoveUp(); DrawGame(); DoWhatever();
return true; //for the active control to see the keypress, return false
}
else if (keyData == Keys.Down)
{
MoveDown(); DrawGame(); DoWhatever();
return true; //for the active control to see the keypress, return false
}
else
return base.ProcessCmdKey(ref msg, keyData);
}
Override IsInputKey behaviour
You must override the IsInputKey behavior to inform that you want the Right Arrow key to be treated as an InputKey and not as a special behavior key.
For that you must override the method for each of your controls.
I would advise you to create your won Buttons, let's say MyButton
The class below creates a custom Button that overrides the IsInputKey method so that the right arrow key is not treated as a special key. From there you can easily make it for the other arrow keys or anything else.
public partial class MyButton : Button
{
protected override bool IsInputKey(Keys keyData)
{
if (keyData == Keys.Right)
{
return true;
}
else
{
return base.IsInputKey(keyData);
}
}
}
Afterwards, you can treat your keyDown event event in each different Button or in the form itself:
In the Buttons' KeyDown Method try to set these properties:
private void myButton1_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
//DoSomething();
}
-- OR --
handle the common behaviour in the form: (do not set e.Handled = true; in the buttons)
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//DoSomething();
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
KeyPreview = true;
KeyDown += new KeyEventHandler(Form1_KeyDown);
}
void Form1_KeyDown(object sender, KeyEventArgs e)
{
System.Diagnostics.Debug.Write(e.KeyCode);
}
}