在本文中,我们将练习如何使用Golang编写一个简单的Windows系统空闲时间监测工具。该工具能够检测系统的空闲时间,并在达到一定阈值时计数。
功能概述
监控鼠标和键盘的空闲事件,每空闲超过50s,触发次数加一。
该工具具有以下功能:
- 监测系统空闲时间。
- 当系统空闲时间超过设定的阈值时,触发计数。
- 实时显示当前系统触发次数。
代码实现
下载包
go get golang.org/x/sys/windows
go get github.com/getlantern/systray
以下是实现该工具的完整代码:
package main
import (
"fmt"
"time"
"unsafe"
"github.com/getlantern/systray"
"golang.org/x/sys/windows"
)
// 配置参数
const (
idleThreshold = 40 * time.Second
)
var (
user32 = windows.NewLazySystemDLL("user32.dll")
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
getLastInputInfo = user32.NewProc("GetLastInputInfo")
getTickCount = kernel32.NewProc("GetTickCount")
counter uint
triggerTimes []string
lastActive time.Time
)
type LASTINPUTINFO struct {
CbSize uint32
Dtime uint32
}
func main() {
systray.Run(onReady, onExit)
}
func onReady() {
// 设置托盘图标和菜单
systray.SetIcon(IconData)
systray.SetTitle("空闲监测")
systray.SetTooltip("空闲监测运行中...")
mHistory := systray.AddMenuItem("查看历史", "显示触发记录")
mReset := systray.AddMenuItem("重置计数", "重置统计信息")
mQuit := systray.AddMenuItem("退出", "退出程序")
// 初始化记录
lastActive = time.Now().Add(-getSystemIdleTime())
updateTooltip()
// 启动监测协程
go monitorLoop()
// 处理菜单点击
go func() {
for {
select {
case <-mHistory.ClickedCh:
showHistory()
case <-mReset.ClickedCh:
resetCounter()
case <-mQuit.ClickedCh:
systray.Quit()
return
}
}
}()
}
func monitorLoop() {
for {
idle := getSystemIdleTime()
updateCounter(idle)
updateTooltip()
time.Sleep(time.Second)
}
}
func updateCounter(idle time.Duration) {
if idle < idleThreshold {
actualIdle := time.Since(lastActive)
if actualIdle >= idleThreshold {
counter++
triggerTimes = append(triggerTimes, time.Now().Format("2006-01-02 15:04:05"))
}
lastActive = time.Now().Add(-idle)
}
}
func resetCounter() {
counter = 0
triggerTimes = nil
updateTooltip()
}
func updateTooltip() {
tooltip := fmt.Sprintf("空闲监测\n触发次数: %d\n最后触发: %s",
counter,
lastTriggerTime())
systray.SetTooltip(tooltip)
}
func lastTriggerTime() string {
if len(triggerTimes) == 0 {
return "从未触发"
}
return triggerTimes[len(triggerTimes)-1]
}
func showHistory() {
if len(triggerTimes) == 0 {
showMessage("触发历史", "暂无触发记录")
return
}
content := "触发时间记录:\n"
for _, t := range triggerTimes {
content += t + "\n"
}
showMessage("触发历史", content)
}
func showMessage(title, message string) {
windows.MessageBox(0,
strPtr(message),
strPtr(title),
windows.MB_OK|windows.MB_ICONINFORMATION)
}
func strPtr(s string) *uint16 {
p, _ := windows.UTF16PtrFromString(s)
return p
}
func getSystemIdleTime() time.Duration {
info := &LASTINPUTINFO{CbSize: uint32(unsafe.Sizeof(LASTINPUTINFO{}))}
ret, _, _ := getLastInputInfo.Call(uintptr(unsafe.Pointer(info)))
if ret == 0 {
return 0
}
tick, _, _ := getTickCount.Call()
lastInput := uint32(tick) - info.Dtime
return time.Duration(lastInput) * time.Millisecond
}
func onExit() {
// 退出时的清理工作
fmt.Print("\033[?25h") // 恢复光标显示(如果之前隐藏了)
}
// 图标数据(需用2goarray生成)
var IconData []byte = []byte{
// 这里填入实际的图标字节数据
}
go.mod
module idle-monitor
go 1.23.0
toolchain go1.23.7
require (
github.com/getlantern/systray v1.2.2
golang.org/x/sys v0.31.0
)
require (
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
)
需要使用 2goarray 生成图标的 bytes
变量并替换掉 IconData
变量,图标使用64×64 ico格式
下载后运行
go run 2goarray.go MyArray mypackage < myimage.ico > myimage.go
代码解析
- 配置参数:定义了空闲触发阈值和刷新间隔。
- 数据结构:定义了
LASTINPUTINFO
结构体,用于获取系统最后输入时间。 - 全局变量:定义了所需的全局变量,如用户32和内核32库的引用、触发次数等。
- 主函数:初始化显示、记录活动时间,并在循环中更新计数器和显示状态。
- 辅助函数:包括更新计数器、显示状态、初始化显示、启用虚拟终端处理和获取系统空闲时间。
通过这个简单的工具,我们可以实时监测Windows系统的空闲时间,并在达到设定阈值时进行计数。
打包为exe
go build -ldflags="-H windowsgui" -o idle-monitor.exe
运行exe,右下角会出现相应图标
鼠标悬浮显示空闲段触发次数
右键查看历史会显示历史空闲