C# For how long was user inactive - c#

Some background:
I am writing a application with several forms, etc. Users have to log in in order to use most of the features, and this worked fine until now. However, now, client has requested that the user would be logged out after a certain amount of inactive time. The problem is that the user can still be active on the computer, just not in my application,. To be clear, I have to log the user out when he is inactive in my application, even if he is still interacting with the desktop.
First I thought this would be fairly simple. Just remember the time of the last action, compare it continually in a timer with current time and log out the user if the time passed is greater than the allowed time. However I have realised that finding out the last action time may not be so simple...
Of course I could copy paste something like
Program.LastActionTime = DateTime.Now;
in every OnChange, OnClick, etc, event ... However not only that this would be a great amount of work because of the size of the application ... It would also be a very bad practice and I'm sure it would be forgot at least once, making the whole thing unreliable (And appear broken, the bug would be almost impossible to reproduce!)
So, is there a better way?

One approach that I've used in the past, create a MessageFilter on your application form and check for certain types of events that indicate user activity:
public class UserActivityFilter : IMessageFilter
{
// Define WinAPI window message values (see pinvoke.net)
private int WM_LBUTTONDOWN = 0x0201;
private int WM_MBUTTONDOWN = 0x0207;
private int WM_RBUTTONDOWN = 0x0204;
private int WM_MOUSEWHEEL = 0x020A;
private int WM_MOUSEMOVE = 0x0200;
private int WM_KEYDOWN = 0x0100;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_MBUTTONDOWN || m.Msg == WM_RBUTTONDOWN || m.Msg == WM_MOUSEWHEEL || m.Msg == WM_MOUSEMOVE || m.Msg == WM_KEYDOWN)
{
//User activity has occurred
// Reset a flag / timer etc.
}
return false;
}
}
Then in the Main() method of the form, BEFORE the call to Run():
Application.AddMessageFilter(new UserActivityFilter());
One caveat, adding a complex message filter or adding multiple separate filters can slow down the responsiveness of your application.

In your Program.CS file, you can handle the Application.Idle event and reset your timer there. See:
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.idle.aspx

You can override WndProc, update Program.LastActionTime on each relevant Keyboard/Mouse event message.

Hook an event handler on the MouseMove and KeyPressed events, and then check for focus inside that event?

In general it would be the best idea to derive this information from your application logic instead of raw user input, but I assume you have no flexible infrastructure (maybe using the command pattern) that could provide this information.
So I suggest just to register handlers with your main form - if you receive clicks or key events (enable Form.KeyPreview for this), your user is active and you can reset the inactivity time.

You could create a base class that all your window forms inherits from. In the base class you check and reset your timeout on every KeyPress or Click.

Related

C#: Get informed when any new process is started / any new window is opened

I need to check when a new process with a new visible main window handle is started (as the mouse hook of my app is lost on some applications and is restored only on a short internal restart).
I have tried to use EnumWindows and EnumDesktopWindows but those give me many many windows and child windows I do not need. I only need the visible main window handles. Therefore (and to find out if they are belonging to a new process) I decided to directly check the processes within an own update-check-thread. But this approach (as well as to permanently check EnumWindows) is extremely cpu consuming (1-3 % at Ryzen 5600X) and in my opinion, completely overblown.
Therefore I'd like to know if there is any other, slick approach to find out whenever any new process is started or window is opened to only execute the check when it is necessary.
Polling is never a good solution.
If you are already hooking, why not use WH_SHELL, WH_CBT or SetWinEventHook()?
I solved it by using/extracting the ApplicationWatcher from this Package with minor adjustments to run it within .NET v4.5.2 and to get rid of all unnecessary things.
The application event hook only works for apps/windows which are started after the event hook has been launched which is sufficient for my purposes. If one needs all existing windows as well, you once need to add all existing windows to the activeWindows property of the ApplicationWatcher class.
Furthermore, the WindowsActivated event seems to be bugged. Herefore, you need to adjust the following things:
Within the ApplicationWatcher class
private void WindowActivated(WindowData wnd) {
if (_ActiveWindows.ContainsKey(wnd.HWnd)) {
if (!_LastEventWasLaunched) { // < if condition adjusted
ApplicationStatus(_ActiveWindows[wnd.HWnd], ApplicationEvents.Activated);
}
}
_LastEventWasLaunched = false;
}
and within the ShellHook class
protected override void WndProc(ref Message m) {
if (m.Msg == _wmShellHook) {
switch ((User32.ShellEvents)m.WParam) {
...
case User32.ShellEvents.HSHELL_RUDEAPPACTIVATED: // < line added
case User32.ShellEvents.HSHELL_WINDOWACTIVATED:
if (WindowActivated != null) {
WindowActivated.Invoke(this, m.LParam);
}
break;
}
}
base.WndProc(ref m);
}
Works like a charme and my CPU usage went down to 0 %.

Using Remote Control Input Outside of Windows Media Center C#

I would like to make a very simple C# windows form application (or WPF) that can be controlled by the Media Center Remote Control that came with the computer.
It's a very simple app that has an event listener that receives messages from the remote and calls the appropriate function.
I found this article that explains how to do it yet I was not able to follow up:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb417079.aspx
I've read the article many times yet I have no clue how execute it.
I'm novice when it comes to HID programing,
so please try to be as clear and detailed as possible.
A full example would be appreciated.
Thank You
Thank You Corey your answer was very helpfull, I mixed it with another code I found:
http://discuss.mediacentersandbox.com/forums/thread/8549.aspx
and it worked
I don't have a Media Center Remote to test with, but from what I can find...
Pressing buttons on the MC remote will result in one of three types messages being sent to your application: WM_APPCOMMAND, WM_KEYDOWN or WM_INPUT. The first two are fairly simple - just synthetic keyboard interactions. The third is the difficult one.
First, you need to call RegisterRawInputDevices with an array of RAWINPUTDEVICE structures that indicate the data your application is interested in. In this case you'll need at least Page 0x000C Collection 0x01 and Page 0xFFBC Collection 0x88 to get the majority of the buttons. If you want to handle the Standyby button you also need Page 0x0001 Collection 0x80.
After that call you will get WM_INPUT messages for each button. This is as far as I can go at the moment, since I haven't found a decent explanation of the content of the HIDRAW structure beyond the fact that it can contain data for multiple events. I'd suggest dumping it out and seeing if you can locate the appropriate codes - from the Button Usage ID column.
Edit: processing the messages
In order to process the WM_APPCOMMAND messages you'll need to override the WndProc method of your form:
// Some of the named constants:
const int WM_APPCOMMAND = 0x0319;
const int APPCOMMAND_BROWSER_BACK = 1;
const int APPCOMMAND_MEDIA_CHANNEL_DOWN = 52;
const int APPCOMMAND_MEDIA_CHANNEL_UP = 51;
const int APPCOMMAND_MEDIA_FAST_FORWARD = 49;
const int APPCOMMAND_VOLUME_MUTE = 8;
const int APPCOMMAND_MEDIA_PAUSE = 14;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_APPCOMMAND)
{
int lParam = unchecked ((int)m.LParam);
int cmd = unchecked ((short)((uint)lParam>>16));
switch (cmd)
{
case APPCOMMAND_BROWSER_BACK:
// process 'back' button
break;
case APPCOMMAND_MEDIA_CHANNEL_DOWN:
// process 'channel down' command
break;
}
}
base.WndProc(ref m);
}
There are more, but that's the gist of it. You'll need to find the values for the various named constants.

Send Windows key keypress into application [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to detect the currently pressed key?
(EDIT: For what it's worth, this is not a duplicate... not sure why it was voted as such)
I have a small timer application that we use in the office to track the hours spent on a project. There is a start and stop button, and a project and task fields. When we go on break and to lunch and other things, we stop the timer for that project, then restart it. This is a repetitive task that generally involves digging the window out from behind several other Windows, then the same after the break.
What I want to do is assign WindowKey+W to the work timer application and have it not only bring the timer application to the front and focus it, but also have it toggle the Start/Stop.
I have tried a number of searches, but I can't seem to narrow down the examples to what I want. I do know that you can open the properties of a Windows shortcut and assign a shortcut key to launch a program, and (I guess?) if you have that app already open and it is set to allow only one instance of the program that it will bring that program to the front??? maybe..
Anyway.. but that method will not accept the WindowsKey as a valid key combo. And I don't know if it can somehow pass that key combo in to the program.
I appreciate any help or direction here!!
EDIT - Answer Update
Thank you #huadianz for your answer! I converted your code to VB:
Public Const MOD_WIN As Integer = &H8
Public Const KEY_W As Integer = &H57
<DllImport("user32.dll")> _
Public Shared Function RegisterHotKey(hWnd As IntPtr, id As Integer, fsModifiers As Integer, vlc As Integer) As Boolean
End Function
<DllImport("user32.dll")> _
Public Shared Function UnregisterHotKey(hWnd As IntPtr, id As Integer) As Boolean
End Function
Public Sub RegisterKeys()
RegisterHotKey(Me.Handle, 1, MOD_WIN, KEY_W)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
If (m.Msg = &H312) Then
Me.TopMost = True
Me.PlayPauseTimer()
Me.TopMost = False
End If
End Sub
On an interesting note, Me.BringToFront() would not actually bring the application to the front in this scenario in Win7, nor did Me.Focus(). However, Me.TopMost = True worked, but it has the secondary effect of making the window always on top. Setting it to True, toggling the timer, then setting it back to False works great!
If you want full operating system intergration, you can hook into the kernel input functions by using PInvoke.
What you are looking for is the explorer.exe Windows API function, described in detail here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646309%28v=vs.85%29.aspx
Using PInvoke, you can invoke this C++ function
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
public const int MOD_WIN = 0x00000008;
public const int KEY_W = 0x00000057
public static void RegisterKeys()
{
RegisterHotKey((IntPtr)this.Handle, 1, MOD_WIN, KEY_W);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x0312)
this.Visible = !this.Visible;
}
I would also suggest looking at Auto Hotkey: http://www.autohotkey.com/. If all you're after is sending a window to front on key-press then you may find it faster to learn AHK and write a script to do so (be only 1 or 2 lines) than writing something in C# or VB.
*edit*As regards pressing a button automatically, if it's set as the default button then you can just send the enter keystroke to it. Otherwise you may need to send a mouse click even to the window. Neither is particularly difficult once you have the first part done.
#W::MsgBox "This is a message box. You just need to use something like send to send keystrokes and other commands to the window you want to control, instead of the this message box."
You can use Windows SendKeys. If you look at that link it shows the codes and syntax for applying a ctrl, alt or shift key. I imagine you can send these keys to your application to simulate a shortcut press.

Alternative Input Device(Midi) doesn't prevent Screen Saver in Winforms application

I have developed a C# WinForms application whereby the user is providing input via a MIDI-connected device. The user will go for long periods without using the keyboard or mouse.
When I receive a MIDI message, is there anything I can do to "tell" the system that this counts as user activity (i.e., key press). I don't want the screen saver or time lockouts to occur if the MIDI device is actively being used.
I think my request is different than other requests I've seen because they want to disable screen savers for the life of their application whereby I just want MIDI input I receive to count as user interactivity.
Is there something I can call when I receive MIDI input to signify to the system user activity?
Here's a CodeProject project that appears to do this:
http://www.codeproject.com/KB/cs/ScreenSaverControl.aspx
Looks like you can just call his SetScreenSaverTimeout(GetScreenSaverTimeout()) method every time you receive MIDI input.
Windows sends out a message to each window before activating the screen saver or monitor power saver, all you need to do to prevent the screen from changing is to swallow these messages.
const int WM_SYSCOMMAND = 0x0112, SC_SCREENSAVE = 0xF140, SC_MONITORPOWER = 0xF170;
protected override void WndProc(ref Message m)
{
if( m.Msg == WM_SYSCOMMAND ) //Intercept System Command
{
if( m.WParam.ToInt32() == SC_SCREENSAVE || m.WParam.ToInt32() == SC_MONITORPOWER )
{
//Intercept ScreenSaver and Monitor Power Messages
//MessageBox.Show("Reached SC/PowerCondition");
return; //
}
}
base.WndProc(ref m);
}
The sample code, along with further reading, is from this developer fusion thread.

keyboard Events

whenever i am pressing key in my server system i ll send that keyevent to another system after that the correspondingaction should be happend in the client machine.. help me to get a better way to solve this problem
thanx in advance
If I understand it correctly then what you have doesn't sound too bad. Are you saying that:
You have a client server architecture.
At the server (presumably at command console or management application) you press a key.
The key corresponds to an action. The action needs to be invoked at the client.
You could implement this using asynchronous WCF. See here and here for more some more info. One way to look at this problem is as a distributed observer pattern. Your server is the subject and the client(s) are the observer(s).
Update: Handling Key Events in .Net
You could try adding a KeyDown event handler to your form:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control & e.KeyCode == Keys.C)
{
MessageBox.Show( "Ctrl + C pressed" );
// Swallow key event, i.e. indicate that it was handled.
e.Handled = true;
}
}
But if you have any controls on your form then you won't get the event. What you probably need to do is sniff windows messages using a message filter. E.g.
public class KeyDownMessageFilter : IMessageFilter
{
public const int WM_KEYDOWN = 0x0100;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_KEYDOWN)
{
// Key Down
return true; // Event handled
}
return false;
}
}
Add this message filter to the application using the AddMessageFilter method. If you want to check if the CTRL key is pressed for the key down message then check the lparam.
If any of this isn't clear then let me know.
please give us more details on what you're trying to do.
To simulate key presses in Windows Forms, I'd use SendKeys class.

Categories