mirror of
https://github.com/SagerNet/sing.git
synced 2025-04-05 12:57:38 +03:00
Reuse winpowrprof callback
This commit is contained in:
parent
fa81eabc29
commit
e422e3d048
3 changed files with 102 additions and 47 deletions
|
@ -6,6 +6,8 @@ const (
|
||||||
EVENT_RESUME_AUTOMATIC // Because the user is not present, most applications should do nothing.
|
EVENT_RESUME_AUTOMATIC // Because the user is not present, most applications should do nothing.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type EventCallback = func(event int)
|
||||||
|
|
||||||
type EventListener interface {
|
type EventListener interface {
|
||||||
Start() error
|
Start() error
|
||||||
Close() error
|
Close() error
|
||||||
|
|
|
@ -6,6 +6,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewEventListener(callback func(event int)) (EventListener, error) {
|
func NewEventListener(callback EventCallback) (EventListener, error) {
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,70 +3,119 @@ package winpowrprof
|
||||||
// modify from https://github.com/golang/go/blob/b634f6fdcbebee23b7da709a243f3db217b64776/src/runtime/os_windows.go#L257
|
// modify from https://github.com/golang/go/blob/b634f6fdcbebee23b7da709a243f3db217b64776/src/runtime/os_windows.go#L257
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/x/list"
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type powerEventListener struct {
|
||||||
|
element *list.Element[EventCallback]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEventListener(callback EventCallback) (EventListener, error) {
|
||||||
|
err := initCallback()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
access.Lock()
|
||||||
|
defer access.Unlock()
|
||||||
|
return &powerEventListener{
|
||||||
|
element: callbackList.PushBack(callback),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *powerEventListener) Start() error {
|
||||||
|
access.Lock()
|
||||||
|
defer access.Unlock()
|
||||||
|
if handle != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return startListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *powerEventListener) Close() error {
|
||||||
|
access.Lock()
|
||||||
|
defer access.Unlock()
|
||||||
|
if l.element != nil {
|
||||||
|
callbackList.Remove(l.element)
|
||||||
|
}
|
||||||
|
if callbackList.Len() > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return closeListener()
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
modpowerprof = windows.NewLazySystemDLL("powrprof.dll")
|
modpowerprof = windows.NewLazySystemDLL("powrprof.dll")
|
||||||
procPowerRegisterSuspendResumeNotification = modpowerprof.NewProc("PowerRegisterSuspendResumeNotification")
|
procPowerRegisterSuspendResumeNotification = modpowerprof.NewProc("PowerRegisterSuspendResumeNotification")
|
||||||
procPowerUnregisterSuspendResumeNotification = modpowerprof.NewProc("PowerUnregisterSuspendResumeNotification")
|
procPowerUnregisterSuspendResumeNotification = modpowerprof.NewProc("PowerUnregisterSuspendResumeNotification")
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
var (
|
||||||
PBT_APMSUSPEND uint32 = 4
|
access sync.Mutex
|
||||||
PBT_APMRESUMESUSPEND uint32 = 7
|
callbackList list.List[EventCallback]
|
||||||
PBT_APMRESUMEAUTOMATIC uint32 = 18
|
initCallbackOnce sync.Once
|
||||||
|
rawCallback uintptr
|
||||||
|
handle uintptr
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
func initCallback() error {
|
||||||
_DEVICE_NOTIFY_CALLBACK = 2
|
err := procPowerRegisterSuspendResumeNotification.Find()
|
||||||
)
|
if err != nil {
|
||||||
|
return err // Running on Windows 7, where we don't need it anyway.
|
||||||
type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
|
}
|
||||||
callback uintptr
|
err = procPowerUnregisterSuspendResumeNotification.Find()
|
||||||
context uintptr
|
if err != nil {
|
||||||
|
return err // Running on Windows 7, where we don't need it anyway.
|
||||||
|
}
|
||||||
|
initCallbackOnce.Do(func() {
|
||||||
|
rawCallback = windows.NewCallback(func(context uintptr, changeType uint32, setting uintptr) uintptr {
|
||||||
|
const (
|
||||||
|
PBT_APMSUSPEND uint32 = 4
|
||||||
|
PBT_APMRESUMESUSPEND uint32 = 7
|
||||||
|
PBT_APMRESUMEAUTOMATIC uint32 = 18
|
||||||
|
)
|
||||||
|
var event int
|
||||||
|
switch changeType {
|
||||||
|
case PBT_APMSUSPEND:
|
||||||
|
event = EVENT_SUSPEND
|
||||||
|
case PBT_APMRESUMESUSPEND:
|
||||||
|
event = EVENT_RESUME
|
||||||
|
case PBT_APMRESUMEAUTOMATIC:
|
||||||
|
event = EVENT_RESUME_AUTOMATIC
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
access.Lock()
|
||||||
|
callbacks := callbackList.Array()
|
||||||
|
access.Unlock()
|
||||||
|
for _, callback := range callbacks {
|
||||||
|
callback(event)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type eventListener struct {
|
func startListener() error {
|
||||||
params _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS
|
type DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
|
||||||
handle uintptr
|
callback uintptr
|
||||||
}
|
context uintptr
|
||||||
|
|
||||||
func NewEventListener(callback func(event int)) (EventListener, error) {
|
|
||||||
if err := procPowerRegisterSuspendResumeNotification.Find(); err != nil {
|
|
||||||
return nil, err // Running on Windows 7, where we don't need it anyway.
|
|
||||||
}
|
}
|
||||||
if err := procPowerUnregisterSuspendResumeNotification.Find(); err != nil {
|
const DEVICE_NOTIFY_CALLBACK = 2
|
||||||
return nil, err // Running on Windows 7, where we don't need it anyway.
|
params := DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
|
||||||
|
callback: rawCallback,
|
||||||
}
|
}
|
||||||
|
|
||||||
var fn interface{} = func(context uintptr, changeType uint32, setting uintptr) uintptr {
|
|
||||||
switch changeType {
|
|
||||||
case PBT_APMSUSPEND:
|
|
||||||
callback(EVENT_SUSPEND)
|
|
||||||
case PBT_APMRESUMESUSPEND:
|
|
||||||
callback(EVENT_RESUME)
|
|
||||||
case PBT_APMRESUMEAUTOMATIC:
|
|
||||||
callback(EVENT_RESUME_AUTOMATIC)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return &eventListener{
|
|
||||||
params: _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
|
|
||||||
callback: windows.NewCallback(fn),
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *eventListener) Start() error {
|
|
||||||
_, _, errno := syscall.SyscallN(
|
_, _, errno := syscall.SyscallN(
|
||||||
procPowerRegisterSuspendResumeNotification.Addr(),
|
procPowerRegisterSuspendResumeNotification.Addr(),
|
||||||
_DEVICE_NOTIFY_CALLBACK,
|
DEVICE_NOTIFY_CALLBACK,
|
||||||
uintptr(unsafe.Pointer(&l.params)),
|
uintptr(unsafe.Pointer(¶ms)),
|
||||||
uintptr(unsafe.Pointer(&l.handle)),
|
uintptr(unsafe.Pointer(&handle)),
|
||||||
)
|
)
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return errno
|
return errno
|
||||||
|
@ -74,10 +123,14 @@ func (l *eventListener) Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *eventListener) Close() error {
|
func closeListener() error {
|
||||||
_, _, errno := syscall.SyscallN(procPowerUnregisterSuspendResumeNotification.Addr(), uintptr(unsafe.Pointer(&l.handle)))
|
if handle == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, _, errno := syscall.SyscallN(procPowerUnregisterSuspendResumeNotification.Addr(), uintptr(unsafe.Pointer(&handle)))
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return errno
|
return errno
|
||||||
}
|
}
|
||||||
|
handle = 0
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue