|
19 | 19 | using Windows.Win32;
|
20 | 20 | using Windows.Win32.Foundation;
|
21 | 21 | using Windows.Win32.Graphics.Dwm;
|
| 22 | +using Windows.Win32.System.Power; |
22 | 23 | using Windows.Win32.System.Threading;
|
23 | 24 | using Windows.Win32.UI.Input.KeyboardAndMouse;
|
24 | 25 | using Windows.Win32.UI.Shell.Common;
|
@@ -338,9 +339,6 @@ public static Point TransformPixelsToDIP(Visual visual, double unitX, double uni
|
338 | 339 | public const int SC_MAXIMIZE = (int)PInvoke.SC_MAXIMIZE;
|
339 | 340 | public const int SC_MINIMIZE = (int)PInvoke.SC_MINIMIZE;
|
340 | 341 |
|
341 |
| - public const int WM_POWERBROADCAST = (int)PInvoke.WM_POWERBROADCAST; |
342 |
| - public const int PBT_APMRESUMEAUTOMATIC = (int)PInvoke.PBT_APMRESUMEAUTOMATIC; |
343 |
| - |
344 | 342 | #endregion
|
345 | 343 |
|
346 | 344 | #region Window Handle
|
@@ -918,5 +916,105 @@ public static string SelectFile()
|
918 | 916 | }
|
919 | 917 |
|
920 | 918 | #endregion
|
| 919 | + |
| 920 | + #region Sleep Mode Listener |
| 921 | + |
| 922 | + private static Action _func; |
| 923 | + private static PDEVICE_NOTIFY_CALLBACK_ROUTINE _callback = null; |
| 924 | + private static DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS _recipient; |
| 925 | + private static SafeHandle _recipientHandle; |
| 926 | + private static HPOWERNOTIFY _handle = HPOWERNOTIFY.Null; |
| 927 | + |
| 928 | + /// <summary> |
| 929 | + /// Registers a listener for sleep mode events. |
| 930 | + /// Inspired from: https://github.com/XKaguya/LenovoLegionToolkit |
| 931 | + /// https://blog.csdn.net/mochounv/article/details/114668594 |
| 932 | + /// </summary> |
| 933 | + /// <param name="func"></param> |
| 934 | + /// <exception cref="Win32Exception"></exception> |
| 935 | + public static unsafe void RegisterSleepModeListener(Action func) |
| 936 | + { |
| 937 | + if (_callback != null) |
| 938 | + { |
| 939 | + // Only register if not already registered |
| 940 | + return; |
| 941 | + } |
| 942 | + |
| 943 | + _func = func; |
| 944 | + _callback = new PDEVICE_NOTIFY_CALLBACK_ROUTINE(DeviceNotifyCallback); |
| 945 | + _recipient = new DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS() |
| 946 | + { |
| 947 | + Callback = _callback, |
| 948 | + Context = null |
| 949 | + }; |
| 950 | + |
| 951 | + _recipientHandle = new StructSafeHandle<DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS>(_recipient); |
| 952 | + _handle = PInvoke.PowerRegisterSuspendResumeNotification( |
| 953 | + REGISTER_NOTIFICATION_FLAGS.DEVICE_NOTIFY_CALLBACK, |
| 954 | + _recipientHandle, |
| 955 | + out var handle) == WIN32_ERROR.ERROR_SUCCESS ? |
| 956 | + new HPOWERNOTIFY(new IntPtr(handle)) : |
| 957 | + HPOWERNOTIFY.Null; |
| 958 | + if (_handle.IsNull) |
| 959 | + { |
| 960 | + throw new Win32Exception("Error registering for power notifications: " + Marshal.GetLastWin32Error()); |
| 961 | + } |
| 962 | + } |
| 963 | + |
| 964 | + /// <summary> |
| 965 | + /// Unregisters the sleep mode listener. |
| 966 | + /// </summary> |
| 967 | + public static void UnregisterSleepModeListener() |
| 968 | + { |
| 969 | + if (!_handle.IsNull) |
| 970 | + { |
| 971 | + PInvoke.PowerUnregisterSuspendResumeNotification(_handle); |
| 972 | + _handle = HPOWERNOTIFY.Null; |
| 973 | + _func = null; |
| 974 | + _callback = null; |
| 975 | + _recipientHandle = null; |
| 976 | + } |
| 977 | + } |
| 978 | + |
| 979 | + private static unsafe uint DeviceNotifyCallback(void* context, uint type, void* setting) |
| 980 | + { |
| 981 | + switch (type) |
| 982 | + { |
| 983 | + case PInvoke.PBT_APMRESUMEAUTOMATIC: |
| 984 | + // Operation is resuming automatically from a low-power state.This message is sent every time the system resumes |
| 985 | + _func(); |
| 986 | + break; |
| 987 | + |
| 988 | + case PInvoke.PBT_APMRESUMESUSPEND: |
| 989 | + // Operation is resuming from a low-power state.This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key |
| 990 | + _func(); |
| 991 | + break; |
| 992 | + } |
| 993 | + |
| 994 | + return 0; |
| 995 | + } |
| 996 | + |
| 997 | + private sealed class StructSafeHandle<T> : SafeHandle where T : struct |
| 998 | + { |
| 999 | + private readonly nint _ptr = nint.Zero; |
| 1000 | + |
| 1001 | + public StructSafeHandle(T recipient) : base(nint.Zero, true) |
| 1002 | + { |
| 1003 | + var pRecipient = Marshal.AllocHGlobal(Marshal.SizeOf<T>()); |
| 1004 | + Marshal.StructureToPtr(recipient, pRecipient, false); |
| 1005 | + SetHandle(pRecipient); |
| 1006 | + _ptr = pRecipient; |
| 1007 | + } |
| 1008 | + |
| 1009 | + public override bool IsInvalid => handle == nint.Zero; |
| 1010 | + |
| 1011 | + protected override bool ReleaseHandle() |
| 1012 | + { |
| 1013 | + Marshal.FreeHGlobal(_ptr); |
| 1014 | + return true; |
| 1015 | + } |
| 1016 | + } |
| 1017 | + |
| 1018 | + #endregion |
921 | 1019 | }
|
922 | 1020 | }
|
0 commit comments