-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathssh-auto-lock.py
More file actions
165 lines (129 loc) · 4.12 KB
/
ssh-auto-lock.py
File metadata and controls
165 lines (129 loc) · 4.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#! python3
# Kelsey Gilbert 2025-03-31 CC0: https://creativecommons.org/public-domain/cc0/
import importlib
import subprocess
import sys
import time
assert sys.platform == 'win32', f'Not supported: {sys.platform}'
# -
WINDOW_TITLE = 'ssh-auto-lock.py'
VERBOSE = '-v' in sys.argv
# -
def pip_install(package_name):
install_args = [sys.executable] + f'-m pip install {package_name}'.split(' ')
yn = input(f'pip-install "{package_name}"? (y/N) ')
yes = yn != '' and yn in 'Yy'
print(f'("{yn}" => {yes})')
if not yes:
return False
print(f'> {" ".join(install_args)}')
subprocess.run(install_args)
import importlib
importlib.invalidate_caches()
return True
# -
while True:
try:
import win32gui
import win32api
import win32con
import win32ts
break
except ModuleNotFoundError as e:
print(f'Module "{e.name}" not found.')
if not pip_install('pywin32'):
raise
try:
import win32gui
except ModuleNotFoundError as e:
print(f'Module "{e.name}" still not found!')
print(f'`importlib.invalidate_caches()` is probably still broken:',
'https://stackoverflow.com/questions/77354992/pythons-importlib-invalidate-caches-doesnt-seem-to-work-in-my-case')
print(f'Rerun the command and it should work though!')
exit(1)
continue
# -
THIS_MODULE = win32api.GetModuleHandle(None)
# -
def print2(*args):
return print(f'[{time.ctime()}]', *args)
# -
def RegisterClass(name, fn_wnd_proc, hinst=THIS_MODULE):
wc = win32gui.WNDCLASS()
wc.hInstance = hinst
wc.lpszClassName = name
wc.lpfnWndProc = fn_wnd_proc
return win32gui.RegisterClass(wc)
class CreateWindow:
def __init__(self, wclass, title='', hinst=THIS_MODULE, style=0, x=0, y=0, w=0, h=0, parent=0, menu=0):
self.hwnd = win32gui.CreateWindow(wclass, title,
style, x, y, w, h, parent, menu, hinst, None)
#win32gui.UpdateWindow(self.hwnd)
def close(self):
if not self.hwnd:
return
win32gui.DestroyWindow(self.hwnd)
self.hwnd = None
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.close()
# -
WM_NAME_BY_ID = {
win32con.WM_CREATE: 'WM_CREATE',
win32con.WM_GETMINMAXINFO: 'WM_GETMINMAXINFO',
win32con.WM_NCCREATE: 'WM_NCCREATE',
win32con.WM_CLOSE: 'WM_CLOSE',
win32con.WM_DESTROY: 'WM_DESTROY',
win32con.WM_QUERYENDSESSION: 'WM_QUERYENDSESSION',
0x2b1: 'WM_WTSSESSION_CHANGE',
}
EVENT_BY_WTS_SESSION_WPARAM = {
0x7: 'WTS_SESSION_LOCK',
0x8: 'WTS_SESSION_UNLOCK',
}
# -
def on_WTS_SESSION_LOCK():
print2(f'Session lock detected. Clearing ssh-agent:')
cmd = 'ssh-add -D'
print2(f'> {cmd}')
subprocess.run(cmd.split(' '))
def on_WTSSESSION_CHANGE(hwnd, event, session_id):
try:
event = EVENT_BY_WTS_SESSION_WPARAM[event]
except KeyError:
pass
if VERBOSE:
print2(f'<WTSSESSION_CHANGE(event={event}, session_id={session_id})>')
if event == 'WTS_SESSION_LOCK':
on_WTS_SESSION_LOCK()
def WNDPROC(hwnd, msg, wparam, lparam):
try:
msg = WM_NAME_BY_ID[msg]
except KeyError:
# You might be able to find it here: https://github.com/mhammond/pywin32/blob/main/win32/Lib/win32con.py
#print(f'Warning: Unknown WNDPROC msg: {msg}')
pass
if VERBOSE:
print2(f'<WNDPROC(hwnd, {msg}, {wparam}, {lparam})>')
if msg == 'WM_CLOSE':
WINDOW.close()
elif msg == 'WM_DESTROY':
win32gui.PostQuitMessage(0)
elif msg == 'WM_QUERYENDSESSION':
return True
# Thank you @grawity: https://superuser.com/a/264973
if msg == 'WM_WTSSESSION_CHANGE':
on_WTSSESSION_CHANGE(hwnd, wparam, lparam)
return 0
# -
WCLASS = RegisterClass('ssh-auto-lock.py: hidden window', WNDPROC)
with CreateWindow(WCLASS, title=WINDOW_TITLE) as WINDOW:
win32ts.WTSRegisterSessionNotification(WINDOW.hwnd, win32ts.NOTIFY_FOR_ALL_SESSIONS)
print2('Waiting for session change...')
try:
#win32gui.PumpMessages() # Seems uninterruptable!
while win32gui.PumpWaitingMessages() == 0:
continue
except KeyboardInterrupt:
WINDOW.close()