Skip to content

Commit

Permalink
add methods for removing hotkeys and hotstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
spyoungtech committed Jul 8, 2023
1 parent bf83a24 commit 8d72d3c
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 2 deletions.
21 changes: 21 additions & 0 deletions ahk/_async/engine.py
Expand Up @@ -189,6 +189,27 @@ def add_hotstring(
warnings.warn(warning.message, warning.category, stacklevel=2)
return None

def remove_hotkey(self, keyname: str) -> None:
def _() -> None:
return None

h = Hotkey(keyname=keyname, callback=_) # XXX: this can probably be avoided
self._transport.remove_hotkey(hotkey=h)
return None

def clear_hotkeys(self) -> None:
self._transport.clear_hotkeys()
return None

def remove_hotstring(self, trigger: str) -> None:
hs = Hotstring(trigger=trigger, replacement_or_callback='') # XXX: this can probably be avoided
self._transport.remove_hotstring(hs)
return None

def clear_hotstrings(self) -> None:
self._transport.clear_hotstrings()
return None

async def set_title_match_mode(self, title_match_mode: TitleMatchMode, /) -> None:
"""
Sets the default title match mode
Expand Down
16 changes: 16 additions & 0 deletions ahk/_async/transport.py
Expand Up @@ -362,6 +362,22 @@ def add_hotstring(self, hotstring: Hotstring) -> None:
warnings.warn(warning.message, warning.category, stacklevel=2)
return None

def remove_hotkey(self, hotkey: Hotkey) -> None:
self._hotkey_transport.remove_hotkey(hotkey)
return None

def clear_hotkeys(self) -> None:
self._hotkey_transport.clear_hotkeys()
return None

def remove_hotstring(self, hotstring: Hotstring) -> None:
self._hotkey_transport.remove_hotstring(hotstring)
return None

def clear_hotstrings(self) -> None:
self._hotkey_transport.clear_hotstrings()
return None

def start_hotkeys(self) -> None:
return self._hotkey_transport.start()

Expand Down
40 changes: 40 additions & 0 deletions ahk/_hotkey.py
Expand Up @@ -7,6 +7,7 @@
import subprocess
import sys
import threading
import time
import warnings
from abc import ABC
from abc import abstractmethod
Expand Down Expand Up @@ -102,6 +103,38 @@ def add_hotstring(self, hotstring: Hotstring) -> None:
# TODO: add support for adding IfWinActive/IfWinExist
return None

def remove_hotkey(self, hotkey: Hotkey) -> None:
if hotkey._id not in self._callback_registry:
raise ValueError(f'Hotkey {hotkey.keyname!r} is not registered')
del self._hotkeys[hotkey._id]
self._get_callback_registry.cache_clear()
if self._running:
self.restart()
return None

def clear_hotkeys(self) -> None:
self._hotkeys.clear()
self._get_callback_registry.cache_clear()
if self._running:
self.restart()
return None

def remove_hotstring(self, hotstring: Hotstring) -> None:
if hotstring._id not in self._callback_registry:
raise ValueError(f'Hostring {hotstring.trigger!r} is not registered')
del self._hotstrings[hotstring._id]
self._get_callback_registry.cache_clear()
if self._running:
self.restart()
return None

def clear_hotstrings(self) -> None:
self._hotstrings.clear()
self._get_callback_registry.cache_clear()
if self._running:
self.restart()
return None

def on_clipboard_change(
self, callback: Callable[[int], Any], ex_handler: Optional[Callable[[int, Exception], Any]] = None
) -> None:
Expand Down Expand Up @@ -170,6 +203,13 @@ def start(self) -> None:
dispatcher_thread.start()

def stop(self) -> None:
assert self._running is True, 'Not running! Must be started first!'
assert self._dispatcher_thread is not None
for i in range(1, 6):
if self._proc is not None:
break
logging.debug(f'stop called before dispatched has started proc. Waiting for proc ({i}/5)')
time.sleep(0.2)
assert self._proc is not None
self._running = False

Expand Down
22 changes: 22 additions & 0 deletions ahk/_sync/engine.py
Expand Up @@ -185,6 +185,27 @@ def add_hotstring(
warnings.warn(warning.message, warning.category, stacklevel=2)
return None

def remove_hotkey(self, keyname: str) -> None:
def _() -> None:
return None
h = Hotkey(keyname=keyname, callback=_) # XXX: this can probably be avoided
self._transport.remove_hotkey(hotkey=h)
return None

def clear_hotkeys(self) -> None:
self._transport.clear_hotkeys()
return None

def remove_hotstring(self, trigger: str) -> None:
hs = Hotstring(trigger=trigger, replacement_or_callback='') # XXX: this can probably be avoided
self._transport.remove_hotstring(hs)
return None

def clear_hotstrings(self) -> None:
self._transport.clear_hotstrings()
return None


def set_title_match_mode(self, title_match_mode: TitleMatchMode, /) -> None:
"""
Sets the default title match mode
Expand Down Expand Up @@ -2693,6 +2714,7 @@ def image_search(

if coord_mode is not None:
args.append(coord_mode)

resp = self._transport.function_call('AHKImageSearch', args, blocking=blocking)
return resp

Expand Down
19 changes: 19 additions & 0 deletions ahk/_sync/transport.py
Expand Up @@ -343,6 +343,25 @@ def add_hotstring(self, hotstring: Hotstring) -> None:
warnings.warn(warning.message, warning.category, stacklevel=2)
return None

def remove_hotkey(self, hotkey: Hotkey) -> None:
self._hotkey_transport.remove_hotkey(hotkey)
return None

def clear_hotkeys(self) -> None:
self._hotkey_transport.clear_hotkeys()
return None

def remove_hotstring(self, hotstring: Hotstring) -> None:
self._hotkey_transport.remove_hotstring(hotstring)
return None

def clear_hotstrings(self) -> None:
self._hotkey_transport.clear_hotstrings()
return None




def start_hotkeys(self) -> None:
return self._hotkey_transport.start()

Expand Down
22 changes: 21 additions & 1 deletion tests/_async/test_hotkeys.py
Expand Up @@ -14,7 +14,7 @@
sleep = time.sleep


class TestMouseAsync(IsolatedAsyncioTestCase):
class TestHotkeysAsync(IsolatedAsyncioTestCase):
win: AsyncWindow

async def asyncSetUp(self) -> None:
Expand Down Expand Up @@ -47,3 +47,23 @@ def side_effect():
await self.ahk.key_press('a')
await async_sleep(1)
mock_ex_handler.assert_called()

async def test_remove_hotkey(self):
with mock.MagicMock(return_value=None) as m:
self.ahk.add_hotkey('a', callback=m)
self.ahk.start_hotkeys()
self.ahk.remove_hotkey('a')
await self.ahk.key_down('a')
await self.ahk.key_press('a')
await async_sleep(1)
m.assert_not_called()

async def test_clear_hotkeys(self):
with mock.MagicMock(return_value=None) as m:
self.ahk.add_hotkey('a', callback=m)
self.ahk.start_hotkeys()
self.ahk.clear_hotkeys()
await self.ahk.key_down('a')
await self.ahk.key_press('a')
await async_sleep(1)
m.assert_not_called()
20 changes: 20 additions & 0 deletions tests/_async/test_keys.py
Expand Up @@ -48,6 +48,26 @@ async def test_hotstring(self):

assert 'by the way' in await self.win.get_text()

async def test_remove_hotstring(self):
self.ahk.add_hotstring('btw', 'by the way')
self.ahk.start_hotkeys()
await self.ahk.set_send_level(1)
await self.win.activate()
self.ahk.remove_hotstring('btw')
await self.ahk.send('btw ')
time.sleep(2)
assert 'by the way' not in await self.win.get_text()

async def test_clear_hotstrings(self):
self.ahk.add_hotstring('btw', 'by the way')
self.ahk.start_hotkeys()
await self.ahk.set_send_level(1)
await self.win.activate()
self.ahk.clear_hotstrings()
await self.ahk.send('btw ')
time.sleep(2)
assert 'by the way' not in await self.win.get_text()

async def test_hotstring_callback(self):
with unittest.mock.MagicMock(return_value=None) as m:
self.ahk.add_hotstring('btw', m)
Expand Down
22 changes: 21 additions & 1 deletion tests/_sync/test_hotkeys.py
Expand Up @@ -11,7 +11,7 @@
sleep = time.sleep


class TestMouseAsync(TestCase):
class TestHotkeysAsync(TestCase):
win: Window

def setUp(self) -> None:
Expand Down Expand Up @@ -44,3 +44,23 @@ def side_effect():
self.ahk.key_press('a')
sleep(1)
mock_ex_handler.assert_called()

def test_remove_hotkey(self):
with mock.MagicMock(return_value=None) as m:
self.ahk.add_hotkey('a', callback=m)
self.ahk.start_hotkeys()
self.ahk.remove_hotkey('a')
self.ahk.key_down('a')
self.ahk.key_press('a')
sleep(1)
m.assert_not_called()

def test_clear_hotkeys(self):
with mock.MagicMock(return_value=None) as m:
self.ahk.add_hotkey('a', callback=m)
self.ahk.start_hotkeys()
self.ahk.clear_hotkeys()
self.ahk.key_down('a')
self.ahk.key_press('a')
sleep(1)
m.assert_not_called()
20 changes: 20 additions & 0 deletions tests/_sync/test_keys.py
Expand Up @@ -47,6 +47,26 @@ def test_hotstring(self):

assert 'by the way' in self.win.get_text()

def test_remove_hotstring(self):
self.ahk.add_hotstring('btw', 'by the way')
self.ahk.start_hotkeys()
self.ahk.set_send_level(1)
self.win.activate()
self.ahk.remove_hotstring('btw')
self.ahk.send('btw ')
time.sleep(2)
assert 'by the way' not in self.win.get_text()

def test_clear_hotstrings(self):
self.ahk.add_hotstring('btw', 'by the way')
self.ahk.start_hotkeys()
self.ahk.set_send_level(1)
self.win.activate()
self.ahk.clear_hotstrings()
self.ahk.send('btw ')
time.sleep(2)
assert 'by the way' not in self.win.get_text()

def test_hotstring_callback(self):
with unittest.mock.MagicMock(return_value=None) as m:
self.ahk.add_hotstring('btw', m)
Expand Down

0 comments on commit 8d72d3c

Please sign in to comment.