I'm new to Qt as of a few weeks ago. I'm trying to rewrite a C# application with C++ and have a good portion of it figure now. My current challenge is finding a way to detect the system idle time.
With my C# application, I stole code from somewhere that looks like this:
public struct LastInputInfo
{
public uint cbSize;
public uint dwTime;
}
[DllImport("User32.dll")]
private static extern bool GetLastInputInfo(ref LastInputInfo plii);
/// <summary>
/// Returns the number of milliseconds since the last user input (or mouse movement)
/// </summary>
public static uint GetIdleTime()
{
LastInputInfo lastInput = new LastInputInfo();
lastInput.cbSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(lastInput);
GetLastInputInfo(ref lastInput);
return ((uint)Environment.TickCount - lastInput.dwTime);
}
I haven't yet learned how to reference Windows API functions through DLL Imports or whatever the C++ equivalent is. Honestly, I would prefer to avoid them if possible. This application is moving to Mac OSX and possibly Linux in the future as well.
Is there a Qt specific, platform-independent way to get the system idle-time? Meaning the user has not touched the mouse or any keys for X amount of time.
Thanks you in advance for any help you can provide.
Since no one seems to know, and I'm not sure that this is even possible, I decided to setup a low interval polling timer to check the current X, Y of the mouse. I know it's not a perfect solution, but...
It will work cross platform without me doing platform specific things (like DLL imports, yuck)
It serves the purpose I need it for: determining if someone is actively using the system or not
Yes, yes, I know there could be situations where someone may not have a mouse or whatever. I'm calling that a "low activity state" for now. Good enough. Here is the code:
mainwindow.h - Class declaration
private:
QPoint mouseLastPos;
QTimer *mouseTimer;
quint32 mouseIdleSeconds;
mainwindow.cpp - Constructor method
//Init
mouseTimer = new QTimer();
mouseLastPos = QCursor::pos();
mouseIdleSeconds = 0;
//Connect and Start
connect(mouseTimer, SIGNAL(timeout()), this, SLOT(mouseTimerTick()));
mouseTimer->start(1000);
mainwindow.cpp - Class body
void MainWindow::mouseTimerTick()
{
QPoint point = QCursor::pos();
if(point != mouseLastPos)
mouseIdleSeconds = 0;
else
mouseIdleSeconds++;
mouseLastPos = point;
//Here you could determine whatever to do
//with the total number of idle seconds.
}
Related
I am working on an Windows Form that will run to Lock the Desktop after x minutes of User's inactivity.
I tried GetLastInputInfo() but it only detect the User's inactivity based on Keyboard and Mouse movement only. Well, it is written on their explanation (or do I misunderstand it?).
This function is useful for input idle detection. However, GetLastInputInfo does not provide system-wide user input information across all running sessions. Rather, GetLastInputInfo provides session-specific user input information for only the session that invoked the function.
*Now I understand the definition of system-wide user input, thanks to #Garr Godfrey
And now, I want to extend the functionality by detecting a running media player (From web browser or Window's media player).
For example:
User "A" did nothing in his/her Desktop, so the Timer start
But if he/she watch a youtube video or a video through the Windows's media player, The timer is restarted to 0 again until the player stop playing any media.
My current Code is like this
public class Form1 : Form
{
private struct LASTINPUTINFO
{
public uint cbSize;
public uint dwTime;
}
[DllImport("user32.dll")]
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
public CancellationTokenSource ctsCheckInactive;
public int InactivityCheckTimeGap = 1 * 1000;
public int InactiveThresholdInS = 15 * 60 *1000; //15 minute
public Form1()
{
InitializeComponent();
CheckInactivity();
}
public void CheckInactivity()
{
ctsCheckInactive = new CancellationTokenSource();
var t = System.Threading.Tasks.Task.Run(async () => await CheckInactivityRoutine(ctsCheckInactive.Token), ctsCheckInactive.Token);
}
private async Task CheckInactivityRoutine(CancellationToken ct)
{
while (true)
{
var time = GetLastInputTime();
//Here I want to add Media Player Detection
//if(DetectMediaPlayer() == true){
// time = 0
//}
//For debugging
Console.WriteLine(time + " Sec");
If(time > InactiveThresholdInS){
//Lock the PC or show screen saver
}
ct.ThrowIfCancellationRequested();
await System.Threading.Tasks.Task.Delay(InactivityCheckTimeGap);
}
}
static uint GetLastInputTime()
{
uint idleTime = 0;
LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
lastInputInfo.dwTime = 0;
//Gets the number of milliseconds elapsed since the system started.
uint envTicks = (uint)Environment.TickCount;
if (GetLastInputInfo(ref lastInputInfo))
{
uint lastInputTick = lastInputInfo.dwTime;
idleTime = envTicks - lastInputTick;
}
return ((idleTime > 0) ? (idleTime / 1000) : 0);
}
}
Does anyone know how to achieve that?
My program is minimized to windows tray and always running after the user logged in. And it has the ability like this.
EDIT: Added pseudo code
System wide user input reflects the fact that multiple users could be logged in to the same computer and have different desktops and sessions. Some users may be connected via Remote Desktop, or simply there could be multiple users logged in and you are switching between them.
Detecting media playing is problematic. You may be able to use one of the audio interfaces and measure output volume levels, but that's a major PITA. Detecting video is likely impossible (short of packet sniffing to look for packets coming from known streaming sites, hardly worthwhile or bullet proof).
Instead, why not implement a screen saver executable? The media programs disable screen savers while they run, and Windows handles launching it when it should. You can do a lot of stuff from the EXE itself. You could even use built in screensavers and just apply the setting to lock screen when resuming.
EDIT: A screensaver is really any executable file, renamed to be .scr. Windows will execute it based on the system screensaver settings. There are a few extra windows messages to handle, so I put examples in comments.
I wonder whether from .Net managed code, or maybe p/invoking the needed NT dll, if I could generate a BSOD (Blue Screen Of Death) with specific bugcheck-code reason.
I know this is possible from a kernel-mode driver by calling KeBugCheck or KeBugCheckEx methods, but I think there is no way to call those methods from user-mode applications.
Someone could clarify me things, and bring an alternative way (if exists) for managed code?.
I had some code that did exactly that
here we go:
you might just need ntdll.dll but I used it without installing anything...
though the bug check codes don't seem to be the normal types
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
namespace bsod
{
class Program
{
private static uint STATUS_ASSERTION_FAILURE = 0xC0000420;
// private static uint KMODE_EXEPTION_NOT_HANDLED=0x0000008E;
static void Main(string[] args) {
while (Console.ReadKey(true).Key == ConsoleKey.W)
{
crash();
}
}
static void crash()
{
bool previousValue=false;
// Console.WriteLine("Adjusting privileges");
RtlAdjustPrivilege(19, true, false, out previousValue);
// Console.WriteLine("Triggering BSOD");
uint oul = 0;
IntPtr sptr = Marshal.StringToHGlobalAnsi("");
NtRaiseHardError(STATUS_ASSERTION_FAILURE, 0, 0, IntPtr.Zero, 6, out oul);
}
[DllImport("ntdll.dll")]
private static extern uint RtlAdjustPrivilege(
int Privilege,
bool bEnablePrivilege,
bool IsThreadPrivilege,
out bool PreviousValue
);
[DllImport("ntdll.dll")]
private static extern uint NtRaiseHardError(
uint ErrorStatus,
uint NumberOfParameters,
uint UnicodeStringParameterMask,
IntPtr Parameters,
uint ValidResponseOption,
out uint Response
);
}
}
let me clarify that this can be very dangerous, as you are one step away from an infinite loop constantly crashing your computer...
You can kill the csrss process, pretty simple:
System.Diagnostics.Process.GetProcessesByName("csrss").Single().Kill();
Even if that requires administrator rights
I can't say for certain that the kernel does not provide some means of invoking KeBugCheck with arbitrary arguments from user mode, even if just for highly privileged processes, but I very much hope none does and I certainly sympathise with anyone who wonders why on earth you would want something like this to exist let alone to use it.
Of course, even if the kernel doesn't already expose it for calling from user mode, it is readily available in kernel mode, i.e., to be called by drivers. Even there, however, drivers are strongly discouraged from resorting to it in any code that's ever released. Though a driver could expose a user-mode interface, e.g., through Device I/O Control, for calling KeBugCheck on behalf of a user-mode client, even an unprivileged one, doing so would be incredibly irresponsible of a driver writer (except, perhaps, for private testing).
As for CSRSS, some of you may want to know as background (and perhaps know already) that the architecture has long allowed that CSRSS needn't be critical (in the sense that killing it kills Windows) and also that it needn't be the only one. There is an undocumented function RtlSetProcessIsCritical which programs such as CSRSS call to register themselves as being so vital that when the kernel sees them exit then the kernel should raise either of two particular bug checks.
I am working on a C# application which runs in the background without any Windows control.
I want to notify Windows that my application is still alive to prevent Windows from going into the idle state.
Are there any APIs available to call from my application which notify the Windows OS that my application is still alive?
Thanks in advance.
You've to use SetThreadExecutionState function. Something like this:
public partial class MyWinForm: Window
{
private uint fPreviousExecutionState;
public Window1()
{
InitializeComponent();
// Set new state to prevent system sleep
fPreviousExecutionState = NativeMethods.SetThreadExecutionState(
NativeMethods.ES_CONTINUOUS | NativeMethods.ES_SYSTEM_REQUIRED);
if (fPreviousExecutionState == 0)
{
Console.WriteLine("SetThreadExecutionState failed. Do something here...");
Close();
}
}
protected override void OnClosed(System.EventArgs e)
{
base.OnClosed(e);
// Restore previous state
if (NativeMethods.SetThreadExecutionState(fPreviousExecutionState) == 0)
{
// No way to recover; already exiting
}
}
}
internal static class NativeMethods
{
// Import SetThreadExecutionState Win32 API and necessary flags
[DllImport("kernel32.dll")]
public static extern uint SetThreadExecutionState(uint esFlags);
public const uint ES_CONTINUOUS = 0x80000000;
public const uint ES_SYSTEM_REQUIRED = 0x00000001;
}
You have a couple of options:
Use SetThreadExecutionState, which:
Enables an application to inform the system that it is in use, thereby preventing the system from entering sleep or turning off the display while the application is running.
Where you could use the ES_SYSTEM_REQUIRED flag to
Forces the system to be in the working state by resetting the system idle timer.
Use SendInput to fake keystroke, mouse motion/clicks
Another alternative would be to change your app to be a Windows service.
SetThreadExecutionState example
// Television recording is beginning. Enable away mode and prevent
// the sleep idle time-out.
SetThreadExecutionState(
ES_CONTINUOUS |
ES_SYSTEM_REQUIRED |
ES_AWAYMODE_REQUIRED);
// Wait until recording is complete...
// Clear EXECUTION_STATE flags to disable away mode and allow the system
// to idle to sleep normally.
SetThreadExecutionState(ES_CONTINUOUS);
You can use SetThreadExecutionState described here:
SetThreadExecutionState Function
Since it is a Win32 API function, to use it from C# you'll need to PInvoke it. The steps are described here, including a sample method PreventSleep to temporarily disable sleep mode:
PInvoke.net: setthreadexecutionstate (kernel32)
I don't think there's any way to do this directly in managed code.
A quick search reveals this post from 2 years ago. Basically you'd need to do some interop to call a raw windows API.
Here is SetThreadExecutionState C# implementation
I have a desktop application in which I would like to know two things:
Is the user currently on the PC (more specifically, is he giving any input to the PC), so I can change his state to "away" if needed; and
Is the screensaver running right now, so I can perform more CPU intensive work during that time.
I'm using C#/.NET. How would you suggest to tackle these two tasks?
NOTE: WIN32 invocation will be just as good, as well as any unmanaged code solution.
http://dataerror.blogspot.com/2005/02/detect-windows-idle-time.html
^ Detect Windows Idle Time. :)
The enabler for this feature is the GetLastInputInfo() Win32 API and the LASTINPUTINFO Win32 structure.
Here is the code to detect if a screen saver is running. See this for more details
const int SPI_GETSCREENSAVERRUNNING = 114;
[DllImport( "user32.dll", CharSet = CharSet.Auto )]
private static extern bool SystemParametersInfo(
int uAction, int uParam, ref bool lpvParam,
int flags );
// Returns TRUE if the screen saver is actually running
public static bool GetScreenSaverRunning( )
{
bool isRunning = false;
SystemParametersInfo( SPI_GETSCREENSAVERRUNNING, 0,
ref isRunning, 0 );
return isRunning;
}
Rather than figuring out when to run more intensive work... Consider doing your "intensive work" as early as you can, but at a lower thread priority.
I don't think your questions have an answer in pure C#, unless you poll the mouse position and observe movements... Or something like that.
You could use a global keyboard/mouse hook and just reset your "counter" to 0 when you receive an event from either. When your counter reaches the idle time that you're looking for, perform your background actions.
There is some code here that allows you to easily do the hooking in .NET: http://www.codeproject.com/KB/cs/globalhook.aspx
How can I prevent the pocket PC device from shutting down from my application when the power button pressed? I am using C#.
You could use the Microsoft.WindowsCE.Form.MessageWindows class to intercept the Power Button event. This solution will not be portable, as the hardware key will be different in different machines.
I recommend however that you don't disable power down completely. Have a look at my answer in another question here. You could also use openetcf to easily create power down events handlers and register wake up events. You should implement the application logic based on what you are trying to achieve, for instance wake up every one minute to run a process.
You can try changing the power requirements for the device "BLK1:", which is the blacklight device. Be aware that the behavior may not be the same on all devices and version of the OS or Vendor specific Extensions.
To do this, you can write something like :
[DllImport("coredll")]
private extern static IntPtr SetPowerRequirement(string pvDevice, int deviceState,
int deviceFlags, IntPtr pvSystemState, int stateFlags);
[DllImport("coredll")]
private extern static int ReleasePowerRequirement(IntPtr handle);
and call it this way :
IntPtr handle = SetPowerRequirement("BLK1:", 0 /* D0, Full On */, 1, IntPtr.Zero, 0);
// Do something that requires the device to stay on ...
ReleasePowerRequirement(handle);
But this is generally not a good practice, leaving a device with the backlight on for extended periods might reduce dramatically its autonomy.