2020-08-18 11:59:20 +00:00
|
|
|
package afterlock
|
|
|
|
|
|
|
|
import(
|
|
|
|
"time"
|
|
|
|
"errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2020-08-20 14:57:57 +00:00
|
|
|
// Display controls and monitors the physical display
|
|
|
|
type Display interface {
|
|
|
|
Suspend() error
|
|
|
|
IsOn() (bool, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lockscreen can determine whether the screensaver is active or not
|
|
|
|
type Lockscreen interface {
|
|
|
|
IsActive() (bool, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// KeypressDetector can wait for keypresses
|
|
|
|
type KeypressDetector interface {
|
|
|
|
BlockUntilKeypress(string) error
|
|
|
|
}
|
|
|
|
|
2020-08-18 11:59:20 +00:00
|
|
|
// AfterLock suspends the display when the lockscreen is active
|
|
|
|
type AfterLock struct {
|
|
|
|
InitialDelay uint
|
|
|
|
LoopDelay uint
|
|
|
|
keyboardDeviceNode string
|
2020-08-20 15:07:05 +00:00
|
|
|
keypressFlag *AtomicFlag
|
2020-08-20 14:57:57 +00:00
|
|
|
Display Display
|
|
|
|
LockScreen Lockscreen
|
|
|
|
KeypressDetector KeypressDetector
|
2020-08-18 11:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// New constructs a new AfterLock instance
|
|
|
|
func New(keyboardDeviceNode string) *AfterLock {
|
|
|
|
return &AfterLock{
|
|
|
|
keyboardDeviceNode: keyboardDeviceNode,
|
2020-08-20 15:07:05 +00:00
|
|
|
keypressFlag: NewAtomicFlag(false),
|
2020-08-18 11:59:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-20 14:57:57 +00:00
|
|
|
// Start starts monitoring the lockscreen/keyboard to determine
|
2020-08-18 11:59:20 +00:00
|
|
|
// when to suspend the display.
|
|
|
|
// Exits after the computer is unlocked
|
2020-08-20 14:57:57 +00:00
|
|
|
// Requires InitialDelay, LoopDelay, Display and LockScreen to be set
|
2020-08-18 11:59:20 +00:00
|
|
|
func (af *AfterLock) Start() {
|
2020-08-20 14:57:57 +00:00
|
|
|
af.checkStructConfigured()
|
2020-08-18 11:59:20 +00:00
|
|
|
|
|
|
|
go af.detectKeypresses()
|
|
|
|
|
|
|
|
time.Sleep(time.Duration(af.InitialDelay) * time.Second)
|
|
|
|
af.hybernateDisplayLoop()
|
|
|
|
}
|
|
|
|
|
2020-08-20 14:57:57 +00:00
|
|
|
func (af *AfterLock) checkStructConfigured() {
|
2020-08-18 11:59:20 +00:00
|
|
|
if af.InitialDelay == 0 {
|
|
|
|
panic(errors.New("InitialDelay not configured"))
|
|
|
|
}
|
|
|
|
if af.LoopDelay == 0 {
|
|
|
|
panic(errors.New("LoopDelay not configured"))
|
|
|
|
}
|
2020-08-20 14:57:57 +00:00
|
|
|
if af.Display == nil {
|
|
|
|
panic(errors.New("Display not configured"))
|
|
|
|
}
|
|
|
|
if af.LockScreen == nil {
|
|
|
|
panic(errors.New("LockScreen not configured"))
|
|
|
|
}
|
|
|
|
if af.KeypressDetector == nil {
|
|
|
|
panic(errors.New("KeypressDetector not configured"))
|
|
|
|
}
|
2020-08-18 11:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (af *AfterLock) detectKeypresses() {
|
|
|
|
for {
|
2020-08-20 14:57:57 +00:00
|
|
|
err := af.KeypressDetector.BlockUntilKeypress(af.keyboardDeviceNode)
|
2020-08-18 11:59:20 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
af.keypressFlag.Set(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (af *AfterLock) hybernateDisplayLoop() {
|
|
|
|
for {
|
2020-08-20 14:57:57 +00:00
|
|
|
screenLocked, err := af.LockScreen.IsActive()
|
2020-08-18 11:59:20 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
if !screenLocked {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-08-20 14:57:57 +00:00
|
|
|
displayOn, err := af.Display.IsOn()
|
2020-08-18 11:59:20 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
if displayOn {
|
2020-08-20 14:57:57 +00:00
|
|
|
err := af.Display.Suspend()
|
2020-08-18 11:59:20 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2020-08-21 08:35:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
time.Sleep(time.Duration(af.LoopDelay) * time.Second)
|
|
|
|
if af.keypressFlag.Get() {
|
|
|
|
af.keypressFlag.Set(false)
|
|
|
|
continue
|
2020-08-18 11:59:20 +00:00
|
|
|
}
|
2020-08-21 08:35:05 +00:00
|
|
|
break
|
2020-08-18 11:59:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|