I need to close the application (C#) when user doesn't use it - let's say that when there is no Click event on any form of the program (there are about 100 forms). Is there any way to do that without handling Click even on each form of the app. (I have the thread running each minute, where it could be checked)?
Thanks in advance!
You can hook into the application message loop using the Application.AddMessageFilter function. Write a message filter that inspects all mouse click messages and/or keyboard messages, or anything you're interested in.
For instance:
public class DetectActivityMessageFilter : IMessageFilter
{
private const int WM_LBUTTONDOWN = 0x0201;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN)
{
// The left mouse button was pressed
}
return false;
}
}
Related
I have a winforms control derived from Button, whose purpose is to display some dialog.
So, the control can be "activated" by tabbing or by a mouse click according to the application state. Forcing tab access is required under some circumstances, to ensure previous fields are filled.
Therefore, I need to "capture" mouse clicks on it, so to allow or disallow the mouse event according to the application state.
To trap the tab key, I override OnEnter() and it works ok.
I also overrided OnClick(), OnMouseDown() and OnMouseClick() at no avail: the program control is always silently passed to the OnEnter() method.
The debugger never stops in the OnClick() or OnMouse*() methods, so I cannot signal the event origin and prevent the core execution when needed.
Could someone help? Of course, I don´t like to trap the windows message queue; some previous experiences were not happy.
TIA
Using simple message pump filtering, as described here (https://www.daniweb.com/programming/software-development/threads/304777/how-to-temporarily-disabling-mouse-clicks-on-a-vb-net-form) with a class like this
// relevant usings...
using System.Security.Permissions;
...
using System.Windows.Forms;
namespace YourNameSpace
{
public class MouseFilter : IMessageFilter
{
protected static bool inEffect = false;
public static bool ActiveFiltering { set { inEffect = value; } }
const int LButtonDown = 0x201;
const int LButtonUp = 0x202;
const int LButtonDoubleClick = 0x203;
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public bool PreFilterMessage( ref Message m )
{
if (!inEffect)
return false;
bool result = false;
switch (m.Msg) {
case LButtonDown:
case LButtonUp:
case LButtonDoubleClick:
result = true;
break;
}
return result;
}
}
}
The static property ActiveFiltering provides a way to enable/disable mouse clicks filtering as required.
Of course, the Program class must execute
Application.AddMessageFilter(new MouseFilter());
but, being inEffect = false, it don´t interfere normal general mouse operation.
My control disables the mouse when required, and takes care to left it enabled otherwise.
The solution is not perfect, but is what´s possible. The worst drawback is that while the control cancels the mouse clicks, no one can go to other control or the window self.
I'm currently working on a simple game that is drawn on a form by overriding the OnPaint method. The game requires Keyboard input and was working perfectly until I decided to enhance the GUI and add a few Buttons to the form.
The moment I added these Buttons, the form stopped receiving any Keyboard input, no matter how hard I tried the focus was always on the buttons. This behavior can be replicated by placing any Focus-able Control on the form. (ie. TextBox)
I don't need ANY Kayboard interaction with these buttons, I want the user to interact with them with the mouse only.
I've tried the following techniques to try and get around this problem - none of these worked:
1) Normal KeyDown and KeyUp events of the form. (This is the way
I was capturing Keyboard input before placing the buttons.)
2) Overriding the Form's OnKeyDown and OnKeyUp events.
3) Overriding ProcessCmdKey - Works, but cannot differentiate
between KeyUp and KeyDown events, so it is inadequate for me.
I also tried create a MessageFilter for the application, but I couldn't force it to capture only the Keyboard keys that I needed.
I've been looking into this for many hours already and can't find a suitable solution.
Help would be greatly appreciated.
Here is a sample form with a IMessageFilter for the up and down arrow keys, hope this helps:
public partial class MainForm : Form
{
private class MessageFilter : IMessageFilter
{
public MainForm Main { get; set; }
public bool PreFilterMessage(ref Message msg)
{
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
if (msg.Msg == WM_KEYDOWN)
{
var keyData = (Keys)msg.WParam;
if (keyData == Keys.Down || keyData == Keys.Up)
{
return true; // Process keys before return
}
}
else if (msg.Msg == WM_KEYUP)
{
var keyData = (Keys)msg.WParam;
if (keyData == Keys.Down || keyData == Keys.Up)
{
return true; // Process keys before return
}
}
return false;
}
}
public MainForm()
{
this.InitializeComponent();
Application.AddMessageFilter(new MessageFilter { Main = this });
}
}
For a list of possible Windows messages check:
List Of Windows Messages
Set the KeyPreview property of the form to True, and then set event.Handled = True when you handle KeyDown/KeyUp. This will ensure that the form gets a chance to handle events before its children. Because you set the handled property to true, the childen won't see the keyboard events.
More info here: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview.aspx
I've got a C# winforms application that runs in the background, listening for hotkeys to be pressed. When a hotkey is pressed, my form makes a brief appearance. The form is always running, but set to hidden until I receive a hotkey event, at which time I set the visible property to true. The code looks like this:
void hook_volumeDown(object sender, KeyPressedEventArgs e)
{
this.Visible = true;
}
It should be noted that the topmost property of this form is set to true.
The really odd part is, after my C# app has stolen focus from another application, it will never do it again. For example: I launch my app, then launch some fullscreep app like Team Fortress 2. Then I press my hotkey. Team Fortress 2 minimizes, and I see my form. Then, however, I can restore TF2, and press my hotkey again all I want (with the desired effect), and TF2 will remain focused.
At any rate, I'm looking for a way to fix this. I've found a lot of questions here covering similar problems, but all of them are related to creating/launching a new form, not making an existing one visible (unless I missed something). I could rework the application to create a new form every time I need one, but that would entail creating yet another form to be invisible all the time just to wait for hotkey events, so I'd rather leave it as it is.
Any ideas?
I think you problem is related to the fact that Visible = true behaves differently between the first and subsequent calls. The first time visible is called and the window handle has not been created, the Window is created by calling CreateWindowEx which has some style parameters which controls how the window should behave. I think you need to make sure that the window is created with the style WS_EX_NOACTIVATE, which you can do by overriding CreateParams.
Other things to try out:
1) The ShowWindow function (used by Visible = true) ignores the focus parameter the first time it is called (http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx) if the program provides a STARTUPINFO structure. Dig into reflector and find out if the Form class provides a STARTUPINFO structure and if so, how to manipulate it.
2) The Form has a ShowWithoutActivation property than can be overriden and set to true, have you overriden this?
Sorry for the "no exact answer", but I hope this at least gives you some starting points for further investigation. Good luck.
Seeing KeyPressedEventArgs being used in your function looks really strange. Hot keys can be implemented by P/Invoking the RegisterHotKey() API function. It sends a message to your window when the hot key is pressed. Here's an example of a form that's invisible at start up, springs alive when you press the hot key. Ctrl+Alt+U in this case:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
private const int MYKEYID = 0; // In case you want to register more than one...
public Form1() {
InitializeComponent();
this.FormClosing += (s, args) => UnregisterHotKey(this.Handle, MYKEYID);
}
protected override void SetVisibleCore(bool value) {
if (value && !this.IsHandleCreated) {
this.CreateHandle();
RegisterHotKey(this.Handle, MYKEYID, MOD_CONTROL + MOD_SHIFT, Keys.U);
value = false;
}
base.SetVisibleCore(value);
}
protected override void WndProc(ref Message m) {
if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == MYKEYID) {
this.Visible = true;
if (this.WindowState == FormWindowState.Minimized)
this.WindowState = FormWindowState.Normal;
SetForegroundWindow(this.Handle);
}
base.WndProc(ref m);
}
// P/Invoke declarations
private const int WM_HOTKEY = 0x312;
private const int MOD_ALT = 1;
private const int MOD_CONTROL = 2;
private const int MOD_SHIFT = 4;
[DllImport("user32.dll")]
private static extern int RegisterHotKey(IntPtr hWnd, int id, int modifier, Keys vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
}
}
Note that the SetForegroundWindow() function is the rub, possibly also the source of the problem you describe in your question. Windows doesn't permit an app to shove a window in the user's face when the user is actively using another window. At least several seconds of inactivity must expire before it will allow the window to steal the focus. With the given code, that is easy enough to see, the taskbar button of your form will be blinking. Avoid setting the ShowInTaskbar property to false. It isn't necessary to do so with this code, the taskbar button won't show up until the hot key is pressed.
I want my application to be able to display certain information when no user input has been detected for some time (like a Welcome/Instruction layer). Is there anyway to have the application register any form of user input (keyboard, mousedown/move etc) without having to write handlers for each of those events?
Is there a generic input window message that gets sent before it is interpreted as being mouse or keyboard or other device? The behaviour I want is similar to Windows waking up from screen saver / sleep on keyboard or mouse input.
I want to avoid something like:
void SomeHandler(object sender, EventArgs e) { WakeUp(); }
...
this.KeyDown += SomeHandler;
this.MouseMove += SomeHandler;
this.SomeInputInteraction += SomeHandler;
The GetLastInputInfo Function is probably what you're looking for. It retrieves the time of the last input event.
I don't know if this works in WPF but this may help:
public class DetectInput : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
if ( m.Msg == (int)WindowsMessages.WM_KEYDOWN
|| m.Msg == (int)WindowsMessages.WM_MOUSEDOWN
// add more input types if you want
)
{
// Do your stuff here
}
return false;
}
}
and in Program:
Application.AddMessageFilter(new DetectInput ()); // Must come before Run
Application.Run(YourForm);
Maybe this article on CodeProject will help you. It is about automatically logging off after a period of inactivity using WPF.
Hope this helps.
I need to capture keystokes from a wedge device and prevent any controls or the form from receiving them. I also need to be able to know the value (char). I have tried overriding the ProcessCmdKey(Keys) and ProcessDialogChar(char) events. In the ProcessCmd event I can suppress the keystroke if it's one I want, but I the character isn't a parameter of the event. In the ProcessDialogChar event the character is there, but I cannot prevent the form or control with the focus from receiving the key. Suggestions?
You'll want to add this during Form load:
Application.AddMessageFilter(this);
Add this constant:
private const int WM_KEYDOWN = 0x100;
And this method:
public bool PreFilterMessage(ref Message m)
{
Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode;
bool retVal = false;
if (m.Msg == WM_KEYDOWN)
{
// Handle the keypress
retVal = true;
}
return retVal;
}
By returning true, your form and control(s) will never see the key press.
It was not how I wanted to do it, but because I needed to fix this and move on I put a hidden textbox on the form and as soon as I see the character that signals the possible start of the string of data I want to capture I set focus to that text box and respond to the TextChanged event. If I haven't seen the ending character before I timer expires I clear the textbox and start again. Kludge, but it works and got me to the next task.