How to Disable LWin and Arrow shortcut in WPF? - c#

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.

Related

C# Keys.Apps will always open Windows context menu

I'm trying to handle the Apps/Context Menu key on the keyboard. The key should be catched at a TextBox and then should show the programmed ContextMenuStrip of a DataGridView object.
However getting the ContextMenuStrip displayed turned out pretty simple. My only problem is that the flag e.Handled = true does not seem to work to prevent the Windows default context menu for the TextBox to appear. So it's opening the ContextMenuStrip for the DataGridView and the default context menu for the TextBox.
Following code applies:
void EditSearchField_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Apps)
{
// ContextMenuStrip is shown here
DataGridView1.ContextMenuStrip.Show(DataGridView1, new Point(0, 0));
e.Handled = true;
e.SuppressKeyPress = true;
}
}
The result looks rather unpleasant. KeyPreview = true is also set.
Any ideas?
Since ProcessCmdKey() and PreviewKeyDown() didn't do the job, I decided to take another approach...
I found a (at least for my needs) decent workaround for my problem. In the "designer" portion of my form i defined a new ContextMenuStrip for my TextBox:
// editSearchField
[...]
this.editSearchField.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip();
This resulted in the Windows default context menu not showing anymore. Since the ContextMenuStrip has no ToolStripMenuItems it is discarded immediately.
For completeness, here's how I changed the KeyDown() function
void EditSearchField_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Apps)
{
if (dgvClients.SelectedRows.Count > 0)
{
// force the selected row to be visible, or else we could get a .NET debugger
dgvClients.CurrentCell = dgvClients.SelectedRows[0].Cells[0];
// prepare context menu (disable inaccessible entries)
Point ptMouse = dgvClients.GetCellDisplayRectangle(0, dgvClients.SelectedRows[0].Index, false).Location;
var mouseEvtArgs = new MouseEventArgs(MouseButtons.Right, 1, 0, 0, 0);
var mouseDgvArgs = new DataGridViewCellMouseEventArgs(0, dgvClients.SelectedRows[0].Index, ptMouse.X, ptMouse.Y, mouseEvtArgs);
DgvClientsMouseDown(dgvClients, mouseDgvArgs);
// calculate location for the context menu and finally show it
Point ptContextMenuPos = dgvClients.PointToScreen(ptMouse);
ptContextMenuPos.X += dgvClients.Width / 2;
ptContextMenuPos.Y += dgvClients.RowTemplate.Height / 2;
dgvClients.ContextMenuStrip.Show(ptContextMenuPos);
}
e.Handled = true;
e.SuppressKeyPress = true;
}
}
Edit: fixed a bug within the code

C# Arrow Key is not captured [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 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.

Are some keyboards more loquacious than others?

The lead developer says that when he uses my app, his keyboard beeps when he moves between TextBoxes on the TableLayoutPanel via the directional arrow keys.
However, I hear no such aural activity.
Here's my code:
// Had to intercept Up and Down arrows from Windows
private void textBoxPlatypi_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) {
TextBox tb = (TextBox)sender;
if (e.KeyCode.Equals(Keys.Up)) {
SetFocusOneRowUp(tb.Name);
return;
}
if (e.KeyCode.Equals(Keys.Down)) {
SetFocusOneRowDown(tb.Name);
return;
}
}
private void textBoxPlatypi_KeyDown(object sender, KeyEventArgs e) {
TextBox tb = (TextBox)sender;
if (e.KeyCode.Equals(Keys.Left)) {
SetFocusOneColumnBack(tb.Name);
e.Handled = true;
return;
}
if (e.KeyCode.Equals(Keys.Right)) {
SetFocusOneColumnForward(tb.Name);
e.Handled = true;
return;
}
}
..He thought maybe I needed "e.Handled" but that is not available in the PreviewKeyDown event.
Is there a way to suppress the beeping (which apparently occurs only with certain keyboards or specific setups (he's using Windows7, I'm on XP still))?
UPDATE
I've got this code now:
private void textBoxPlatypus1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) {
switch (e.KeyCode) {
case Keys.Down:
case Keys.Up:
e.IsInputKey = true;
break;
}
}
private void textBoxPlatypus1_KeyDown(object sender, KeyEventArgs e) {
TextBox tb = (TextBox)sender;
if (e.KeyCode.Equals(Keys.Up)) {
SetFocusOneRowUp(tb.Name);
e.Handled = true;
return;
}
if (e.KeyCode.Equals(Keys.Down)) {
SetFocusOneRowDown(tb.Name);
e.Handled = true;
return;
}
if (e.KeyCode.Equals(Keys.Left)) {
SetFocusOneColumnBack(tb.Name);
e.Handled = true;
return;
}
if (e.KeyCode.Equals(Keys.Right)) {
SetFocusOneColumnForward(tb.Name);
e.Handled = true;
return;
}
}
...but he still hears the beeping (I don't).
He's in Alaska and using Windows 7; I'm in California and using XP. I don't know if some combination/mismatch there is the problem...
UPDATED AGAIN
I know this may be shocking to some, but the Alaska/California disconnection has nothing to do with it. I'm now hearing the beeps, too, and it's not from the arrow keys. It's when a value is entered in a TextBox and then, if that text box already has a character, focus is moved to the next textBox and the value is entered there (this is my code that causes this to happen). But the irritating beeping seems to be random - I haven't figured out the pattern for when it beeps (sometimes it does, sometimes it doesn't)...has anybody ever run across anything like that, or, better yet, know how to suppress the beep? All I'm doing is pressing either the "1" or the "2" key above the keyboard.
There is no way in the PreviewKeyDownEvent to Handle / Supress a KeyEvent like there is in the normal KeyDown Event. What the documentation suggests is to set the PreviewKeyDownEventArgs.IsInputKey property to true in order to handle key presses that are not available normally in the KeyDown Event.
From above Link, they are using a button as an example:
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... 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.
Try this:
e.SuppressKeyPress = true;

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".

ToggleButton in C# WinForms

Is it possible to create a toggle button in C# WinForms? I know that you can use a CheckBox control and set it's Appearance property to "Button", but it doesn't look right. I want it to appear sunken, not flat, when pressed. Any thoughts?
You can just use a CheckBox and set its appearance to Button:
CheckBox checkBox = new System.Windows.Forms.CheckBox();
checkBox.Appearance = System.Windows.Forms.Appearance.Button;
Check FlatStyle property. Setting it to "System" makes the checkbox sunken in my environment.
You may also consider the ToolStripButton control if you don't mind hosting it in a ToolStripContainer. I think it can natively support pressed and unpressed states.
thers is a simple way to create toggle button. I test it in vs2010. It's perfect.
ToolStripButton has a "Checked" property and a "CheckOnClik" property. You can use it to act as a toggle button
tbtnCross.CheckOnClick = true;
OR
tbtnCross.CheckOnClick = false;
tbtnCross.Click += new EventHandler(tbtnCross_Click);
.....
void tbtnCross_Click(object sender, EventArgs e)
{
ToolStripButton target = sender as ToolStripButton;
target.Checked = !target.Checked;
}
also, You can create toggle button list like this:
private void Form1_Load(object sender, EventArgs e)
{
arrToolView[0] = tbtnCross;
arrToolView[1] = tbtnLongtitude;
arrToolView[2] = tbtnTerrain;
arrToolView[3] = tbtnResult;
for (int i = 0; i<arrToolView.Length; i++)
{
arrToolView[i].CheckOnClick = false;
arrToolView[i].Click += new EventHandler(tbtnView_Click);
}
InitTree();
}
void tbtnView_Click(object sender, EventArgs e)
{
ToolStripButton target = sender as ToolStripButton;
if (target.Checked) return;
foreach (ToolStripButton btn in arrToolView)
{
btn.Checked = false;
//btn.CheckState = CheckState.Unchecked;
}
target.Checked = true;
target.CheckState = CheckState.Checked;
}
How about this?
Assuming you have System.Windows.Forms referenced.
var cbtnToggler = new CheckBox();
cbtnToggler.Appearance = Appearance.Button;
cbtnToggler.TextAlign = ContentAlignment.MiddleCenter;
cbtnToggler.MinimumSize = new Size(75, 25); //To prevent shrinkage!
Hope this helps ;)
This is my simple codes I hope it can help you
private void button2_Click(object sender, EventArgs e)
{
if (button2.Text == "ON")
{
panel_light.BackColor = Color.Yellow; //symbolizes light turned on
button2.Text = "OFF";
}
else if (button2.Text == "OFF")
{
panel_light.BackColor = Color.Black; //symbolizes light turned off
button2.Text = "ON";
}
}
When my button's FlatStyle is set to system, it looks flat. And when it's set to popup, it only pops up when mouses over. Either is what I want. I want it to look sunken when checked and raised when unchecked and no change while mousing over (the button is really a checkbox but the checkbox's appearance property is set to button).
I end up setting the FlatStyle to flat and wrote a new Paint event handler.
private void checkbox_paint(object sender, PaintEventArgs e)
{
CheckBox myCheckbox = (CheckBox)sender;
Rectangle borderRectangle = myCheckbox.ClientRectangle;
if (myCheckbox.Checked)
{
ControlPaint.DrawBorder3D(e.Graphics, borderRectangle,
Border3DStyle.Sunken);
}
else
{
ControlPaint.DrawBorder3D(e.Graphics, borderRectangle,
Border3DStyle.Raised);
}
}
I give a similar answer to this question:
C# winforms button with solid border, like 3d
Sorry for double posting.
You can always code your own button with custom graphics and a PictureBox, though it won't necessarily match the Windows theme of your users.
I ended up overriding the OnPaint and OnBackgroundPaint events and manually drawing the button exactly like I need it. It worked pretty well.
use if command to check status and let operate as a toggle button
private void Protection_ON_OFF_Button_Click(object sender, EventArgs e)
{
if (FolderAddButton.Enabled == true)
{
FolderAddButton.Enabled = false;
}
else
{
FolderAddButton.Enabled = true;
}
}
You should look into Siticone I use it and I love it. It works exactly like a checkbox but is a toggle button. Its downside is a message box will come up every time you open Visual Studios so I just installed a tool that disables it. You can also look into Guana but I found that to have a few bugs :)
Changing a CheckBox appearance to Button will give you difficulty in adjustments. You cannot change its dimensions because its size depends on the size of your text or image.
You can try this: (initialize the count variable first to 1 | int count = 1)
private void settingsBtn_Click(object sender, EventArgs e)
{
count++;
if (count % 2 == 0)
{
settingsPanel.Show();
}
else
{
settingsPanel.Hide();
}
}
It's very simple but it works.
Warning: This will work well with buttons that are occasionally used (i.e. settings), the value of count in int/long may be overloaded when used more than it's capacity without closing the app's process. (Check data type ranges: http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx)
The Good News: If you're running an app that is not intended for use 24/7 all-year round, I think this is helpful. Important thing is that when the app's process ended and you run it again, the count will reset to 1.

Categories