| 1 | using Core.Enums; |
| 2 | using Core.Event; |
| 3 | using Core.Librarys; |
| 4 | using Core.Servicers.Interfaces; |
| 5 | using Microsoft.Win32; |
| 6 | using System; |
| 7 | using System.Collections.Generic; |
| 8 | using System.Diagnostics; |
| 9 | using System.Linq; |
| 10 | using System.Runtime.InteropServices; |
| 11 | using System.Text; |
| 12 | using System.Threading; |
| 13 | using System.Threading.Tasks; |
| 14 | using System.Windows; |
| 15 | using System.Windows.Threading; |
| 16 | |
| 17 | namespace Core.Servicers.Instances |
| 18 | { |
| 19 | public class Sleepdiscover : ISleepdiscover |
| 20 | { |
| 21 | public event SleepdiscoverEventHandler SleepStatusChanged; |
| 22 | |
| 23 | private DispatcherTimer timer; |
| 24 | |
| 25 | private Point lastPoint; |
| 26 | |
| 27 | private SleepStatus status = SleepStatus.Wake; |
| 28 | |
| 29 | ///<summary> |
| 30 | /// |
| 31 | ///</summary> |
| 32 | private DateTime playSoundStartTime; |
| 33 | |
| 34 | ///<summary> |
| 35 | /// |
| 36 | ///</summary> |
| 37 | private DateTime pressKeyboardLastTime; |
| 38 | |
| 39 | |
| 40 | private Win32API.LowLevelKeyboardProc keyboardProc; |
| 41 | private static IntPtr hookKeyboardID = IntPtr.Zero; |
| 42 | |
| 43 | |
| 44 | |
| 45 | private Win32API.LowLevelKeyboardProc mouseProc; |
| 46 | private static IntPtr hookMouseID = IntPtr.Zero; |
| 47 | private IntPtr mouseHook; |
| 48 | |
| 49 | private int emptyPointNum = 0; |
| 50 | public Sleepdiscover() |
| 51 | { |
| 52 | SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(OnPowerModeChanged); |
| 53 | SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; |
| 54 | |
| 55 | keyboardProc = HookCallback; |
| 56 | mouseProc = HookMouseCallback; |
| 57 | } |
| 58 | |
| 59 | public void Start() |
| 60 | { |
| 61 | StartTimer(); |
| 62 | |
| 63 | lastPoint = Win32API.GetCursorPosition(); |
| 64 | playSoundStartTime = DateTime.MinValue; |
| 65 | pressKeyboardLastTime = DateTime.Now; |
| 66 | |
| 67 | |
| 68 | Win32API.SetKeyboardHook(keyboardProc); |
| 69 | } |
| 70 | |
| 71 | public void Stop() |
| 72 | { |
| 73 | StopTimer(); |
| 74 | } |
| 75 | |
| 76 | private void StartTimer() |
| 77 | { |
| 78 | StopTimer(); |
| 79 | timer = new DispatcherTimer(); |
| 80 | |
| 81 | timer.Interval = new TimeSpan(0, 5, 0); |
| 82 | timer.Tick += Timer_Tick; |
| 83 | timer.Start(); |
| 84 | } |
| 85 | |
| 86 | private void StopTimer() |
| 87 | { |
| 88 | if (timer != null) |
| 89 | { |
| 90 | timer.Tick -= Timer_Tick; |
| 91 | timer.Stop(); |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) |
| 96 | { |
| 97 | if (e.Reason == SessionSwitchReason.RemoteDisconnect || e.Reason == SessionSwitchReason.ConsoleDisconnect) |
| 98 | { |
| 99 | |
| 100 | if (status == SleepStatus.Wake) |
| 101 | { |
| 102 | Logger.Warn("与这台设备远程桌面连接断开"); |
| 103 | Sleep(); |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | private IntPtr HookMouseCallback(int nCode, IntPtr wParam, IntPtr lParam) |
| 109 | { |
| 110 | |
| 111 | if (nCode >= 0) |
| 112 | { |
| 113 | if (wParam == (IntPtr)Win32API.WM_LBUTTONDBLCLK || wParam == (IntPtr)Win32API.WM_WHEEL) |
| 114 | { |
| 115 | Logger.Info("鼠标唤醒"); |
| 116 | |
| 117 | Wake(); |
| 118 | } |
| 119 | |
| 120 | } |
| 121 | |
| 122 | return Win32API.CallNextHookEx(hookMouseID, nCode, wParam, lParam); |
| 123 | } |
| 124 | private IntPtr HookCallback( |
| 125 | int nCode, IntPtr wParam, IntPtr lParam) |
| 126 | { |
| 127 | if (nCode >= 0 && wParam == (IntPtr)Win32API.WM_KEYDOWN) |
| 128 | { |
| 129 | if (status == SleepStatus.Sleep) |
| 130 | { |
| 131 | Logger.Info("键盘唤醒"); |
| 132 | |
| 133 | Wake(); |
| 134 | } |
| 135 | else |
| 136 | { |
| 137 | playSoundStartTime = DateTime.MinValue; |
| 138 | pressKeyboardLastTime = DateTime.Now; |
| 139 | } |
| 140 | } |
| 141 | return Win32API.CallNextHookEx(hookKeyboardID, nCode, wParam, lParam); |
| 142 | } |
| 143 | |
| 144 | private void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e) |
| 145 | { |
| 146 | switch (e.Mode) |
| 147 | { |
| 148 | case PowerModes.Suspend: |
| 149 | |
| 150 | if (status == SleepStatus.Wake) |
| 151 | { |
| 152 | Logger.Info("设备已休眠"); |
| 153 | |
| 154 | Sleep(); |
| 155 | } |
| 156 | break; |
| 157 | case PowerModes.Resume: |
| 158 | |
| 159 | if (status == SleepStatus.Sleep) |
| 160 | { |
| 161 | Logger.Info("设备已恢复"); |
| 162 | |
| 163 | Wake(); |
| 164 | } |
| 165 | break; |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | |
| 170 | |
| 171 | #region 指示当前是否处于睡眠状态 |
| 172 | ///<summary> |
| 173 | /// |
| 174 | ///</summary> |
| 175 | ///<returns></returns> |
| 176 | private async Task<bool> IsSleepAsync() |
| 177 | { |
| 178 | Point point = Win32API.GetCursorPosition(); |
| 179 | |
| 180 | if (point.X + point.Y == 0) |
| 181 | { |
| 182 | emptyPointNum++; |
| 183 | |
| 184 | if (emptyPointNum == 2) |
| 185 | { |
| 186 | emptyPointNum = 0; |
| 187 | return true; |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | bool isActive = await IsActiveAsync(); |
| 192 | if (isActive) |
| 193 | { |
| 194 | return false; |
| 195 | } |
| 196 | |
| 197 | |
| 198 | |
| 199 | |
| 200 | bool isPlaySound = await IsPlaySoundAsync(); |
| 201 | |
| 202 | if (!isPlaySound) |
| 203 | { |
| 204 | |
| 205 | return true; |
| 206 | } |
| 207 | |
| 208 | |
| 209 | if (playSoundStartTime == DateTime.MinValue) |
| 210 | { |
| 211 | |
| 212 | playSoundStartTime = DateTime.Now; |
| 213 | return false; |
| 214 | } |
| 215 | |
| 216 | |
| 217 | TimeSpan timeSpan = DateTime.Now - playSoundStartTime; |
| 218 | |
| 219 | if (timeSpan.TotalHours >= 2) |
| 220 | { |
| 221 | |
| 222 | playSoundStartTime = DateTime.MinValue; |
| 223 | return true; |
| 224 | } |
| 225 | |
| 226 | return false; |
| 227 | } |
| 228 | #endregion |
| 229 | |
| 230 | private async void Timer_Tick(object sender, EventArgs e) |
| 231 | { |
| 232 | Debug.WriteLine("检测"); |
| 233 | timer.Stop(); |
| 234 | bool isSleep = await IsSleepAsync(); |
| 235 | if (isSleep) |
| 236 | { |
| 237 | Sleep(); |
| 238 | } |
| 239 | else |
| 240 | { |
| 241 | timer.Start(); |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | private void Sleep() |
| 246 | { |
| 247 | if (status == SleepStatus.Sleep) |
| 248 | { |
| 249 | return; |
| 250 | } |
| 251 | |
| 252 | |
| 253 | SystemEvents.SessionSwitch -= SystemEvents_SessionSwitch; |
| 254 | |
| 255 | |
| 256 | StopTimer(); |
| 257 | |
| 258 | status = SleepStatus.Sleep; |
| 259 | |
| 260 | |
| 261 | mouseHook = Win32API.SetMouseHook(mouseProc); |
| 262 | |
| 263 | |
| 264 | SleepStatusChanged?.Invoke(status); |
| 265 | } |
| 266 | |
| 267 | private void Wake() |
| 268 | { |
| 269 | if (status == SleepStatus.Wake) |
| 270 | { |
| 271 | return; |
| 272 | } |
| 273 | try |
| 274 | { |
| 275 | |
| 276 | SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; |
| 277 | |
| 278 | status = SleepStatus.Wake; |
| 279 | |
| 280 | |
| 281 | Win32API.UnhookWindowsHookEx(mouseHook); |
| 282 | |
| 283 | |
| 284 | StartTimer(); |
| 285 | |
| 286 | |
| 287 | |
| 288 | |
| 289 | playSoundStartTime = DateTime.MinValue; |
| 290 | |
| 291 | |
| 292 | lastPoint = Win32API.GetCursorPosition(); |
| 293 | |
| 294 | |
| 295 | SleepStatusChanged?.Invoke(status); |
| 296 | } |
| 297 | catch (Exception e) |
| 298 | { |
| 299 | Logger.Error(e.ToString()); |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | ///<summary> |
| 304 | /// |
| 305 | ///</summary> |
| 306 | ///<returns></returns> |
| 307 | private async Task<bool> IsPlaySoundAsync() |
| 308 | { |
| 309 | bool result = false; |
| 310 | |
| 311 | await Task.Run(() => |
| 312 | { |
| 313 | |
| 314 | int time = 30; |
| 315 | |
| 316 | while (time > 0) |
| 317 | { |
| 318 | bool isPlay = Win32API.IsWindowsPlayingSound(); |
| 319 | if (isPlay) |
| 320 | { |
| 321 | result = true; |
| 322 | break; |
| 323 | } |
| 324 | else |
| 325 | { |
| 326 | time--; |
| 327 | Debug.WriteLine(time); |
| 328 | Thread.Sleep(1000); |
| 329 | } |
| 330 | } |
| 331 | }); |
| 332 | return result; |
| 333 | } |
| 334 | |
| 335 | ///<summary> |
| 336 | /// |
| 337 | ///</summary> |
| 338 | ///<returns></returns> |
| 339 | private async Task<bool> IsActiveAsync() |
| 340 | { |
| 341 | bool result = false; |
| 342 | |
| 343 | await Task.Run(() => |
| 344 | { |
| 345 | |
| 346 | int time = 30; |
| 347 | |
| 348 | while (time > 0) |
| 349 | { |
| 350 | Point point = Win32API.GetCursorPosition(); |
| 351 | bool isMouseMove = lastPoint.ToString() != point.ToString(); |
| 352 | bool isKeyboardActive = !IsKeyboardOuttime(); |
| 353 | |
| 354 | if (isMouseMove || isKeyboardActive) |
| 355 | { |
| 356 | lastPoint = Win32API.GetCursorPosition(); |
| 357 | result = true; |
| 358 | break; |
| 359 | } |
| 360 | else |
| 361 | { |
| 362 | time--; |
| 363 | Debug.WriteLine(time); |
| 364 | Thread.Sleep(1000); |
| 365 | } |
| 366 | } |
| 367 | }); |
| 368 | return result; |
| 369 | } |
| 370 | |
| 371 | ///<summary> |
| 372 | /// |
| 373 | ///</summary> |
| 374 | ///<returns></returns> |
| 375 | private bool IsKeyboardOuttime() |
| 376 | { |
| 377 | TimeSpan timeSpan = DateTime.Now - pressKeyboardLastTime; |
| 378 | #if DEBUG |
| 379 | return timeSpan.TotalSeconds >= 10; |
| 380 | #endif |
| 381 | return timeSpan.TotalMinutes >= 10; |
| 382 | } |
| 383 | } |
| 384 | } |