Is it possible to capture any unspecific input event in C#? - c#

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.

Related

SendKeys.Send() does not send or react as I expect

I have a problem using Sendkeys.Send in my C# application and I really cannot understand why. When using it then it does not send what I expect to the active application. I am using it together with the global hotkey manager, https://github.com/thomaslevesque/NHotkey
I have created this simple PoC that, for my part at least, will be able to reproduce my problem. Just launch Wordpad and press the hotkey, ALT + O:
using System.Windows.Forms;
using System.Diagnostics;
using NHotkey.WindowsForms;
namespace WindowsFormsApp5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Convert string to keys
string hotkey = "Alt + O";
KeysConverter cvt;
Keys key;
cvt = new KeysConverter();
key = (Keys)cvt.ConvertFrom(hotkey);
// Setup the hotkey
HotkeyManager.Current.AddOrReplace("MyID", key, HotkeyAction);
// Copy some text to the clipboard that I want to paste to the active application
Clipboard.SetText("My String");
}
private void HotkeyAction(object sender, NHotkey.HotkeyEventArgs e)
{
Debug.WriteLine("Pressed the hotkey");
SendKeys.Send("^v");
// SendKeys.Send("Test string");
e.Handled = true;
}
}
}
When I do this in Wordpad, then instead of pasting the clipboard (^v equals CTRL + V) then it tries to "Paste Special":
Even if I do the most simple thing and then just put some text in SendKeys.Send, then it seems to be messing with the menus in Wordpad? SendKeys.SendWait is not any different.
I have been trying to figure this out for quite some time now but I simply do not understand why it does that. Basically, I need to paste the clipboard on a hotkey though it doesn't need to be with this exact method so if anyone knows another way of doing it then I would appreciate some hints.
MY IMPLEMENTED SOLUTION
Based on the accepted answer then I did change my implementation slightly as I could not get it working with just a timer. I may have missed something(?) but this is working.
In basic then I change focus to my application as soon as the hotkey is detected, to avoid conflict with modifier keys (ALT etc) in the active application. I then create an invisible form and when I detect a KeyUp event, then I check for modifier keys and if none is pressed down then I enable a timer and immediately switch focus back to the originating application. After 50ms the clipboard will be pasted to the active application.
Something like this:
// Somewhere else in code but nice to know
// IntPtr activeApp = GetForegroundWindow(); // get HWnd for active application
// SetForegroundWindow(this.Handle); // switch to my application
private System.Timers.Timer timerPasteOnHotkey = new System.Timers.Timer();
// Main
public PasteOnHotkey()
{
InitializeComponent();
// Define the timer
timerPasteOnHotkey.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timerPasteOnHotkey.Interval = 50;
timerPasteOnHotkey.Enabled = false;
// Make the form invisble
this.Size = new System.Drawing.Size(0, 0);
this.Opacity = 0.0;
}
private void PasteOnHotkey_KeyUp(object sender, KeyEventArgs e)
{
// Check if modifier keys are pressed
bool isShift = e.Shift;
bool isAlt = e.Alt;
bool isControl = e.Control;
// Proceed if no modifier keys are pressed down
if (!isShift && !isAlt && !isControl)
{
Hide();
// Start the timer and change focus to the active application
timerPasteOnHotkey.Enabled = true;
SetForegroundWindow(activeApp);
}
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
timerPasteOnHotkey.Enabled = false;
SendKeys.SendWait("^v"); // send "CTRL + v" (paste from clipboard)
}
When you use SendKeys.Send in a response to a key press then the keys you send may be combined with the physical keys you’re holding at that moment. In this case you’re holding Alt, so Wordpad assumes you pressed Alt-Ctrl-V instead of just Ctrl-V. Also Alt opens menu, so sending other keys may relate to hotkeys there.
Adding a delay will remove this issue, and usually when sending key presses it would be done as not relating to other key presses so it won’t be a problem.

How to execute code when Universal Windows Store App is closing?

I am developing an app for Windows 10 Store app, but I can't seem to find/learn on how to check if the user pressed the red close button (at the top right) or by pressing Alt + F4. Basically what I want is something like this:
private void app_Close(object sender, CloseEventArgs e)
{
//saves some data in the app :D
}
.: EDIT :.
If you have a Universal app that doesn't have a MainWindow object you'll probably want to tap into the "Suspending" event:
appObject.Suspending += (s, a) =>
{
SaveTheData(); // I really like my data and want it for later too
};
or
public App()
{
/*
stuff
*/
Suspending += (s, a) =>
{
SaveTheData(); // I really like my data and want it for later too
};
}
.: Original :.
Add a handler to your MainWindow "Closing" event to save your data. Once "Closing" has finished, "Close" should fire normally.
theMainWindowObject.Closing += (s,a) =>
{
SaveTheData(); // It's precious!
};
I have something similar to this in one of my smaller applications where in the constructor for MainWindow I put the above snippet substituting "theMainWindowObject" for "this" so that it references itself
So I have:
public MainWindow()
{
// Note: "this." isn't necessary here but it helps me with mental accounting
this.Closing += (s, a) =>
{
Save();
};
}
If you're just saving one or two properties and don't have any crazy logic going on you can just drop it right in the handler:
public MainWindow()
{
Closing += (s, a) =>
{
Properties.Settings.Default.SettingsPopupX = mySettingsPopupObject.GetX();
Properties.Settings.Default.SettingsPopupY = mySettingsPopupObject.GetY();
Properties.Settings.Default.Save();
};
}
If you want to manage your Application Lifecycle have a look at this MSDN article: https://msdn.microsoft.com/en-us/library/windows/apps/mt243287.aspx
In general you don't have a "close" event in Windows Apps. Your App will be suspended when Windows or your user wants to close it. Using the ApplicationExecutionState (see more) enum you can find out who (windows or your user) closed the app.
Hope it helps!

C# Events / Block when hit GUI

I'm working on a custom GUI with SharpDX.
I have user Input from a Form Object and assign Action Methods to the specific events. Below my UI I have a "drawing canvas" and I use Tool Objects that also listen to those Form Events.
But I'm a bit stuck on the matter of how to design my program to only pass those events to a second layer (in this case my canvas) when the first layer did not "hit" anything. In short: Only call "Tool.OnMouseDown" when "Button.OnMouseDown" did return false? Would a Chain Of Responsibility be the/a correct or possible approach?
Or shall I make the current Tool check if "Excecute (Vector2)" is above some gui element but I think this would lead to the kind of coupling I want to prevent.
Hope someone is willing to help/hint (sorry for no code examples, if it's to confusingly descriped please tell me ;))
Thanks!
(Disclaimer: I know I don't have to reinvent the wheel, but I use it partly to learn and improve on my design patterns and coding skills)
thanks to sharp-ninja's answer i did the following:
ok working with it like this now :) thanks again Mister Ninja
using System.Windows.Forms;
public class HandleMouseEventArgs : MouseEventArgs
{
public bool handled { get; protected set; }
public HandleMouseEventArgs(MouseEventArgs args) : base(args.Button, args.Clicks, args.X, args.Y, args.Delta)
{
handled = false;
}
public void SetHandled()
{
handled = true;
}
}
Fortunately in .Net events get called in the order in which they are registered. You can use a handlable event arg so that the first handler of the event can tell subsequent event handlers whether the event was handled.
event EventHandler<MyHandlableEventArg> MultiLevelEvent;
Then in your main program:
// First event handler
MultiLevelEvent += (s, e) => { if(x) e.Handled = true; };
// Subsequent event handler
MultiLevelEvent += (s, e) => { if(!e.Handled) { /* Do Work */ } };

How to check whether the program is being used?

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;
}
}

Maximize C# Application from System Tray using Keyboard Shortcut

Can I know if there is anyway that I can maximise my windows form application from the system tray using say a Keyboard Shortcut rather than clicking on it?
I am currently minimizing using this piece of code
//Minimize to Tray with over-ride for short cut
private void MinimiseToTray(bool shortCutPressed)
{
notifyIcon.BalloonTipTitle = "Minimize to Tray App";
notifyIcon.BalloonTipText = "You have successfully minimized your app.";
if (FormWindowState.Minimized == this.WindowState || shortCutPressed)
{
notifyIcon.Visible = true;
notifyIcon.ShowBalloonTip(500);
this.Hide();
}
else if (FormWindowState.Normal == this.WindowState)
{
notifyIcon.Visible = false;
}
}
Hence, I need a keyboard shortcut that should maximize it. Much thanks!
EDIT: If you simply want to 'reserve a key combination' to perform something on your application, a Low-Level keyboard hook whereby you see every keypress going to any other application is not only an overkill, but bad practice and in my personal view likely to have people thinking that you're keylogging! Stick to a HOT-KEY!
Given that your icon will not have keyboard focus, you need to register a global keyboard hotkey.
Other similar questions:
How can I register a global hot key to say CTRL+SHIFT+(LETTER)
Best way to tackle global hotkey processing in c#?
Example from Global Hotkeys With .NET:
Hotkey hk = new Hotkey();
hk.KeyCode = Keys.1;
hk.Windows = true;
hk.Pressed += delegate { Console.WriteLine("Windows+1 pressed!"); };
if (!hk.GetCanRegister(myForm))
{
Console.WriteLine("Whoops, looks like attempts to register will fail " +
"or throw an exception, show error to user");
}
else
{
hk.Register(myForm);
}
// .. later, at some point
if (hk.Registered)
{
hk.Unregister();
}
To do this, you must use "Low-Level Hook".
You will find all information about it on this article : http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx
Look at this too : http://www.codeproject.com/Articles/6362/Global-System-Hooks-in-NET
I second Franck's suggestion about a global keyboard hook. Personally, I had very good experiences with the CodeProject article "Processing Global Mouse and Keyboard Hooks in C#".
As they write in their article, you can do things like:
private UserActivityHook _actHook;
private void MainFormLoad(object sender, System.EventArgs e)
{
_actHook = new UserActivityHook();
_actHook.KeyPress += new KeyPressEventHandler(MyKeyPress);
}
You could then call a function in your MyKeyPress handler that opens your window.
If you follow the guide here. It will show you how to register a global shortcut key.
public partial class Form1 : Form
{
KeyboardHook hook = new KeyboardHook();
public Form1()
{
InitializeComponent();
// register the event that is fired after the key press.
hook.KeyPressed += new EventHandler<KeyPressedEventArgs>(hook_KeyPressed);
// register the CONTROL + ALT + F12 combination as hot key.
// You can change this.
hook.RegisterHotKey(ModifierKeys.Control | ModifierKeys.Alt, Keys.F12);
}
private void hook_KeyPressed(object sender, KeyPressedEventArgs e)
{
// Trigger your function
MinimiseToTray(true);
}
private void MinimiseToTray(bool shortCutPressed)
{
// ... Your code
}
}

Categories