My application needs to resume operations after the system wakes up after sleep. To do that, the app registers a PowerModeChanged event listener, waiting for PowerMode.Resume, where some bookkeeping needs to be done.
This code worked quite well with Windows 7, but with Windows 10 the PowerModeChanged does not fire until a key is pressed or mouse is moved.
public Shell()
{
Logging.LogMethodEntry();
try
{
InitializeComponent();
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
}
catch (Exception exc)
{
Logging.LogException(exc);
}
Logging.LogMethodExit();
}
private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
Logging.LogMethodEntry(sender, e);
try
{
switch (e.Mode)
{
case PowerModes.StatusChange
case PowerModes.Resume:
Logging.LogInfo("Resuming...");
// some code here
break;
}
}
catch (Exception exc)
{
Logging.LogException(exc);
}
Logging.LogMethodExit();
}
I could not find any hint about any changes that were introduced in this mechanics for Windows 10, but maybe there is some settings I'm just not aware of...
The PowerModeChanged event relies upon the WM_POWERBROADCAST windows event. We note from the documentation for that event that there are two different resume events - PBT_APMRESUMEAUTOMATIC and PBT_APMRESUMESUSPEND.
We can see from the reference source that .NET only looks for the second of these events, not the first, and the second is defined only to fire
if the resume is triggered by user input, such as pressing a key.
Which appears to match your experience. You may wish to put your own message handler in place to watch for the first event. But note -
In Windows 10, version 1507 systems or later, if the system is resuming from sleep only to immediately enter hibernation, this event is not delivered. A WM_POWERBROADCAST message is not sent in this case.
Related
I'm working on a Windows forms application that needs to perform some logic before the PC goes to sleep. I've looked through many threads and found this which should work perfectly: Link. I can detect when the power is plugged/unplugged just fine, but I've run into serious problems when trying to detect a sleep/suspend event.
Using the logic mentioned, I have this section of code in my program:
public void powerModeChanged(object sender, PowerModeChangedEventArgs args)
{
if (args.Mode == PowerModes.Suspend)
{
Trace.WriteLine("Sleeping.....");
}
else if (args.Mode == PowerModes.StatusChange)
{
Trace.WriteLine("Other Status Change:");
}
}
public MainPage()
{
InitializeComponent();
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(powerModeChanged);
Per this documentation page - Link, there are 3 types of power modes. The statusChange is detected as expected when I unplug and replug the power adapter into my laptop, and prints to the debug Window just fine. However, it will not detect when I put the computer to sleep. After going over this for hours, my conclusion is that what the version of Windows 10 I'm running defines as "sleep" doesn't match up with the event that I'm checking for.
There is a comment on that initial thread in the first link that says the solution I tried doesn't seem to work with the "new Connected/Modern Standby modes" and provides a link to this thread: Link where it describes using the session switch event handler instead. This works on my laptop as my laptop locks upon sleep, but when testing on a Surface tablet (which is our target device for operation), it doesn't work due to the surface not locking upon sleep.
Of course, I could just set the device to lock on sleep, and that may end up being the only solution, but I wanted to see if there was something I was overlooking or any other way to check for sleep in modern versions of Windows. As it stands, I would hate for this important feature of the application depend on the system having to be setup to lock when sleeping. Thanks!
You could use the SystemEvents.PowerModeChanged event to detect when the computer is about to go to sleep. Within the event handler, you can perform any logic that needs to be done before the computer goes to sleep. For example, you could write commands to the windows registry or perform some other related tasks.
Below is an example of how this could be done:
// Register the SystemEvents.PowerModeChanged event handler
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
// Event handler for SystemEvents.PowerModeChanged
private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
// Check if the computer is about to go to sleep
if (e.Mode == PowerModes.Suspend)
{
// Perform the logic that needs to be done before the computer goes to sleep
// ...
}
}
I ended up finding this thread, the answer on that thread solves this issue.
Link to Solution
We are using Microsoft's UIAutomation framework to develop a client that monitors events of a specific application and responds to them in different ways. We've started with the managed version of the framework, but due to delay issues, moved to the native version wrapped in UIACOMWrapper. After more issues with performance inside our (massive) WPF application, we decided to move it to a separate terminal application (transfer the events to our WPF app through UDP) which seemed to fix all the performance issues. The only problem is that it seems that every several minutes, the events for TabSelection, StructureChanged, WindowOpened and WindowClosed stop being captured for a few minutes. Surprisingly PropertyChanged events are still received and handled while this happens. I will post the relevant code of our event monitor, but this is probably irrelevant as we have seen similar behavior when using Microsoft's own AccEvent utility. I can't post the code of the monitored application as it is proprietary and confidential as well, I can say that it is a WinForms application that hosts WPF windows and also quite massive.
Has anyone seen this sort of behavior while working with the UI Automation framework?
Thank you for your time.
Here's the monitor code (I know the event handling is on the UI Automation threads here but moving it to a dedicated thread did not change anything):
public void registerHandlers()
{
//Register on structure changed and window opened events
System.Windows.Automation.Automation.AddStructureChangedEventHandler(
this.getMsAutomationElement(), System.Windows.Automation.TreeScope.Subtree, this.handleStructureChanged);
System.Windows.Automation.Automation.AddAutomationEventHandler(
System.Windows.Automation.WindowPattern.WindowOpenedEvent,
this.getMsAutomationElement(),
System.Windows.Automation.TreeScope.Subtree,
this.handleWindowOpened);
System.Windows.Automation.Automation.AddAutomationEventHandler(
System.Windows.Automation.WindowPattern.WindowClosedEvent,
System.Windows.Automation.AutomationElement.RootElement,
System.Windows.Automation.TreeScope.Subtree,
this.handleWindowClosed);
this.registerValueChanged();
this.registerTextNameChange();
this.registerTabSelected();
this.registerRangeValueChanged();
}
private void registerRangeValueChanged()
{
if (this.getMsAutomationElement() != null)
{
System.Windows.Automation.Automation.AddAutomationPropertyChangedEventHandler(
this.getMsAutomationElement(),
System.Windows.Automation.TreeScope.Subtree, this.handlePropertyChange,
System.Windows.Automation.RangeValuePattern.ValueProperty);
}
}
private void unregisterRangeValueChanged()
{
System.Windows.Automation.Automation.RemoveAutomationPropertyChangedEventHandler(
this.getMsAutomationElement(),
this.handlePropertyChange);
}
private void registerValueChanged()
{
if (this.getMsAutomationElement() != null)
{
System.Windows.Automation.Automation.AddAutomationPropertyChangedEventHandler(
this.getMsAutomationElement(),
System.Windows.Automation.TreeScope.Subtree, this.handlePropertyChange,
System.Windows.Automation.ValuePattern.ValueProperty);
}
}
private void unregisterValueChanged()
{
System.Windows.Automation.Automation.RemoveAutomationPropertyChangedEventHandler(
this.getMsAutomationElement(),
this.handlePropertyChange);
}
private void registerTextNameChange()
{
if (this.getMsAutomationElement() != null)
{
System.Windows.Automation.Automation.AddAutomationPropertyChangedEventHandler(
this.getMsAutomationElement(),
System.Windows.Automation.TreeScope.Subtree, this.handlePropertyChange,
System.Windows.Automation.AutomationElement.NameProperty);
}
}
private void unregisterTextNameChange()
{
System.Windows.Automation.Automation.RemoveAutomationPropertyChangedEventHandler(
this.getMsAutomationElement(),
this.handlePropertyChange);
}
private void handleWindowOpened(object src, System.Windows.Automation.AutomationEventArgs e)
{
Console.ForegroundColor = ConsoleColor.Magenta;
Console.WriteLine(DateTime.Now.ToShortTimeString() + " " + "Window opened:" + " " +
(src as System.Windows.Automation.AutomationElement).Current.Name);
System.Windows.Automation.AutomationElement element = src as System.Windows.Automation.AutomationElement;
//this.sendEventToPluginQueue(src, e, element.GetRuntimeId(), this.getAutomationParent(element).GetRuntimeId());
//Fill out the fields of the control added message
int[] parentId = this.getAutomationParent(element).GetRuntimeId();
this.copyToIcdArray(parentId,
this.protocol.getMessageSet().outgoing.ControlAddedMessage.Data.controlAdded.parentRuntimeId);
this.copyToIcdArray(element.GetRuntimeId(),
this.protocol.getMessageSet().outgoing.ControlAddedMessage.Data.controlAdded.runtimeId);
//Send the message using the protocol
this.protocol.send(this.protocol.getMessageSet().outgoing.ControlAddedMessage);
}
private void copyToIcdArray(int[] runtimeId, ICD.UI_AUTOMATION.RuntimeId icdRuntimeId)
{
icdRuntimeId.runtimeIdNumberOfItems.setVal((byte)runtimeId.Count());
for (int i = 0; i < runtimeId.Count(); i++)
{
icdRuntimeId.runtimeIdArray.getElement(i).setVal(runtimeId[i]);
}
}
private void handleWindowClosed(object src, System.Windows.Automation.AutomationEventArgs e)
{
if (src != null)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine(DateTime.Now.ToShortTimeString() + " " + "Window closed:" + " " +
(src as System.Windows.Automation.AutomationElement).GetRuntimeId().ToString());
System.Windows.Automation.AutomationElement element = src as System.Windows.Automation.AutomationElement;
this.copyToIcdArray(element.GetRuntimeId(),
this.protocol.getMessageSet().outgoing.ControlRemovedMessage.Data.controlRemoved.runtimeId);
//Send the message using the protocol
this.protocol.send(this.protocol.getMessageSet().outgoing.ControlRemovedMessage);
//this.sendEventToPluginQueue(src, e, element.GetRuntimeId());
}
}
EDIT:
I forgot to mention that I strongly suspect that the issue is that one of the UI-Automation event handler threads gets stuck somehow. The reason I believe this, is that when the problem occurred in my monitor, I started an instance of AccEvent and it received all the missing events that my monitor was not getting. This means that the events are being fired but not passed to my monitor.
EDIT2:
I forgot to mention that this happens running in Windows 8 with the specific target application, I have not seen this phenomenon on my own Windows 7 machine with other applications. Another interesting thing is that it seems to happen periodically more or less, but regardless of when I subscribe to events, i.e. it can happen almost immediately after subscribing but then it takes several minutes to reoccur.
I'm afraid I don't know the cause of the delays that you're seeing, but here are some thoughts on this...
Everything I say below relates to the native UIA API in Windows, not the managed .NET UIA API. All improvements to UIA in recent years have been made to the Windows UIA API. So whenever I write UIA client C# code, I call UIA through a managed wrapper that I generate with the tlbimp.exe SDK tool.
That is, I first generate the wrapper with a command like...
"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\x64\tlbimp.exe" c:\windows\system32\uiautomationcore.dll /out:Interop.UIAutomationCore.dll
Then I include a reference to the Interop.UIAutomationCore.dll in my C# project, add "using Interop.UIAutomationCore;" to my C# file, and then I can do things like...
IUIAutomation uiAutomation = new CUIAutomation8();
IUIAutomationElement rootElement = uiAutomation.GetRootElement();
uiAutomation.AddAutomationEventHandler(
20016, // UIA_Window_WindowOpenedEventId
rootElement,
TreeScope.TreeScope_Descendants,
null,
this);
...
public void HandleAutomationEvent(IUIAutomationElement sender, int eventId)
{
// Got a window opened event...
}
In Windows 7, there were some important constraints around UIA event handlers. It was easy to write event handlers which didn't account for those constraints, and that could lead to long delays when interacting with UIA. For example, it was important to not add or remove a UIA event handler from inside an event handler. So at the time, I intentionally made no UIA calls at all from inside my event handlers. Instead, I'd post myself a message or add some action to a queue, allow my event handler to return, and take whatever action I wanted to in response to the event shortly afterwards on another thread. This required some more work on my part, but I didn't want to risk hitting delays. And any threads I created would be running in an MTA.
An example of the action described above is in my old focus tracking sample up at https://code.msdn.microsoft.com/windowsapps/Windows-7-UI-Automation-6390614a/sourcecode?fileId=21469&pathId=715901329. The file FocusEventHandler.cs creates the MTA thread and queues messages to avoid making UIA calls inside the event hander.
Since Window 7, I know the constraints in UIA relating to threading and delays have been relaxed, and the likelihood of encountering delays has been reduced. More recently, there were some improvements between Windows 8.1 and Windows 10 in this area, so if it'd be practical to run your code on Windows 10, it would be interesting to see if the delays still repro there.
I know this is time consuming, but you might be interested in removing the interaction with UIA inside your event handlers and seeing if the delays go away. If they do, it'd be a case of determining which action seems to trigger the problem, and seeing if there's an alternative way of achieving your goals without performing the UIA interaction in the event handlers.
For example, in your event handler, you call...
this.getAutomationParent(element).GetRuntimeId();
I expect this will lead to two calls back into the provider app which generated the event. The first call is to get the parent of the source element, and the second call is to get the RuntimeId of that parent. So while UIA is waiting for your event handler to return, you've called twice back into UIA. While I don't know that that's a problem, I'd avoid it.
Sometimes you can avoid a cross-proc call back to the provider process by having some data of interest cached with the event itself. For example, say I know I'm going to want the RuntimeId of an element that raised a WindowOpened event. I can ask UIA to cache that data with the events I receive, when I register for the events.
int propertyRuntimeId = 30000; // UIA_RuntimeIdPropertyId
...
IUIAutomationCacheRequest cacheRequestRuntimeId = uiAutomation.CreateCacheRequest();
cacheRequestRuntimeId.AddProperty(propertyRuntimeId);
uiAutomation.AddAutomationEventHandler(
20016, // UIA_Window_WindowOpenedEventId
rootElement,
TreeScope.TreeScope_Descendants,
cacheRequestRuntimeId,
this);
...
public void HandleAutomationEvent(IUIAutomationElement sender, int eventId)
{
// Got a window opened event...
// Get the RuntimeId from the source element. Because that data is cached with the
// event, we don't have to call back through UIA into the provider process here.
int[] runtimeId = sender.GetCachedPropertyValue(propertyRuntimeId);
}
On a side note, when practical, I always cache data when dealing with events or accessing elements through UIA, (by using calls such as FindFirstBuildCache(),) as I want to avoid as many cross-proc calls as possible.
So my advice would be:
Use the native Windows UIA API with a managed wrapper generated by tlbimp.exe.
Cache as much data as possible with the events, to avoid having to call back into the provider process unnecessarily later.
Avoid calls back into UIA from inside a UIA event handler.
Thanks,
Guy
I have seen this behavior in my project. The solution was unsubscribes and resubscribe to the events using a timer.
In addition, I set off any action following the events in a new task (running in an STA thread pool).
I have an app that keeps a connection alive to a server, however if the user walks away and the tablet goes to sleep, I would like to handle the disconnect gracefully, and I would also like to log back in when the user wakes the tablet.
I've tried in my putting the following code in my connection class, but they never get fired.
Application.Current.Suspending += this.OnAppSuspending;
Application.Current.Resuming += this.OnAppResuming;;
For desktop apps, you can use SystemEvents.PowerModeChanged event to know if Windows is going into sleep state. I don't know if this works for the tablets too, but you can try it...
From MSDN:
• Resume The operating system is about to resume from a suspended state.
• StatusChange A power mode status notification event has been raised by the operating system. This might indicate a weak or charging battery, a transition between AC power and battery, or another change in the status of the system power supply.
• Suspend The operating system is about to be suspended.
SystemEvents.PowerModeChanged += OnPowerChange;
private void OnPowerChange(object s, PowerModeChangedEventArgs e)
{
switch ( e.Mode )
{
case PowerModes.Resume:
break;
case PowerModes.Suspend:
break;
}
}
First of all I need to make it clear that I have no interest in keylogging.
I need a way to monitor keyboard activity at the most basic level while my application is in the background.
I don't need to know which keys, I don't need to save any data, I don't need or plan to hide my application at all, all I need is to know when keys are pressed and invoke a method.
I'm looking for the simplest way to do this possible, I know a reasonable amount of C# but nothing too complex as most of my knowledge is self-taught.
I've looked around for some appropriate ways of doing this and I've found nothing useful. All I've found is a bunch of people saying "No, that's illegal" on forums and source code for in depth keyloggers.
If any of you could advise me on a way to achieve this then I would be most appreciative.
You'll need to use Window Hooks:
Low-Level Keyboard Hook in C#
But beware, Windows security, may be protecting us from doing what you want!
You can monitor keyboard and mouse activity in the background with the Nuget package MouseKeyHook (GitHub).
This code detects when a key is pressed:
private IKeyboardMouseEvents _globalHook;
private void Subscribe()
{
if (_globalHook == null)
{
// Note: for the application hook, use the Hook.AppEvents() instead
_globalHook = Hook.GlobalEvents();
_globalHook.KeyPress += GlobalHookKeyPress;
}
}
private static void GlobalHookKeyPress(object sender, KeyPressEventArgs e)
{
Console.WriteLine("KeyPress: \t{0}", e.KeyChar);
}
private void Unsubscribe()
{
if (_globalHook != null)
{
_globalHook.KeyPress -= GlobalHookKeyPress;
_globalHook.Dispose();
}
}
You will need to call Subscribe() to start listening, and Unsubscribe() to stop listening. Obviously you need to modify GlobalHookKeyPress() to do useful work.
I needed this functionality in order to write a utility which will turn on the keyboard backlight on a Lenovo Thinkpad when any key is pressed, including CTRL (which KeyPress doesn't catch). For this purpose, I had to monitor for key down instead. The code is the same except we attach to a different event...
_globalHook.KeyDown += GlobalHookOnKeyDown;
and the event handler signature is different:
private static void GlobalHookOnKeyDown(object sender, KeyEventArgs e)
{
Console.WriteLine("KeyDown: \t{0}", e.KeyCode);
}
The library can also detect specific key combinations and sequences. For example:
Hook.GlobalEvents().OnCombination(new Dictionary<Combination, Action>
{
{ Combination.TriggeredBy(Keys.A).Control(), () => { Console.WriteLine("You Pressed CTRL+A"); } },
{ Combination.FromString("Shift+Alt+Enter"), () => { Console.WriteLine("You Pressed FULL SCREEN"); } }
});
Microsoft tells you How to: Handle Keyboard Input at the Form Level. As long as you handle the same event(s) this works for any non web application.
You should also take a look at the other questions here on SO, such as Handling Input from a Keyboard Wedge
You could register Windows Hot Key with RegisterHotKey windows API, look at this blog post :
http://www.liensberger.it/web/blog/?p=207
What is the best way to keep a console application open as long as the CancelKeyPress event has not been fired?
I would prefer to not use Console.Read or Console.ReadLine as I do not want to accept input. I just want to enable the underlying application to print to the console event details as they are fired. Then once the CancelKeyPress event is fired I want to gracefully shut down the application.
I'm assuming that "gracefully shut down the application" is the part you are struggling with here. Otherwise your application will automatically exit on ctrl-c. You should change the title.
Here's a quick demo of what I think you need. It could be refined a bit more with use of locking and Monitors for notification. I'm not sure exactly what you need though, so I'll just pose this...
class Program
{
private static volatile bool _s_stop = false;
public static void Main(string[] args)
{
Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
while (!_s_stop)
{
/* put real logic here */
Console.WriteLine("still running at {0}", DateTime.Now);
Thread.Sleep(3000);
}
Console.WriteLine("Graceful shut down code here...");
//don't leave this... demonstration purposes only...
Console.ReadLine();
}
static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
//you have 2 options here, leave e.Cancel set to false and just handle any
//graceful shutdown that you can while in here, or set a flag to notify the other
//thread at the next check that it's to shut down. I'll do the 2nd option
e.Cancel = true;
_s_stop = true;
Console.WriteLine("CancelKeyPress fired...");
}
}
The _s_stop boolean should be declared volatile or an overly-ambitious optimizer might cause the program to loop infinitely.
The _s_stop boolean should be declared volatile in the example code, or an overly-ambitious optimizer might cause the program to loop infinitely.
There is already a handler bound to CancelKeyPress that terminates your application, the only reason to hook to it is if you want to intercept the event and prevent the app from closing.
In your situation, just put your app into an infinite loop, and let the built in event handler kill it. You may want to look into using something like Wait(1) or a background process to prevent it from using tons of CPU while doing nothing.
This may be what you're looking for:
http://msdn.microsoft.com/en-us/library/system.console.cancelkeypress.aspx
Simply run your program or codes without debugging, on your keyboard key in CTRL + f5 instead of F5(debugging).