mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 04:04:21 +02:00
Refuse window input when Windows cannot focus its target
This commit is contained in:
1 parent
da5c954ce4
commit
6104c3f192
3 files changed
+30
-3
No files matched your search
@@ -41,7 +41,9 @@ API choices are **documented**, not device verification:
|
||||
|
||||
Windows needs a WGC-capable Windows 10/11 desktop and an available hardware
|
||||
Media Foundation H.264 encoder. Elevated windows and the secure desktop
|
||||
cannot be driven by an ordinary Frame Control process. Minimized/closed
|
||||
cannot be driven by an ordinary Frame Control process. If Windows refuses
|
||||
to focus a selected window, input is refused rather than sent to the app
|
||||
covering it; bring the selected window forward, then Stop and Show again. Minimized/closed
|
||||
windows may stop producing frames. Protected content is not supported.
|
||||
|
||||
On Linux, press **Choose a window or screen…** and approve the desktop's
|
||||
|
||||
@@ -93,6 +93,16 @@ class AdapterTests(unittest.TestCase):
|
||||
self.assertIn(mock.call(mouse=(0, 0, 0, 0x10)), host.send.call_args_list)
|
||||
self.assertIn(mock.call(key=(162, 0, 2)), host.send.call_args_list)
|
||||
|
||||
def test_refused_windows_focus_never_clicks_the_covering_app(self):
|
||||
host = mock.Mock()
|
||||
host.rect.return_value = (0, 0, 800, 600)
|
||||
host.user.GetForegroundWindow.return_value = 99
|
||||
host.user.SetForegroundWindow.return_value = False
|
||||
inp = capture.WindowsInput(host, dict(src='window:12', w=800, h=600))
|
||||
with self.assertRaisesRegex(RuntimeError, 'could not focus'):
|
||||
inp.handle(dict(t='m', e='down', b=0, x=.5, y=.5))
|
||||
host.send.assert_not_called()
|
||||
|
||||
def test_pc_reuses_launcher_and_namespaces_panel_ids(self):
|
||||
view = frame_pcview.PCView(['ssh'], mock.Mock(return_value='panel created'), 'frame')
|
||||
view.call = mock.Mock(side_effect=lambda path, **kw: {'screen': True, 'ticket': 'one-use', 'streams': []})
|
||||
|
||||
+17
-2
@@ -217,6 +217,8 @@ class Windows:
|
||||
self.user.GetWindowTextW.argtypes = [W.HWND, W.LPWSTR, C.c_int]
|
||||
self.user.GetWindowRect.argtypes = [W.HWND, C.POINTER(W.RECT)]
|
||||
self.user.SetForegroundWindow.argtypes = [W.HWND]
|
||||
self.user.GetForegroundWindow.argtypes = []
|
||||
self.user.GetForegroundWindow.restype = W.HWND
|
||||
self.dwm.DwmGetWindowAttribute.argtypes = [W.HWND, W.DWORD, C.c_void_p, W.DWORD]
|
||||
self.callback = C.WINFUNCTYPE(W.BOOL, W.HWND, W.LPARAM)
|
||||
self.monitor_callback = C.WINFUNCTYPE(W.BOOL, W.HMONITOR, W.HDC, C.POINTER(W.RECT), W.LPARAM)
|
||||
@@ -305,6 +307,16 @@ class WindowsInput:
|
||||
if error:
|
||||
raise error
|
||||
|
||||
def focus(self):
|
||||
if not self.source['src'].startswith('window:'):
|
||||
return
|
||||
hwnd = int(self.source['src'].split(':')[1])
|
||||
user = self.host.user
|
||||
if user.GetForegroundWindow() != hwnd and not user.SetForegroundWindow(hwnd):
|
||||
raise RuntimeError('Windows could not focus this window. Bring it to the front on your PC, then press Stop and Show again.')
|
||||
if user.GetForegroundWindow() != hwnd:
|
||||
raise RuntimeError('The selected window is not in front. Reopen the view after bringing it to the front on your PC.')
|
||||
|
||||
def handle(self, m):
|
||||
t, u = m['t'], self.host.user
|
||||
if t == 'release':
|
||||
@@ -314,8 +326,8 @@ class WindowsInput:
|
||||
if source['src'].startswith('window:'):
|
||||
hwnd = int(source['src'].split(':')[1])
|
||||
x, y, w, h = self.host.rect(hwnd)
|
||||
if m.get('e') == 'down':
|
||||
u.SetForegroundWindow(hwnd)
|
||||
if m.get('e') == 'down' or t == 'wheel':
|
||||
self.focus()
|
||||
else:
|
||||
x, y, w, h = (source[k] for k in ('x', 'y', 'w', 'h'))
|
||||
x += max(0, min(1, float(m.get('x', 0)))) * (w - 1)
|
||||
@@ -335,6 +347,8 @@ class WindowsInput:
|
||||
self.host.send(mouse=(0, 0, delta & 0xffffffff, flag))
|
||||
elif t == 'k':
|
||||
code, down = str(m.get('code', '')), m.get('e') == 'down'
|
||||
if down:
|
||||
self.focus()
|
||||
special = {'Enter': 13, 'Escape': 27, 'Tab': 9, 'Backspace': 8, 'Space': 32,
|
||||
'ArrowLeft': 37, 'ArrowUp': 38, 'ArrowRight': 39, 'ArrowDown': 40,
|
||||
'Delete': 46, 'Home': 36, 'End': 35, 'PageUp': 33, 'PageDown': 34,
|
||||
@@ -350,6 +364,7 @@ class WindowsInput:
|
||||
elif down and len(str(m.get('key', ''))) == 1:
|
||||
self.handle({'t': 'text', 's': m['key']})
|
||||
elif t == 'text':
|
||||
self.focus()
|
||||
raw = str(m.get('s', ''))[:4096].encode('utf-16-le')
|
||||
for i in range(0, len(raw), 2):
|
||||
unit = int.from_bytes(raw[i:i+2], 'little')
|
||||
|
||||
Reference in new issue
Block a user