Send keyboard input to a specific child control - c#

Ok, ill try to keep this quick and to the point.
In C# Winforms, I have a GUI window which displays a datagridview and a textbox. Basically what I want to do is, when either the Up Arrow key or Down arrow key is pressed, to send this input straight to the datagridview in order to move up and down through the list. If any other key is pressed, I want to send this input to my textbox.
I've tried over-writing the ProcessCmdKey method and setting focus based on the keyData keycode, but what happens is the first key press will only set the control focus, then, the 2nd key press will actually work on the focused control. I'd like the input to work immediately without that one key delay.
Extra details:
The GUI class is a generic class.
Hope this makes sense! I will edit if more details are needed
Thank you!

This is tricky to do, DataGridView is difficult to tinker with. It has the ProcessUpKey() and ProcessDownKey() methods but they are protected. You'd have to override the class and add public methods so you can call them. What you tried to do failed because by the time you got the keyboard message, it is already committed to the window that has the focus.
A bit of sly hackorama that will work without making big changes to your existing form is just posting the keyboard message back, but this time with the DataGridView as the target window. Paste this snippet into your form class:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (msg.HWnd != dataGridView1.Handle && (keyData == Keys.Up || keyData == Keys.Down)) {
PostMessage(dataGridView1.Handle, msg.Msg, msg.WParam, msg.LParam);
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr PostMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

Related

How to disable Windows lockscreen shortcut

I want to disable Windows lock screen shortcut, because I want to remap it to some other function, but I don't want to disable actual computer locking mechanism.
I know that I can disable lockscreen altogether, this is not what I'm after.
I used this example: https://github.com/kverpoorten/BabyKeyboardBash
I changed the global keyboard hook to ignore all events if it detects that Left Win key is down. If LWin is down, I send a dummy key event.
All the LWin + KEY shortcuts are ignored, except Windows lockscreen shortcut. It seems that Windows catches that event before my app does.
Here is what is changed: https://github.com/kverpoorten/BabyKeyboardBash/blob/master/Keyboard.cs (line 198)
private IntPtr HookCallback( int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
{
if ((NativeMethods.GetKeyState(VK_LWIN) & 0x8000) != 0)
{
Console.WriteLine("LWin down!");
return (System.IntPtr)1;
}
}
Currently I'm only testing if I can even catch the lockscreen shortcut. Everything so for suggests it is not possible.
Thanks!

How to always show underline character? (C# Windows Form)

I'm making a dialog that look like Notepad's Find Dialog. I notice that the underline character of Notepad's Find dialog always show all the time (I have to press ALT key to see this with my dialog). How to always show underline character like that?
I try to use SendKeys.Send("%") on Form_Load event but nothing happens.
There is another problem, when I press ALT key on child Form, it show underline charater of parent Form too. How to avoid that?
This is sreenshot of Notepad's find dialog:
I pretty sure this is not about Ease of Acess Center, because the main Form of Notepad doesn't always show this.
Seeing the n in "Find" underlined in the Notepad dialog is an intentional bug. The dialog isn't actually part of Notepad, it built into Windows. Underlying winapi call is FindText(). The feature is in general a pile 'o bugs, one core problem is that creating a new window after the UI is put in the "show underlines" state doesn't work correctly, that new window isn't also in that state. Presumably the intentional bug was based on the assumption that the user would be somewhat likely to use the Alt key to get the dialog displayed. Yuck if he pressed Ctrl+F.
The Windows dialog probably does it by simply drawing the "Find" string with DrawText() with the DT_NOPREFIX option omitted. You could do the same with TextRenderer.DrawText(), omit the TextFormatFlags.HidePrefix option.
Not exactly WinFormsy, you'd favor a Label control instead of code. It is hackable, you'd have to intentionally send the message that puts the UI in the "show underlines" state for your own dialog. Do so in an override for the OnHandleCreated() method:
protected override void OnHandleCreated(EventArgs e) {
const int WM_UPDATEUISTATE = 0x0128;
base.OnHandleCreated(e);
SendMessage(this.label1.Handle, WM_UPDATEUISTATE, new IntPtr(0x30002), IntPtr.Zero);
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
Where "label1" is the control you want to show underlines. Repeat for other controls, if any. It is supposed to work by sending the message to the form, that this doesn't work is part of the pile 'o bugs. Yuck.
Fwiw: do not fix this by changing the system option as recommended in the duplicate. That's very unreasonable.
You can use RichTextBox control and extension method for that:
public static class FontHelper
{
public static void Underline(this RichTextBox txtBox, int underlineStart, int length)
{
if (underlineStart > 0)
{
txtBox.SelectionStart = underlineStart;
txtBox.SelectionLength = length;
txtBox.SelectionFont = new Font(txtBox.SelectionFont, FontStyle.Underline);
txtBox.SelectionLength = 0;
}
}
}
richTextBox1.Text = "Search for";
richTextBox1.Underline(7, 1); // index and length of underlying text

Datatable value not updating when using keyboard shortcut

I'm trying to implement a ctrl+s shortcut so my users can save their changes in the winform app i'm developing. This is the code for the shortcut:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.S))
{
//Save code
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
When a user makes a bound checkbox checked I expect the bindingsource that is used for binding to have it's data table updated with this new value. When I click the save button it shows the data table has the updated value of 1. When I do ctrl+s the value shows up as 0, so nothing gets saved.
Have you considered testing the code within the if statement to make sure that it is actually being reached?

Why does pressing Ctrl+"+" produce a beep in a TextBox?

I am Working with C# and Windows Forms and want to use Ctrl+"Oemplus" as a function key for my application. I use a German keyboard and this key is located 2 keys right of the letter P (that ist then "+"). Whenever I press this key in combination with Ctrl and the focus is on a TextBox I get a beep.
This also happens when I switch to an US keyboard layout (still using my German keyboard). This is then the ] key.
The same happens when pressing this key while in Internet Explorers address bar.
My question is:
Why does this key combination produce a beep in a TextBox.
How can I avoid the beep?
Thanks for any efforts you put on this.
Update:
I tried it on an US/Thai keyboard and get the beep as well. This happens no matter what logical keyboard layout I use (German, US, Thai).
The beep also happens in Windows Explorer in the address bar but not in the search box.
It is very unclear what you hope to happen when you press that keystroke. TextBox leaves no doubt about it, it BEEPs! because it can see that the user is trying to do something special but it doesn't know exactly what. Good reason to beep you. Solution is to implement magic, in the //.. comment in this next snippet. With the extra code to stop the beep at the end:
private void textBox1_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyData == (Keys.Control | Keys.Oemplus)) {
// Invoke magic
//...
// Magic is done now:
e.Handled = e.SuppressKeyPress = true;
}
}
What I believe is happening is that the key combination is not allowed for the Textbox, therefore you are getting the error. You can test for the Key Combination by this code( using the right bracket key in EN Windows) it is using SuppressKeyPress to prevent the Key Combination from being passed to the underlying control to prevent the beep.
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (ModifierKeys == Keys.Control)
if (e.KeyValue == 221) // You may need to determine this value for your keyboard layout.
{
textBox1.Text += " + "; // Handle the Key combination.
e.SuppressKeyPress = true; // Prevents key from being passed to underlying control
}
}
After some time I came back on this. What I found unsatisfying with the previous solution was that every TextBox would need that handling for every 'beeping' key I use for something else. Sure I could subclass the TextBox but still I would have two places to change for every key with this behavior (the handling and the beep suppression).
Actually I use Ctrl+'+' as a command key. I did this with a global keyboard hook because the action should be available on and impact all forms.
Instead I handle this now in a base form using the following code:
// Avoid beep on Ctrl+'+' in TextBox.
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
Keys key = keyData & Keys.KeyCode;
bool alt = keyData.HasFlag(Keys.Alt);
bool shift = keyData.HasFlag(Keys.Shift);
bool control = keyData.HasFlag(Keys.Control);
if (key == Keys.Oemplus && !shift && control && !alt)
{
// Perform the action for Ctrl+'+'
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
For me this seems the "correct" Position and way to handle a command key. The beep is gone without any additional handling and I don't have to worry if additional command keys produce a beep or not.
When the form had a menu or toolbar this would be handled automatically by the shortcut defined for the menu item. But my forms don't have a menu or toolbar.

WinForms key press isn't working right

update: I've modified the code below to reveal some additional information regarding the key that was pressed.
update #2: I've discovered the root cause of the issue: we have an HTML control (Gecko rendering engine) on our form. When that Gecko rendering engine navigates to some Flash control, suddenly ~2% of our key presses don't get through, even after we've removed the Gecko HTML control. Wahoo, I get to blame this on Flash! Now the question is, how do I fix this?
update #3: Nope, it's not Flash. It's the Gecko rendering engine. Navigating even to Google causes some keys to not come through to our app right. Hrmmm.
We have a strange case in our WinForms app where the user presses a key combination (in this case, Alt + S), and WinForms tells us some other key combo (value 262162) is pressed:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(keyData == (Keys.S | Keys.Alt))
{
Console.WriteLine("You pressed Alt+S");
}
else if(keyData == (Keys.Menu | Keys.Alt))
{
Console.WriteLine("What the hell?"); // This sometimes gets hit when I press Alt+S
}
}
90% of the time, You pressed Alt+S will be shown. But on rare occurrances, we press Alt + S and it says, What the hell?.
Any idea what's wrong?
EDIT I've discovered the root cause of the issue! See below.
After more experimenting, I've found that if do the following, it works as expected:
this.KeyPreview = true;
this.KeyDown += KeyDownHandler;
...
private void KeyDownHandler(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.S && e.Alt)
{
// This always works.
}
}
I can't explain why the ProcessCmdKey didn't work. I wish I knew. Until then, this is an acceptable workaround.
I've discovered the issue. We have an HTML control (Gecko rendering engine) on our form. When that gecko rendering engine is shown on a form, it must be installing a hook or something that changes some key presses, causing us to receive WM_Char instead of WM_KeyDown in certain cases.
From my testing, it would appear that 262162 would be the "Alt" key.
Edit: I overrode the ProcessCmdKey and put in a break point on the "X = 1;" statement:
protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
{
int x = (int)keyData;
if (x == 262162)
x = 1;
return true;
}
It hits that breakpoint whenever I hit the Alt key.
Could it be that you are waiting too long to press the S key and an Alt key repeat is getting fired off?
EDIT2:I tried you posted code and I receive "What the Hell" the second I touch the ALT key, however if I disable this check the Alt-S always comes through. On my system this seems to be the default key code for the Alt key. I am able to ignore it and the Alt-S Will come through afterwards.
EDIT: According to the METADATA for the Keys enumeration Keys.Menu is 18. To see this hit F12 while the cursor is on the Keys Enumeration.
The documentation states that Keys.Menu is the Alt key.
http://msdn.microsoft.com/en-us/library/system.windows.forms.keys.aspx
This tells me that it is reporting the Alt key was pressed(18) with the Alt key modifier(262144) crazy stuff.
Just out of curiosity could you try this:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.S | Keys.Alt))
{
MessageBox.Show("You pressed Alt+S");
}
else if (keyData == (Keys.Menu | Keys.Alt))
{
return false;
}
return true;
}
returning false indicates that this is not a command key.

Categories