C# Arrow Key is not captured [closed] - c#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I'm creating a program, that is able to draw on the full desktop. I have different functions for drawing for example an ellipse. There is also a function for inserting some Text. For this I use a transparent TextBox(Tbx). When I call this function, it creates a Label, that gets the Text of the Textbox, everytime I change the text. This works quite well, but I also have a function that should minimize the Window with ↓. After inserting text, the key is useless, but the other keys are still captured with the event handler. If I don't insert text into Textbox control, I can minimize. The main problem is, that the ↓ is not captured with the event handler and the minimization doesn't happen. I'm unsure if KeyDownEvent is the correct event to capture special keys such as arrows, Ctrl, ... So the question is how to fix this code to capture ↓ and execute the code to minimize the Window.
Here are some parts of my code:
Creating a Label:
Tbx.Clear();
if (!hasStartPoint)
{
START = current;
hasStartPoint = true;
}
this.canvas1.Children.Remove(Lab2);
Lab1 = new Label() { IsEnabled = true, Background = Brushes.Transparent, Foreground = this.brush, FontFamily = textFont, Content = "" };
if (this.thickness > 5000) { FontSize = 5000; }
else { FontSize = this.thickness; }
Canvas.SetLeft(Lab1, START.X);
Canvas.SetTop(Lab1, START.Y);
Tbx.Focus();
isWriting = true;
this.Cursor = Cursors.IBeam;
canvas1.Children.Add(Lab1);
Lab2 = Lab1;
Writing text:
void Tbx_TextChanged(object sender, TextChangedEventArgs e)
{
if (isWriting)
{
Lab1.Content = Tbx.Text;
}
}
Finished writing:
else if (e.Key == Key.Enter || e.Key == Key.End)
{
if (!isWriting)
{ this.Close(); }
else
{
Lab1 = new Label() { IsEnabled = true, Background = Brushes.Transparent, Foreground = this.brush, FontSize = this.thickness, FontFamily = textFont, Content = "" };
Canvas.SetLeft(Lab1, 1);
Canvas.SetTop(Lab1, 1);
canvas1.Children.Add(Lab1);
isWriting = false;
this.Cursor = Cursors.Cross;
}
}
Minimizing the Window in a KeyDownEvent:
else if (e.Key == Key.Down)
this.WindowState = WindowState.Minimized;

The solution for catching special keys is to use PreviewKeyDownEvent. This is because those keys are not considered to be input for some controls.
Some key presses, such as the TAB, RETURN, ESC, and arrow keys, are
typically ignored by some controls because they are not considered
input key presses. For example, by default, a Button control ignores
the arrow keys. Pressing the arrow keys typically causes the focus to
move to the previous or next control. The arrow keys are considered
navigation keys and pressing these keys typically do not raise the
KeyDown event for a Button. However, pressing the arrow keys for a
Button does raise the PreviewKeyDown event. By handling the
PreviewKeyDown event for a Button and setting the IsInputKey property
to true, you can raise the KeyDown event when the arrow keys are
pressed. However, if you handle the arrow keys, the focus will no
longer move to the previous or next control.

Related

Disable jumping between buttons by using arrow keys

I have a WinForms form with a TableLayoutPanel on it.
In this TableLayoutPanel, I have 2 Button controls.
I press one of these buttons.
Then I press the Up or Down arrow (↑ ↓) on the keyboard.
The focus jumps from one button to the other.
I don't want this behaviour.
Setting the TableLayoutPanel's "TabStop" to "False" doesn't help.
I would instead like to intercept the event and set the focus to another control manually.
However, I didn't find the event that I need to intercept.
How could I disable this jumping by arrow keys?
Which event would I have to intercept to set the focus to another control?
Thank you!
You can handle PreviewKeyDown event of all the buttons using a single handler and check if the pressed key is an arrow key, set e.IsInputKey = true and prevent focus change:
private void button1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
var keys = new[] { Keys.Left, Keys.Right, Keys.Up, Keys.Down };
if (keys.Contains(e.KeyData))
e.IsInputKey = true;
}
You can read about the behavior and the solution in Remarks section of the PreviewKeyDown documentations.
The behavior is in fact implemented in ProcessDialogKey method of the container control (you can see source code) and you can also prevent it by overriding ProcessDialogKey of the Form, like this:
protected override bool ProcessDialogKey(Keys keyData)
{
var keys = new[] { Keys.Left, Keys.Right, Keys.Up, Keys.Down };
if (keys.Contains(keyData))
return true;
else
return base.ProcessDialogKey(keyData);
}

How to Disable LWin and Arrow shortcut in WPF?

In my application I have a loading screen that is supposed to cover the whole screen (logo omitted):
Expected
My view is composed of a StackPanel (for the logo and some text) contained within a Grid. It is displayed using the Window.Show() from the System.Windows library.
var popup = new Window()
{
WindowState = WindowState.Maximized,
WindowStyle = WindowStyle.None,
AllowsTransparency = true,
Visibility = Visibility.Visible,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Content = loaderMvvmSet.View,
IsHitTestVisible = true,
Background = new SolidColorBrush(Colors.White) { Opacity = 0.1 },
Topmost = true,
ShowInTaskbar = false
};
When testing, we noticed that the user could bypass the loading screen using key combinations: Window + Arrow. To disable this resizing, I set ResizeMode = ResizeMode.NoResize. This seems to have worked for clicking Windows + Up / Right / Left. However, when I click Windows + Down I get this: Actual
I checked out other posts but have not been able to find a solution to my problem. Here is what I tried:
1. Attaching an event handler to the KeyDown event:
a. Setting the Handled property to true for each key separately:
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.LWin)
{
e.Handled = true;
}
if (e.Key == Key.Down)
{
e.Handled = true;
}
}
b. Checking that both keys are pressed and setting the Handled property to true:
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.LWin && Keyboard.IsKeyDown(Key.Down))
{
e.Handled = true;
}
}
c. Creating separate Booleans for the both keys and then if both are set to true, the event is ignored.
2. Added KeyBindings to the Window and giving it an empty command:
a. Using the Modifiers and the Key:
InputBindings = { new KeyBinding() { Modifiers = ModifierKeys.Windows, Key = Key.Down, Command = EmptyCommand } }
b. Using just the Down Key:
InputBindings = { new KeyBinding() { Key = Key.Down, Command = EmptyCommand } }
What I noticed for point 1 is that the KeyDown event gets fired for the Windows key but not for the Down key. It seems like as long as I am still holding the Windows key, the Down key is never acknowledged.
For point 2, having both the Modifiers and the Key (point a) does not seem to work at all; my breakpoint in the EmptyCommand is never hit. And, having just the Down Key (point b) seems like the same issue as in point 1, that it will fire for a KeyBinding with just the LWin key, but does not get acknowledged for the Down key (because we are still holding LWin).
Here are some of the links I have checked:
How to detect multiple keys down onkeydown event in wpf?
Understanding multiple keys with WPF KeyDown event
This may not be an ideal solution, but if LWin + Down (Restore Down) triggers a size changed event, perhaps you can force reset the window state?
As per https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.resize?redirectedfrom=MSDN&view=netcore-3.1
XAML:
SizeChanged="MyLoaderView_OnSizeChanged"
Code-Behind:
private void MyLoaderView_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
Window window = (Window)sender;
window.WindowState = WindowState.Maximized;
}
This can be definitely solved with keyboard hooker. Capture the win+arraws combination keys and handle that.
With TonyValenti's powerful native hook package, I wrote code below.
var KeyboardDisposable = WindowsInput.Capture.Global.KeyboardAsync();
var Listener = new KeyChordEventSource(Keyboard, new ChordClick(KeyCode.LWin, KeyCode.Left));
Listener.Triggered += (s, e) =>
{
if (User32.GetForegroundWindow() == WpfWindowHandle)
{
e.Input.Next_Hook_Enabled = false;
}
};
Listener.Enabled = true;
Remember dispose keyboard or listener to avoid memory leak.

C#.NET Winform keypress event can't be cancelled

I have a (.NET 3.5) winform with a datagridview on which I added an event on checkboxes in the gridview like this. That post doesn't take into account that people can also use spacebar to toggle the checkbox, and because there is no CellKeyUp event like there is a CellMouseUp event, I enabled KeyPreview on the form and added this code to prevent toggling with the spacebar:
private void BulkOrderAddressDifferencesForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space)
{
e.Handled = true;
e.SuppressKeyPress = true;
}
}
That works mostly, but there is a scenario in which the event is still handled, even though the debugger shows e.Handled is set to true.
If I click on a checkbox, then 1, then 2, I can toggle the checkbox with the space bar again. I have no idea why this happens, nor do I know how to fix it.
You can override Form's ProcessCmdKey method:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Space && checkBox1.Focused)
{
//instead of checkBox1.Focused condition, you check if your DataGridView contains focus and active cell is of checkBox type
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
If the goal is to always react immediately when the check is changed, rather than preventing the use of the spacebar (Unless I'm mistaken, the problem is that the cellmouseup approach doesn't include (un)checking with space, rather than the goal is that space shouldn't be used at all? ), you could use the celldirtychanged approach instead of cellmouseup to catch both
//grid.CurrentCellDirtyStateChanged += grid_CurrentCellDirtyStateChanged;
void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (grid.IsCurrentCellDirty)
{
var cell = grid.CurrentCell;
if (cell is DataGridViewCheckBoxCell)
{
grid.EndEdit();
//you could catch the cellvaluechanged event (or a bound listchanged event), or handle the change immediately here, e.g.:
//Console.WriteLine("{0} value changed to {1}", cell.OwningColumn.HeaderText, cell.Value);
}
}
}
How about the DataGridView.EditMode Property which
Gets or sets a value indicating how to begin editing a cell.
where
The default is EditOnKeystrokeOrF2.
and
All DataGridViewEditMode values except for EditProgrammatically allow a user to double-click a cell to begin editing it.
You have several options to choose from the DataGridViewEditMode Enumeration
EditOnEnter - Editing begins when the cell receives focus. This mode is useful when pressing the TAB key to enter values across a row, or when pressing the ENTER key to enter values down a column.
EditOnF2 - Editing begins when F2 is pressed while the cell has focus. This mode places the selection point at the end of the cell contents.
EditOnKeystroke - Editing begins when any alphanumeric key is pressed while the cell has focus.
EditOnKeystrokeOrF2 - Editing begins when any alphanumeric key or F2 is pressed while the cell has focus.
EditProgrammatically - Editing begins only when the BeginEdit method is called.
Update for DataGridViewCheckBoxCell:
It turns out that the DataGridViewEditMode does not work for the DataGridViewCheckBoxColumn.
In this case you can create your own DataGridViewCheckBoxColumn & DataGridViewCheckBoxCell. This allows you to override the cell's OnKeyUp event handler and reset the EditingCellFormattedValue if Space was pressed.
public class MyCheckBoxColumn : DataGridViewCheckBoxColumn
{
public MyCheckBoxColumn()
{
CellTemplate = new MyCheckBoxCell();
}
}
public class MyCheckBoxCell : DataGridViewCheckBoxCell
{
protected override void OnKeyUp(KeyEventArgs e, int rowIndex)
{
if (e.KeyCode == Keys.Space)
{
e.Handled = true;
if (EditingCellValueChanged)
{
// Reset the value.
EditingCellFormattedValue = !(bool)EditingCellFormattedValue;
}
}
else
{
base.OnKeyUp(e, rowIndex);
}
}
}
After you rebuild your project the new column should appear in the designer:

KeyDown event not being called [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
// The program flow does not enter this scope.
if (e.KeyCode == Keys.Right)
{
}
}
You need to set the KeyPreview property of the Form to true
As per MSDN
When this property is set to true, the form will receive all KeyPress,
KeyDown, and KeyUp events. After the form's event handlers have
completed processing the keystroke, the keystroke is then assigned to
the control with focus. For example, if the KeyPreview property is set
to true and the currently selected control is a TextBox, after the
keystroke is handled by the event handlers of the form the TextBox
control will receive the key that was pressed. To handle keyboard
events only at the form level and not allow controls to receive
keyboard events, set the KeyPressEventArgs.Handled property in your
form's KeyPress event handler to true.
This can be done either at design time, by simply setting true for Form's KeyPreview
or to manually do it
public class Form1 : Form
{
public Form1()
{
base.KeyPreview = true;
InitializeComponent();
}
}
Use the ProcessCmdKey override:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Right)
System.Diagnostics.Debug.WriteLine("Right key pressed");
return true;
}
You could use this:
KeyboardState ks = new KeyboardState();
if(ks.isKeyDown(Keys.Right)
{
System.Diagnostics.Debug.WriteLine("Right key pressed");
}
Note: This is off the top of my head so may not be 100% accurate but I'm 98% sure that it will work :)

Select Tab Page in TabControl without stealing focus

Using TabControl.SelectTab("...") shows the tab but it also gives the tab focus. I would like to show a particular tab, but keep focus where it is.
I have data rows in a grid. Based on properties of the selected row, I show a different tab page to have a different UI layout. But when using arrow keys to scroll through rows, the focus switches to the selected tab -- which I don't want to happen.
Thanks.
You can try disabling the TabControl before setting the selected tab, then re-enabling it. This will prevent it from taking focus. I tested this on a tab control with a few controls on it, and didn't see any visual change, but you'll have to try it in your UI and see whether it's ok for you.
tabControl1.Enabled = false;
tabControl1.SelectTab("tabPage4");
tabControl1.Enabled = true;
To be safe, you could put the line to re-enable the TabControl in a finally block to make sure it doesn't get left disabled.
I don't think there's a built-in function, but you can do in this way:
private bool skipSelectionChanged = false;
private void dataGridView_SelectionChanged(object sender, EventArgs e)
{
if (skipSelectionChanged)
return;
// supposing we decide tab[0] has to be selected...
this.SelectTabWithoutFocus(this.tabControl1.TabPages[0]);
}
private void SelectTabWithoutFocus(TabPage tabPage)
{
this.skipSelectionChanged = true;
// "this" is the form in my case, so you get the current focused control
// (ActiveControl), backup it, and re-set it after Tab activation
var prevFocusedControl = this.ActiveControl;
if (this.ActiveControl != null)
{
this.tabControl1.SelectedTab = tabPage;
prevFocusedControl.Focus();
}
this.skipSelectionChanged = false;
}
Here, I backup the current focused control, select the desired tab, and finally set the focus to the original control.
Skipping boolean is necessary, because giving the focus to the grid you trigger SelectionChanged event again, causing infinite looping.
This selects the tab pages while keeping the focus on top, as asked here above:
tc.TabPages[0].Enabled = false;
tc.SelectTab(0);
tc.TabPages[0].Enabled = true;
tc is here my instance for the TabControl type (i. e. it IS my tab control, and it has a few "tab pages"). This works properly for me. My purpose is to loop through these tab pages with the Left and Right keys (arrows) i. e. when I go forwards (by Key.Right) and reach the last tabpage I want to have my focus on [0] without activating the DataGridView which I have in that page, and when I go backwards (by Key.Left) and reach [0] I want to have [tc.TabCount - 1] enabled, which is the last one. The code for this case is:
tc.TabPages[tc.TabCount - 1].Enabled = false;
tc.SelectTab(tc.TabCount - 1);
tc.TabPages[tc.TabCount - 1].Enabled = true;
The complete piece of code is:
private bool KeyTc(System.Windows.Forms.Keys keyData)
{
if (keyData == K.Left && tc.SelectedIndex == 0)
{
tc.TabPages[tc.TabCount - 1].Enabled = false;
tc.SelectTab(tc.TabCount - 1);
tc.TabPages[tc.TabCount - 1].Enabled = true;
return true;
}
else if (keyData == K.Right && tc.SelectedIndex == tc.TabCount - 1)
{
tc.TabPages[0].Enabled = false;
tc.SelectTab(0);
tc.TabPages[0].Enabled = true;
return true;
}
return false;
}
This bool KeyTc is returned to a case in a switch statement for key evaluation in:
protected override bool ProcessCmdKey(ref Message keyMsg, Keys keyData)
{ switch keyData { ... } }
Base on the solution proposed by "Jeff Ogata : You can try disabling the TabControl before setting the selected tab, then re-enabling it. This will prevent it from taking focus", here bellow my solution:
tabMain.SelectedPageChanging += (s, e) =>
{
tabMain.Enabled = false;
};
tabMain.SelectedPageChanged += (s, e) =>
{
tabMain.Enabled = true;
};
Note: this code is using DevExpress "DevExpress.XtraTab.XtraTabControl".

Categories