Add AT-SPI pointer monitor wrappers

This commit is contained in:
Storm Dragon
2026-04-07 17:11:13 -04:00
parent 8e792dd4e2
commit d7d26c57f4
2 changed files with 213 additions and 5 deletions
@@ -0,0 +1,135 @@
import sys
import types
import unittest
from pathlib import Path
from unittest import mock
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from cthulhu import input_event_manager
class FakeDevice:
def __init__(self):
self.add_key_watcher_calls = []
self.connect_calls = []
self.disconnect_calls = []
self.set_capabilities_calls = []
self.capabilities = 0
self.next_handler_id = 17
def add_key_watcher(self, callback, user_data=None):
self.add_key_watcher_calls.append((callback, user_data))
def connect(self, signalName, callback):
self.connect_calls.append((signalName, callback))
return self.next_handler_id
def disconnect(self, handlerId):
self.disconnect_calls.append(handlerId)
def get_capabilities(self):
return self.capabilities
def set_capabilities(self, capabilities):
self.set_capabilities_calls.append(capabilities)
self.capabilities = capabilities
return capabilities
class FakeDeviceFactory:
def __init__(self, device):
self.device = device
self.new_calls = 0
self.new_full_calls = 0
self.app_ids = []
def new(self):
self.new_calls += 1
return self.device
def new_full(self, appId):
self.new_full_calls += 1
self.app_ids.append(appId)
return self.device
class InputEventManagerPointerMonitorTests(unittest.TestCase):
def setUp(self):
self.manager = input_event_manager.InputEventManager()
def test_activate_device_creates_the_device_only_once(self):
device = FakeDevice()
deviceFactory = FakeDeviceFactory(device)
fakeAtspi = types.SimpleNamespace(
get_version=lambda: (2, 58, 4),
Device=deviceFactory,
)
with mock.patch.object(input_event_manager, "Atspi", fakeAtspi):
firstDevice = self.manager.activate_device()
secondDevice = self.manager.activate_device()
self.assertIs(firstDevice, device)
self.assertIs(secondDevice, device)
self.assertEqual(deviceFactory.new_full_calls, 1)
self.assertEqual(deviceFactory.new_calls, 0)
self.assertEqual(deviceFactory.app_ids, ["org.stormux.Cthulhu"])
def test_enable_pointer_monitoring_returns_false_without_a_device(self):
fakeAtspi = types.SimpleNamespace()
with mock.patch.object(input_event_manager, "Atspi", fakeAtspi):
self.assertFalse(self.manager.enable_pointer_monitoring())
def test_enable_pointer_monitoring_returns_false_when_device_capability_is_missing(self):
device = FakeDevice()
deviceFactory = FakeDeviceFactory(device)
fakeAtspi = types.SimpleNamespace(
get_version=lambda: (2, 58, 4),
Device=deviceFactory,
)
with mock.patch.object(input_event_manager, "Atspi", fakeAtspi):
self.manager.activate_device()
self.assertFalse(self.manager.enable_pointer_monitoring())
self.assertEqual(device.set_capabilities_calls, [])
def test_enable_pointer_monitoring_returns_true_when_pointer_monitor_is_granted(self):
device = FakeDevice()
deviceFactory = FakeDeviceFactory(device)
fakeDeviceCapability = types.SimpleNamespace(POINTER_MONITOR=8)
fakeAtspi = types.SimpleNamespace(
get_version=lambda: (2, 58, 4),
Device=deviceFactory,
DeviceCapability=fakeDeviceCapability,
)
with mock.patch.object(input_event_manager, "Atspi", fakeAtspi):
self.manager.activate_device()
self.assertTrue(self.manager.enable_pointer_monitoring())
self.assertEqual(device.set_capabilities_calls, [8])
self.assertEqual(device.capabilities, 8)
def test_start_and_stop_pointer_watcher_connect_and_disconnect_pointer_moved(self):
device = FakeDevice()
deviceFactory = FakeDeviceFactory(device)
fakeAtspi = types.SimpleNamespace(
get_version=lambda: (2, 58, 4),
Device=deviceFactory,
)
callback = mock.Mock()
with mock.patch.object(input_event_manager, "Atspi", fakeAtspi):
self.manager.activate_device()
self.manager.start_pointer_watcher(callback)
self.manager.stop_pointer_watcher()
self.assertEqual(device.connect_calls, [("pointer-moved", callback)])
self.assertEqual(device.disconnect_calls, [17])
if __name__ == "__main__":
unittest.main()