Handle Lockscreen

pause if screen is locked
This commit is contained in:
Simon Zeyer 2021-12-23 15:15:35 +01:00
parent 172a91c740
commit 0b8f3ad9b6
3 changed files with 143 additions and 8 deletions

View File

@ -13,9 +13,29 @@ from resources import LineState, CLMgrMessage
import serial
from serial import SerialException
import session_event_listener as sel
import ctypes
portName = 'COM3'
global_inactive = True
# Lock Screen detection
user32 = ctypes.windll.User32
OpenDesktop = user32.OpenDesktopA
SwitchDesktop = user32.SwitchDesktop
DESKTOP_SWITCHDESKTOP = 0x0100
global_screen_locked = False
def check_screen_locked():
hDesktop = OpenDesktop ("default", 0, False, DESKTOP_SWITCHDESKTOP)
result = SwitchDesktop (hDesktop)
if result:
return True
else:
return False
def sendSerial(byte):
try:
ser = serial.Serial(port=portName, baudrate=115200)
@ -31,6 +51,7 @@ class PhoneLineEventHandler():
def OnDispOnLineMgrNotification(self, msg, param, returns=""):
global global_inactive, global_screen_locked
if not self.phone_mgr:
self.phone_mgr = win32com.client.Dispatch("CLMgr.ClientLineMgr")
if not self.phone_mgr:
@ -46,15 +67,21 @@ class PhoneLineEventHandler():
)
if line.DispState != LineState.Inactive:
if line.DispState == LineState.Ringing:
sendSerial(b'shc131139131')
sendSerial(b'shc000255000')
else:
sendSerial(b'shc255029000')
asyncio.run(try_pause())
sendSerial(b'shc255000000')
if not global_screen_locked:
asyncio.run(try_pause())
global_inactive = False
for linenum in range(self.phone_mgr.DispNumberOfLines):
line = self.phone_mgr.DispGetLine(linenum)
if line.DispState != LineState.Inactive:
return True
asyncio.run(try_play())
if not global_screen_locked:
asyncio.run(try_play())
global_inactive = True
sendSerial(b'shc000000000')
return True
@ -102,8 +129,27 @@ async def try_pause():
if current_session:
await current_session.try_pause_async()
def OnSessionEvent(event: sel.SessionEvent):
global global_inactive, global_screen_locked
if event == sel.SessionEvent.SESSION_LOCK:
global_screen_locked = True
print("locked, try_pause")
asyncio.run(try_pause())
if event == sel.SessionEvent.SESSION_UNLOCK:
global_screen_locked = False
if global_inactive:
print("unlocked, global inactive, tryplay")
asyncio.run(try_play())
if __name__ == '__main__':
win32com.client.WithEvents("CLMgr.ClientLineMgr", PhoneLineEventHandler)
while True:
pythoncom.PumpWaitingMessages()
time.sleep(0.1) # Don't use up all our CPU checking constantly
m = sel.WorkstationMonitor()
m.register_handler(sel.SessionEvent.ANY, handler=OnSessionEvent)
try:
while True:
pythoncom.PumpWaitingMessages()
m.listen()
time.sleep(0.1) # Don't use up all our CPU checking constantly
except KeyboardInterrupt:
print("exit")

View File

@ -1,2 +1,3 @@
winrt
pywin32
pywin32
python3-tk

88
session_event_listener.py Normal file
View File

@ -0,0 +1,88 @@
from collections import defaultdict
from enum import Enum
import win32api
import win32con
import win32gui
import win32ts
class SessionEvent(Enum):
ANY = 0
# window messages
CHANGE = 0x2B1 # WM_WTSSESSION_CHANGE
# WM_WTSSESSION_CHANGE events (wparam)
CONSOLE_CONNECT = 0x1 # WTS_CONSOLE_CONNECT
CONSOLE_DISCONNECT = 0x2 # WTS_CONSOLE_DISCONNECT
REMOTE_CONNECT = 0x3 # WTS_REMOTE_CONNECT
REMOTE_DISCONNECT = 0x4 # WTS_REMOTE_DISCONNECT
SESSION_LOGON = 0x5 # WTS_SESSION_LOGON
SESSION_LOGOFF = 0x6 # WTS_SESSION_LOGOFF
SESSION_LOCK = 0x7 # WTS_SESSION_LOCK
SESSION_UNLOCK = 0x8 # WTS_SESSION_UNLOCK
SESSION_REMOTE_CONTROL = 0x9 # WTS_SESSION_REMOTE_CONTROL
class WorkstationMonitor:
CLASS_NAME = "WorkstationMonitor"
WINDOW_TITLE = "Workstation Event Monitor"
def __init__(self):
self.window_handle = None
self.event_handlers = defaultdict(list)
self._register_listener()
def _register_listener(self):
wc = win32gui.WNDCLASS()
wc.hInstance = handle_instance = win32api.GetModuleHandle(None)
wc.lpszClassName = self.CLASS_NAME
wc.lpfnWndProc = self._window_procedure
window_class = win32gui.RegisterClass(wc)
style = 0
self.window_handle = win32gui.CreateWindow(window_class,
self.WINDOW_TITLE,
style,
0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT,
0, 0, handle_instance, None)
win32gui.UpdateWindow(self.window_handle)
# scope = win32ts.NOTIFY_FOR_THIS_SESSION
scope = win32ts.NOTIFY_FOR_ALL_SESSIONS
win32ts.WTSRegisterSessionNotification(self.window_handle, scope)
def listen(self):
win32gui.PumpMessages()
def stop(self):
exit_code = 0
win32gui.PostQuitMessage(exit_code)
def _window_procedure(self, window_handle: int, message: int, event_id, session_id):
"""
# WindowProc callback function
https://msdn.microsoft.com/en-us/library/ms633573(v=VS.85).aspx
"""
if message == SessionEvent.CHANGE.value:
self._handle_session_change(SessionEvent(event_id), session_id)
elif message == win32con.WM_CLOSE:
win32gui.DestroyWindow(window_handle)
elif message == win32con.WM_DESTROY:
win32gui.PostQuitMessage(0)
elif message == win32con.WM_QUERYENDSESSION:
return True
def _handle_session_change(self, event: SessionEvent, session_id: int):
for handler in self.event_handlers[event]:
handler(event)
for handler in self.event_handlers[SessionEvent.ANY]:
handler(event)
def register_handler(self, event: SessionEvent, handler: callable):
self.event_handlers[event].append(handler)
if __name__ == '__main__':
m = WorkstationMonitor()
m.register_handler(SessionEvent.ANY, handler=print)
m.listen()