C# capture main form keyboard events - c#

How to catch keyboard events of the WinForm main form, where other controls are.
So I want to catch one event Ctrl + S and doesn't matter where focus is.
But without Pinvoke (hooks and such ...)
Only .NET managed internal power.

Try this code. Use the interface IMessageFilter you can filter any ctrl+key.
public partial class Form1 :
Form,
IMessageFilter
{
public Form1()
{
InitializeComponent();
Application.AddMessageFilter(this);
this.FormClosed += new FormClosedEventHandler(this.Form1_FormClosed);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
Application.RemoveMessageFilter(this);
}
public bool PreFilterMessage(ref Message m)
{
//here you can specify which key you need to filter
if (m.Msg == 0x0100 && (Keys)m.WParam.ToInt32() == Keys.S &&
ModifierKeys == Keys.Control)
{
return true;
}
else
{
return false;
}
}
}
I tested this and worked for me.

the Form Class (System.Windows.Forms) has OnKeyDown, OnKeyPress, and OnKeyUp event methods that you can use to detect Ctrl + S
use the KeyEventArgs in those methods to determine which keys were pressed
EDIT
be sure to enable Form.KeyPreview = true; so the form will capture the events regardless of focus.

Handle the KeyDown on the form and all its controls.
private void OnFormLoad(object sender, EventArgs e)
{
this.KeyDown += OnKeyDown;
foreach (Control control in this.Controls)
{
control.KeyDown += OnKeyDown;
}
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Control)
{
if (e.KeyValue == (int)Keys.S)
{
Console.WriteLine("ctrl + s");
}
}
}

You may add a MenuStrip and then create a menu strip item named save and give it a short cut Ctrl + S. Add a event handler for that. This will fire even if the focus is on other control on the form. If you don't like to see the MenuStrip; you can set visible = false too. I must admit this is ugly.

Related

Detect if pressing a mouse button and which WinForm c#

I don't want to click on a button or the form, I just want to know if user is pressing the left mouse button while the cursor is in the form.
I've tried this:
private void PlayForm_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.LButton)
{
...
}
}
but it doesn't work.
I also tried PlayForm_Click() but it works only when the click is on the 'canvas' if there's something else on top it won't work
If you just want to know if the left mouse button is down while executing some other code in the Form you can look at the static property Control.MouseButtons, which returns a value from the MouseButtons enumeration .E.g.:
if ((Control.MouseButtons & MouseButtons.Left) != 0)
you could use the mouse enter/leave to set a boolean that the mouse cursor is over the form, then you could Use the Mouse.
...
bool mouseOverMe;
public MainWindow()
{
InitializeComponent();
mouseOverMe = false;
}
private void Window_MouseEnter(object sender, MouseEventArgs e)
{
mouseOverMe = true;
}
private void Window_MouseLeave(object sender, MouseEventArgs e)
{
mouseOverMe = false;
}
void doSomething()
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
if (mouseOverMe)
MessageBox.Show("Im a mouse down in the window");
}
...
something sorta like this.
As far as I've understood, you want a handler for a click on whatever is in the form. I'd suggest you could iterate trough all the controls in the form on Form_Load event and just set a common handler for the MouseClick (or KeyPressed or whichever event you want according to your current need) for all controls present in the .Controls collection in the moment the form is loaded and you should register the same handler for the form itself (a.k.a. this.MouseClick). This will be a bit of an overkill if you'd later want to register a MouseClick handler for a particular control, but you can always compare the sender object and get the data from there. Example code is not present for now, since I'm typing from my phone. Will update later.
The main problem is that the form doesn't get any messages when a message is sent directly to a child control.
One way around this is to register an application-wide message filter. Note that the following implementation is rather inefficient (and quite ugly), but it should show you the basic idea:
void Main()
{
var form = new Form();
form.Load += (s, _) => Application.AddMessageFilter(new MyFilter((Form)s));
var pnl = new Panel();
pnl.Controls.Add(new Button());
form.Controls.Add(pnl);
Application.Run(form);
}
public class MyFilter : IMessageFilter
{
Form form;
public MyFilter(Form form)
{
this.form = form;
this.form.Disposed += (_, __) => Application.RemoveMessageFilter(this);
}
public bool PreFilterMessage(ref Message msg)
{
const int WM_LMOUSEDOWN = 0x0201;
if (msg.Msg == WM_LMOUSEDOWN && msg.HWnd != IntPtr.Zero
&& Control.FromHandle(msg.HWnd).TopLevelControl == form)
{
Console.WriteLine("Hi!");
}
return false;
}
}

Oxyplot Model Handle Key Press

OxyPlot's PlotModel and PlotController components contains their own Mouse Handlers, to which you can add or remove you own Handlers. For Instance:
this.Model.MouseMove += this.ModelOnMouseMove;
public void ModelOnMouseMove(object sender, OxyMouseDownEventArgs e)
{
// Do some mouse stuff...
}
Is there a way for the Model to capture KeyBoard Key presses in a similiar manner?
OxyPlot apparently does have a Model.Keydown Even Handler, that triggers when the PlotModel is in focus. There just doesn't appear to be much documentation on it:
this.Model.KeyDown += ModelOnKeyDown;
private void ModelOnKeyDown(object sender, OxyKeyEventArgs e)
{
if (e.Key == OxyKey.Up)
{
// Do Some Stuff
}
else if (e.Key == OxyKey.Down)
{
// Do Some Stuff
}
}

Write events that can be shared throughout all custom controls in C# WPF

I have multiple custom controls, and I noticed that all of them share the same event (custom) example : OnMoved etc
What I'm doing now is, copy & paste the same code from controls to controls.
So, are there anyway for me to write custom events that can be shared throughout all my controls in C# WPF?
An example of an event that I use for all my controls :
Point lastPosition = new Point();
Point currentPosition = new Point();
public static void OnMoved(object sender, EventArgs e)
{
currentPosition.X = Canvas.GetLeft(explorer);
currentPosition.Y = Canvas.GetTop(explorer);
// didn't moved
if (currentPosition.X == lastPosition.X || currentPosition.Y == lastPosition.Y)
{
return;
}
lastPosition.X = Canvas.GetLeft(explorer);
lastPosition.Y = Canvas.GetTop(explorer);
}
It depends on what exactly you need the event to do, but you could place the event into a shared class:
public class MyEvents
{
public static void SomeEvent(object sender, EventArgs e)
{
MessageBox.Show("hi");
}
}
And then just subscribe to it from wherever you need to:
SomeButton.Click += MyEvents.SomeEvent;
You can create a base class that has a public virtual event, and the event will appear in any classes that derive from the base class. That would keep you from having to copy and paste the same code over and over.
Yes you can! :D The only things you need to have present are:
-> Same Events (The Args of the event have to be exactly the same.
-> They are going to do the same.
The bad thing is that you cannot mix controls with events. For example, you can create a .Click event for a button so it closes your application, but if you wish this to do the same when you press the key "F8" it won't work because the Event arguments are different ~
You can try using a method that makes the same stuff in all your events. Example:
private void _Close()
{
Process.GetCurrentProcess().Close();
}
And you can close with "F5" pressed in the form or with a button click or typyng in a textbox "Close".
button.Click += Button_Close;
private void Button_Close(Object o, RoutedEventArgs e)
{
_Close();
}
this.KeyDown += This_Close;
private void This_Close(Object o, KeyEventArgs e)
{
if(e.KeyCode == Key.F5) _Close();
}
TextBox.TextChanged += Text_Close;
private void Text_Close(Object o, TextChangedEventArgs e)
{
if(TextBox.Text == "Close") _Close();
}

textBox Action Methods

I'm working on a program that allows the user to enter a barcode via scanner and then do stuff, and I've got most of it worked out, I just can't figure out which action method for textBox1 would allow me to do something when "Enter" was hit while in the textBox. I've looked at the description of most of the actions, and I can't find one that sounds like it would work.
Is there one that would work? Or do I just have to check every time a key is pressed?
You want the KeyDown / OnKeyDown or KeyUp/OnKeyUp event, just filter for the right key:
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyCode == Keys.Enter)
{
// Do Something
}
}
Or in your case since your parent form is most likely subscribing to the TextBox event then you would add a method like the following using the designer:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
// Do Something
}
}
Keep in mind that what you are calling "Action Methods" are called Events.
Try this, using the KeyUp event:
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
DoSomething();
}
}
try handler the keypress event.
stop the handler and work better.
using System;
using System.Windows.Forms;
public class Form1: Form
{
public Form1()
{
// Create a TextBox control.
TextBox tb = new TextBox();
this.Controls.Add(tb);
tb.KeyPress += new KeyPressEventHandler(keypressed);
}
private void keypressed(Object o, KeyPressEventArgs e)
{
// The keypressed method uses the KeyChar property to check
// whether the ENTER key is pressed.
// If the ENTER key is pressed, the Handled property is set to true,
// to indicate the event is handled.
if (e.KeyChar != (char)Keys.Enter)
{
e.Handled = true;
}
}
public static void Main()
{
Application.Run(new Form1());
}
}

C# keypress doesn't capture 'delete' key

I have added a keyPress event on a ListView. With a breakpoint on my event, I can see that most of the keys trigger the event. However, a few among which, the one I'm interested in (delete), just won't trigger my event.
Is that weird ? And no, there's no broken keys on my keyboard :D
private void listView1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Delete)
{
ListView target = (ListView)sender;
if (target.SelectedIndices != null && target.SelectedIndices.Count > 0)
{
string ric = target.SelectedItems[0].SubItems[0].Text;
//target.Items.RemoveAt(target.SelectedIndices[0]);
ListModels.getInstance().getModel("Vols").removeRic(ric);
}
}
}
The reason for this is that the KeyPress event sends a character to the control based upon the character-key you press. However, as you'd expect, the delete key does not represent a character and is thus a non-character key.
Therefore using the KeyPress event will do nothing as you have noticed. You should use the KeyDown or KeyUp Events, either of which will work absolutely fine. The nuance being whether you want your event to fire upon pressing, or letting go of a key.
You'll want to use the KeyDown event for this.
In KeyDown use the condition as follows,
if (e.KeyCode == Keys.Delete)
{
// Your Logic....
}
Use keyDown instead; keyPress is something like a full keyDown + keyUp
The problem is that if you set EditMode property to EditOnEnter it won't fire. If you use EditOnKeyStrokeOfF2 it will fire the event
If you are looking for a solution where the user should only be able to choose from the defined items, then I believe you can do it with this:
private void DropDownRank_KeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = true;
}
See this code:
private void Form1_Load(object sender, EventArgs e)
{
listView1.KeyUp += new KeyEventHandler(ListView_KeyUp);
}
/// <summary>鍵盤觸發 ListView 清單</summary>
private void ListView_KeyUp(object sender, KeyEventArgs e)
{
ListView ListViewControl = sender as ListView;
if (e.KeyCode == Keys.Delete)
{
foreach (ListViewItem eachItem in ListViewControl.SelectedItems)
{
ListViewControl.Items.Remove(eachItem);
}
}
}
I tried all the stuff mentioned above but nothing worked for me, so im posting what i actually did and worked, in the hopes of helping others with the same problem as me:
Add an event handler in the constructor:
public partial class Test
{
public Test()
{
this.RemoveHandler(KeyDownEvent, new KeyEventHandler(Test_KeyDown));
// im not sure if the above line is needed (or if the GC takes care of it
// anyway) , im adding it just to be safe
this.AddHandler(KeyDownEvent, new KeyEventHandler(Test_KeyDown), true);
InitializeComponent();
}
//....
private void Test_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Delete)
{
//your logic
}
}
}

Categories

Resources