跳到主要内容

github/tai

公开

Tai · Windows 软件与网站使用时长统计。上游 Planshit/Tai 的源码镜像,非灵栈原创;MIT 许可。来源:https://github.com/Planshit/Tai 。本次为手动同步,暂不提供安装包。

提交记录
修改Core/Servicers/Instances/Sleepdiscover.cs+185 −115看文件
@@ -9,6 +9,7 @@ using System.Diagnostics;
99using System.Linq;
1010using System.Runtime.InteropServices;
1111using System.Text;
12新增:using System.Threading;
1213using System.Threading.Tasks;
1314using System.Windows;
1415using System.Windows.Threading;
@@ -35,20 +36,45 @@ namespace Core.Servicers.Instances
3536 /// </summary>
3637 private DateTime pressKeyboardLastTime;
3738
38删除: private readonly IObserver observer;
39删除:
39新增: // 键盘钩子
4040 private Win32API.LowLevelKeyboardProc keyboardProc;
4141 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新增:
4249 private int emptyPointNum = 0;
43删除: public Sleepdiscover(IObserver observer)
50新增: public Sleepdiscover()
4451 {
45删除: this.observer = observer;
46删除: observer.OnAppActive += Observer_OnAppActive;
4752 SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(OnPowerModeChanged);
4853 SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
54新增:
4955 keyboardProc = HookCallback;
56新增: mouseProc = HookMouseCallback;
5057 }
5158
59新增: public void Start()
60新增: {
61新增: timer = new DispatcherTimer();
62新增: timer.Interval = new TimeSpan(0, 5, 0);
63新增: //#if DEBUG
64新增: // timer.Interval = new TimeSpan(0, 0, 10);
65新增: //#endif
66新增: timer.Tick += Timer_Tick;
67新增: timer.Start();
68新增:
69新增: lastPoint = Win32API.GetCursorPosition();
70新增:
71新增: playSoundStartTime = DateTime.MinValue;
72新增:
73新增: pressKeyboardLastTime = DateTime.Now;
74新增:
75新增: // 设置键盘钩子
76新增: Win32API.SetKeyboardHook(keyboardProc);
77新增: }
5278 private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
5379 {
5480 if (e.Reason == SessionSwitchReason.RemoteDisconnect || e.Reason == SessionSwitchReason.ConsoleDisconnect)
@@ -56,24 +82,38 @@ namespace Core.Servicers.Instances
5682 // 与这台设备远程桌面连接断开
5783 if (status == SleepStatus.Wake)
5884 {
59删除: status = SleepStatus.Sleep;
60删除: SleepStatusChanged?.Invoke(status);
6185 Logger.Warn("与这台设备远程桌面连接断开");
86新增: Sleep();
6287 }
6388 }
6489 }
6590
91新增: private IntPtr HookMouseCallback(int nCode, IntPtr wParam, IntPtr lParam)
92新增: {
93新增:
94新增: if (nCode >= 0)
95新增: {
96新增: if (wParam == (IntPtr)Win32API.WM_LBUTTONDBLCLK || wParam == (IntPtr)Win32API.WM_WHEEL)
97新增: {
98新增: Logger.Info("鼠标唤醒");
99新增:
100新增: Wake();
101新增: }
102新增:
103新增: }
104新增:
105新增: return Win32API.CallNextHookEx(hookMouseID, nCode, wParam, lParam);
106新增: }
66107 private IntPtr HookCallback(
67108 int nCode, IntPtr wParam, IntPtr lParam)
68109 {
69110 if (nCode >= 0 && wParam == (IntPtr)Win32API.WM_KEYDOWN)
70111 {
71删除: int vkCode = Marshal.ReadInt32(lParam);
72删除:
73112 if (status == SleepStatus.Sleep)
74113 {
75删除: status = SleepStatus.Wake;
76删除: SleepStatusChanged?.Invoke(status);
114新增: Logger.Info("键盘唤醒");
115新增:
116新增: Wake();
77117 }
78118 else
79119 {
@@ -92,160 +132,190 @@ namespace Core.Servicers.Instances
92132 // 电脑休眠
93133 if (status == SleepStatus.Wake)
94134 {
95删除: status = SleepStatus.Sleep;
96删除: SleepStatusChanged?.Invoke(status);
97删除: Logger.Warn("设备已休眠");
135新增: Logger.Info("设备已休眠");
136新增:
137新增: Sleep();
98138 }
99139 break;
100140 case PowerModes.Resume:
101141 // 电脑恢复
102142 if (status == SleepStatus.Sleep)
103143 {
104删除: playSoundStartTime = DateTime.MinValue;
105删除: status = SleepStatus.Wake;
106删除: SleepStatusChanged?.Invoke(status);
107删除: Logger.Warn("设备已恢复");
144新增: Logger.Info("设备已恢复");
145新增:
146新增: Wake();
108147 }
109148 break;
110149 }
111150 }
112151
113删除: private void Observer_OnAppActive(string processName, string description, string file)
152新增:
153新增:
154新增: #region 指示当前是否处于睡眠状态
155新增: /// <summary>
156新增: /// 指示当前是否处于睡眠状态
157新增: /// </summary>
158新增: /// <returns>睡眠返回true</returns>
159新增: private async Task<bool> IsSleepAsync()
114160 {
115删除: if (status == SleepStatus.Sleep)
161新增: // 1.先判断鼠标是否有过移动
162新增: Point point = Win32API.GetCursorPosition();
163新增:
164新增: if (point.X + point.Y == 0)
116165 {
117删除: TimeSpan timeSpan = DateTime.Now - pressKeyboardLastTime;
166新增: emptyPointNum++;
118167
119删除: Point point = Win32API.GetCursorPosition();
120删除: if (lastPoint.ToString() == point.ToString() && timeSpan.TotalSeconds > 10)
168新增: if (emptyPointNum == 2)
121169 {
122删除: // 非鼠标或键盘激活
123删除: return;
170新增: emptyPointNum = 0;
171新增: return true;
124172 }
173新增: }
125174
126删除: playSoundStartTime = DateTime.MinValue;
127删除: status = SleepStatus.Wake;
128删除: SleepStatusChanged?.Invoke(status);
175新增: if (lastPoint.ToString() != point.ToString())
176新增: {
177新增: // 鼠标在移动,更新坐标
178新增: lastPoint = point;
179新增: return false;
129180 }
130删除: }
131181
132删除: public void Start()
133删除: {
134删除: timer = new DispatcherTimer();
135删除: timer.Interval = new TimeSpan(0, 2, 0);
136删除:#if DEBUG
137删除: //timer.Interval = new TimeSpan(0, 0, 10);
138删除:#endif
139删除: timer.Tick += Timer_Tick;
140删除: timer.Start();
182新增: // 2.判断是否键盘超时
183新增: if (!IsKeyboardOuttime())
184新增: {
185新增: // 十分钟内有键盘操作
186新增: return false;
187新增: }
141188
142删除: lastPoint = Win32API.GetCursorPosition();
189新增: // 3.鼠标和键盘都没有操作时判断是否在播放声音
143190
144删除: playSoundStartTime = DateTime.MinValue;
191新增: // 持续30秒检测当前是否在播放声音
192新增: bool isPlaySound = await IsPlaySoundAsync();
145193
146删除: pressKeyboardLastTime = DateTime.Now;
194新增: if (!isPlaySound)
195新增: {
196新增: // 没有声音判定为睡眠状态
197新增: return true;
198新增: }
147199
148删除: // 设置键盘钩子
149删除: Win32API.SetKeyboardHook(keyboardProc);
200新增: // 在播放声音
201新增: if (playSoundStartTime == DateTime.MinValue)
202新增: {
203新增: // 第一次记录声音开始时间
204新增: playSoundStartTime = DateTime.Now;
205新增: return false;
206新增: }
207新增:
208新增: // 声音播放超过两个小时视为睡眠状态
209新增: TimeSpan timeSpan = DateTime.Now - playSoundStartTime;
210新增:
211新增: if (timeSpan.TotalHours >= 2)
212新增: {
213新增: // 重置声音开始时间
214新增: playSoundStartTime = DateTime.MinValue;
215新增: return true;
216新增: }
217新增:
218新增: return false;
150219 }
220新增: #endregion
151221
152删除: private void Timer_Tick(object sender, EventArgs e)
222新增: private async void Timer_Tick(object sender, EventArgs e)
153223 {
154删除: Point point = Win32API.GetCursorPosition();
155删除:
156删除: if (point.X + point.Y == 0)
224新增: timer.Stop();
225新增: bool isSleep = await IsSleepAsync();
226新增: if (isSleep)
157227 {
158删除: emptyPointNum++;
228新增: Sleep();
229新增: }
230新增: else
231新增: {
232新增: timer.Start();
233新增: }
234新增: }
159235
160删除: if (emptyPointNum == 2)
161删除: {
162删除: emptyPointNum = 0;
163删除: status = SleepStatus.Sleep;
164删除: SleepStatusChanged?.Invoke(status);
165删除: Logger.Info("empty point num:" + point.ToString());
166删除: }
236新增: private void Sleep()
237新增: {
238新增: // 停止离开检测计时器
239新增: timer.Stop();
240新增:
241新增: if (status == SleepStatus.Sleep)
242新增: {
167243 return;
168244 }
245新增: status = SleepStatus.Sleep;
169246
170删除: if (lastPoint == null)
247新增: // 设置鼠标钩子
248新增: mouseHook = Win32API.SetMouseHook(mouseProc);
249新增:
250新增: // 状态通知
251新增: SleepStatusChanged?.Invoke(status);
252新增: }
253新增:
254新增: private void Wake()
255新增: {
256新增: if (status == SleepStatus.Wake)
171257 {
172删除: lastPoint = point;
173258 return;
174259 }
175260
176删除: if (status == SleepStatus.Wake)
261新增: status = SleepStatus.Wake;
262新增:
263新增: // 卸载鼠标钩子
264新增: Win32API.UnhookWindowsHookEx(mouseHook);
265新增:
266新增: // 启动离开检测
267新增: timer.Start();
268新增:
269新增:
270新增:
271新增: // 重置声音播放时间
272新增: playSoundStartTime = DateTime.MinValue;
273新增:
274新增: // 重置鼠标坐标
275新增: lastPoint = Win32API.GetCursorPosition();
276新增:
277新增: // 状态通知
278新增: SleepStatusChanged?.Invoke(status);
279新增:
280新增: }
281新增:
282新增: private async Task<bool> IsPlaySoundAsync()
283新增: {
284新增: bool result = false;
285新增:
286新增: await Task.Run(() =>
177287 {
288新增: // 持续30秒
289新增: int time = 30;
178290
179删除: if (lastPoint.ToString() == point.ToString())
291新增: while (time > 0)
180292 {
181删除: // 处于活跃状态
182删除: bool isPlaySound = Win32API.IsWindowsPlayingSound();
183删除: // 超过时间未活动鼠标
184删除:
185删除: if (isPlaySound)
293新增: bool isPlay = Win32API.IsWindowsPlayingSound();
294新增: if (isPlay)
186295 {
187删除: // 在播放声音
188删除:
189删除: if (playSoundStartTime == DateTime.MinValue)
190删除: {
191删除: playSoundStartTime = DateTime.Now;//没有正确更新时间导致没超过2个小时就进入睡眠状态了
192删除: }
193删除: else
194删除: {
195删除: // 判断声音时间是否超过2个小时
196删除: TimeSpan timeSpan = DateTime.Now - playSoundStartTime;
197删除:
198删除: if (timeSpan.TotalHours >= 2 && IsPressKeyboardOuttime())
199删除: {
200删除: // 超过表示可能睡着了,切换状态
201删除: status = SleepStatus.Sleep;
202删除: Logger.Info("[sleep] [1] time:" + timeSpan.TotalHours + ",start:" + playSoundStartTime);
203删除:
204删除: playSoundStartTime = DateTime.MinValue;
205删除: SleepStatusChanged?.Invoke(status);
206删除: }
207删除: }
296新增: result = true;
297新增: break;
208298 }
209299 else
210300 {
211删除: if (IsPressKeyboardOuttime())
212删除: {
213删除: // 没有播放声音且键盘休眠超时
214删除: status = SleepStatus.Sleep;
215删除: Logger.Info("[sleep] [2] " + pressKeyboardLastTime);
216删除:
217删除: SleepStatusChanged?.Invoke(status);
218删除: }
301新增: time--;
302新增: Debug.WriteLine(time);
303新增: Thread.Sleep(1000);
219304 }
220305 }
221删除: else
222删除: {
223删除: playSoundStartTime = DateTime.MinValue;
224删除: }
225删除: }
226删除: else
227删除: {
228删除: // 处于休眠状态
229删除: if (lastPoint.ToString() != point.ToString())
230删除: {
231删除: // 鼠标活动了切换状态
232删除: status = SleepStatus.Wake;
233删除: SleepStatusChanged?.Invoke(status);
234删除: }
235删除: }
236删除:
237删除: lastPoint = point;
306新增: });
307新增: return result;
238308 }
239309
240删除:
241310 /// <summary>
242删除: /// 通过按键时间判断(超过5分钟未有键盘操作视为超时)
311新增: /// 指示是否键盘行为超时(超过10分钟)
243312 /// </summary>
244删除: /// <returns></returns>
245删除: private bool IsPressKeyboardOuttime()
313新增: /// <returns>超时返回true</returns>
314新增: private bool IsKeyboardOuttime()
246315 {
247316 TimeSpan timeSpan = DateTime.Now - pressKeyboardLastTime;
248删除: return timeSpan.TotalMinutes >= 5;
317新增:
318新增: return timeSpan.TotalMinutes >= 10;
249319 }
250320 }
251321}