class Voice2Keyboard:
    def __init__(self):
        self.hook = Hook()
        self.hook.handler = self.on_event
        self.HOTKEY = {'Lwin', 'Z'}
        self.LANGUAGE = "tr-TR"
        self.recognizer = speech_recognition.Recognizer()
        self.lock = False
        self.list_devices()

    def list_devices(self):
        for index, name in enumerate(
                speech_recognition.Microphone.list_microphone_names()):
            log.info(f"device_index[{index}]='{name}'")

        log.info(
            "if microphone doesn't work, try to set DEVICE_INDEX to one the devices above"
        )
        self.DEVICE_INDEX = None

    def on_event(self, event):
        if not isinstance(
                event,
                KeyboardEvent) or event.event_type != 'key down' or self.lock:
            return False

        if set(event.pressed_key) != self.HOTKEY:
            # log.info(event.__dict__)
            return False

        self.lock = True

        log.info("listening...")
        with speech_recognition.Microphone(
                device_index=self.DEVICE_INDEX) as source:
            audio = self.recognizer.listen(source)

        log.info("converting audio to text...")
        try:
            text = self.recognizer.recognize_google(
                audio_data=audio,
                # This uses Google Speech Engine's public API key.
                # If you exceed the quota, you need your own API key from https://console.developers.google.com/
                key="AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw",
                language=self.LANGUAGE)
            log.info(f"typing '{text}'")
            keyboard.send_keys(text, with_spaces=True)
        except:
            log.exception("")
        finally:
            keyboard.send_keys("{VK_LWIN up}{Z up}")
            self.lock = False

    def listen(self):
        log.info(f"registering {self.HOTKEY} hotkey")
        self.hook.hook(keyboard=True, mouse=False)

    def exit(self):
        log.info(f"unregistering hotkey")
        self.hook.unhook_keyboard()
def mouse_key_hook():
    global monitor_thread_id
    global hk
    monitor_thread_id = win32api.GetCurrentThreadId()
    hk = Hook()
    hk.handler = on_event
    
    hk.hook(keyboard=True, mouse=True)
 def __init__(self):
     self.hook = Hook()
     self.hook.handler = self.on_event
     self.HOTKEY = {'Lwin', 'Z'}
     self.LANGUAGE = "tr-TR"
     self.recognizer = speech_recognition.Recognizer()
     self.lock = False
     self.list_devices()
Exemple #4
0
    def setUp(self):
        """Set some data and ensure the application is in the state we want"""
        self.hook = Hook()

        # Save pointers to original system calls before mocking
        self.CallNextHookEx = windll.user32.CallNextHookEx
        self.PeekMessageW = windll.user32.PeekMessageW
        self.TranslateMessage = windll.user32.TranslateMessage
        self.DispatchMessageW = windll.user32.DispatchMessageW
        self.atexit_register = atexit.register
        self.sys_exit = sys.exit
        self.fake_kbhook_id = 22
        self.fake_mousehook_id = 33
Exemple #5
0
    def setUp(self):
        """Set some data and ensure the application is in the state we want"""
        self.logger = pywinauto.actionlogger.ActionLogger()
        self.hook = Hook()
        self.hook.handler = self._on_hook_event
        self.wait_time = 0.4
        self.short_wait_time = self.wait_time / 4.0
        self.timer = None
        self.keybd_events = []
        self.mouse_events = []
        self.app = None

        # prevent capturing keyboard keys when launching a test manually
        time.sleep(self.short_wait_time)
Exemple #6
0
    def listen():
        # set up hook
        hook = Hook()
        hook.handler = on_event
        hook.hook(keyboard=True, mouse=True)

        hook.listen()
    def setUp(self):
        """Set some data and ensure the application is in the state we want"""
        self.hook = Hook()

        # Save pointers to original system calls before mocking
        self.CallNextHookEx = windll.user32.CallNextHookEx
        self.PeekMessageW = windll.user32.PeekMessageW
        self.TranslateMessage = windll.user32.TranslateMessage
        self.DispatchMessageW = windll.user32.DispatchMessageW
        self.atexit_register = atexit.register
        self.sys_exit = sys.exit
        self.fake_kbhook_id = 22
        self.fake_mousehook_id = 33
    def setUp(self):
        """Set some data and ensure the application is in the state we want"""
        self.logger = pywinauto.actionlogger.ActionLogger()
        self.hook = Hook()
        self.hook.handler = self._on_hook_event
        self.wait_time = 0.4
        self.short_wait_time = self.wait_time / 4.0
        self.timer = None
        self.keybd_events = []
        self.mouse_events = []
        self.app = None

        # prevent capturing keyboard keys when launching a test manually
        time.sleep(self.short_wait_time)
Exemple #9
0
class Win32HooksTests(unittest.TestCase):
    """Unit tests for the Win32Hook class"""
    def setUp(self):
        """Set some data and ensure the application is in the state we want"""
        self.logger = pywinauto.actionlogger.ActionLogger()
        self.hook = Hook()
        self.hook.handler = self._on_hook_event
        self.wait_time = 0.4
        self.short_wait_time = self.wait_time / 4.0
        self.timer = None
        self.keybd_events = []
        self.mouse_events = []
        self.app = None

        # prevent capturing keyboard keys when launching a test manually
        time.sleep(self.short_wait_time)

    def tearDown(self):
        """Close all hooks after tests"""
        self.keybd_events = []
        self.mouse_events = []
        if self.timer:
            self.timer.cancel()
        self.hook.stop()
        if self.app:
            self.app.kill()

    def _get_safe_point_to_click(self):
        """Run notepad.exe to have a safe area for mouse clicks"""

        mfc_samples_folder = os.path.join(os.path.dirname(__file__),
                                          r"..\..\apps\MFC_samples")
        if is_x64_Python():
            mfc_samples_folder = os.path.join(mfc_samples_folder, 'x64')
        sample_exe = os.path.join(mfc_samples_folder, "CmnCtrl1.exe")
        self.app = Application()
        self.app.start(sample_exe)
        self.app.CommonControlsSample.wait("ready")
        return self.app.CommonControlsSample.rectangle().mid_point()

    def _sleep_and_unhook(self):
        """A helper to remove all hooks after a pause"""
        time.sleep(self.short_wait_time)
        self.hook.stop()

    def trace(self, msg, *args):
        """Log the specified message"""
        self.logger.log(msg.format(*args))

    def _on_hook_event(self, args):
        """Callback for keyboard events"""
        if isinstance(args, KeyboardEvent):
            self.trace(
                "Win32HooksTests::_on_hook_event got KeyboardEvent: key={0} type={1}",
                args.current_key, args.event_type)
            self.keybd_events.append(args)
        elif isinstance(args, MouseEvent):
            self.trace(
                "Win32HooksTests::_on_hook_event got MouseEvent: key={0} type={1}",
                args.current_key, args.event_type)
            self.mouse_events.append(args)

    def _type_keys_and_unhook(self, key_strokes):
        """A timer callback to type key strokes and unhook"""
        send_keys(key_strokes)

        # Give a time to process the keys by the hook
        self._sleep_and_unhook()

    def test_keyboard_hook_unicode_sequence(self):
        """Test capturing a sequence of unicode keystrokes by a keyboard hook"""
        keys = u'uk'
        self.timer = Timer(self.wait_time, self._type_keys_and_unhook, [keys])
        self.timer.start()
        self.hook.hook(keyboard=True, mouse=False)
        # Continue here only when the hook will be removed by the timer
        _delete_keys_from_terminal(keys)
        self.assertEqual(len(self.keybd_events), 4)
        self.assertEqual(self.keybd_events[0].current_key, u'u')
        self.assertEqual(self.keybd_events[0].event_type, 'key down')
        self.assertEqual(len(self.keybd_events[0].pressed_key), 0)
        self.assertEqual(self.keybd_events[1].current_key, u'u')
        self.assertEqual(self.keybd_events[1].event_type, 'key up')
        self.assertEqual(len(self.keybd_events[1].pressed_key), 0)
        self.assertEqual(self.keybd_events[2].current_key, u'k')
        self.assertEqual(self.keybd_events[2].event_type, 'key down')
        self.assertEqual(len(self.keybd_events[2].pressed_key), 0)
        self.assertEqual(self.keybd_events[3].current_key, u'k')
        self.assertEqual(self.keybd_events[3].event_type, 'key up')
        self.assertEqual(len(self.keybd_events[3].pressed_key), 0)

    def test_keyboard_hook_parallel_pressed_keys(self):
        """Test capturing parallel pressed keys by a keyboard hook"""
        keys = u'+a'
        self.timer = Timer(self.wait_time, self._type_keys_and_unhook, [keys])
        self.timer.start()
        self.hook.hook(keyboard=True, mouse=False)
        # Continue here only when the hook will be removed by the timer
        _delete_keys_from_terminal(keys)
        self.assertEqual(len(self.keybd_events), 4)
        self.assertEqual(self.keybd_events[0].current_key, u'Lshift')
        self.assertEqual(self.keybd_events[0].event_type, 'key down')
        self.assertEqual(len(self.keybd_events[0].pressed_key), 0)
        self.assertEqual(self.keybd_events[1].current_key, u'A')
        self.assertEqual(self.keybd_events[1].event_type, 'key down')
        self.assertEqual(len(self.keybd_events[1].pressed_key), 0)
        self.assertEqual(self.keybd_events[2].current_key, u'A')
        self.assertEqual(self.keybd_events[2].event_type, 'key up')
        self.assertEqual(len(self.keybd_events[2].pressed_key), 0)
        self.assertEqual(self.keybd_events[3].current_key, u'Lshift')
        self.assertEqual(self.keybd_events[3].event_type, 'key up')
        self.assertEqual(len(self.keybd_events[3].pressed_key), 0)

    def _mouse_click_and_unhook(self, coords):
        """A timer callback to perform a mouse click and unhook"""
        click(coords=coords)

        # Give a time to process the mouse clicks by the hook
        self._sleep_and_unhook()

    def test_mouse_hook(self):
        """Test capturing a sequence of mouse clicks by hook"""

        # Get a safe point to click
        pt = self._get_safe_point_to_click()
        coords = [(pt.x, pt.y)]

        # Set a timer to perform a click and hook the mouse
        self.timer = Timer(self.wait_time, self._mouse_click_and_unhook,
                           coords)
        self.timer.start()
        self.hook.hook(keyboard=False, mouse=True)
        # Continue here only when the hook will be removed by the timer
        self.assertEqual(len(self.mouse_events), 2)
        self.assertEqual(self.mouse_events[0].current_key, u'LButton')
        self.assertEqual(self.mouse_events[0].event_type, 'key down')
        self.assertEqual(self.mouse_events[0].mouse_x, pt.x)
        self.assertEqual(self.mouse_events[0].mouse_y, pt.y)
        self.assertEqual(self.mouse_events[1].current_key, u'LButton')
        self.assertEqual(self.mouse_events[1].event_type, 'key up')
        self.assertEqual(self.mouse_events[1].mouse_x, pt.x)
        self.assertEqual(self.mouse_events[1].mouse_y, pt.y)
Exemple #10
0
class Win32HooksWithMocksTests(unittest.TestCase):
    """Unit tests for the Win32Hook class with mocks for low level dependencies"""
    def setUp(self):
        """Set some data and ensure the application is in the state we want"""
        self.hook = Hook()

        # Save pointers to original system calls before mocking
        self.CallNextHookEx = windll.user32.CallNextHookEx
        self.PeekMessageW = windll.user32.PeekMessageW
        self.TranslateMessage = windll.user32.TranslateMessage
        self.DispatchMessageW = windll.user32.DispatchMessageW
        self.atexit_register = atexit.register
        self.sys_exit = sys.exit
        self.fake_kbhook_id = 22
        self.fake_mousehook_id = 33

    def tearDown(self):
        """Cleanups after finishing a test"""
        self.hook.stop()

        # Restore the pointers to original system calls after mocking
        windll.user32.CallNextHookEx = self.CallNextHookEx
        windll.user32.PeekMessageW = self.PeekMessageW
        windll.user32.TranslateMessage = self.TranslateMessage
        windll.user32.DispatchMessageW = self.DispatchMessageW
        atexit.register = self.atexit_register
        sys.exit = self.sys_exit

    def test_none_hook_handler(self):
        """Test running a hook without a handler

        The next hook in chain still should be called
        Simulate an odd situation when we got a hook ID (a hook is inserted)
        but a handler for the hook processing wasn't supplied by a user
        """
        self.hook.keyboard_id = self.fake_kbhook_id
        self.hook.mouse_id = self.fake_mousehook_id
        self.hook.handler = None

        # replace the system API with a mock object
        windll.user32.CallNextHookEx = mock.Mock(return_value=0)
        # prepare arguments for _keyboard_ll_hdl call
        kbd = win32structures.KBDLLHOOKSTRUCT(0, 0, 0, 0, 0)
        res = self.hook._keyboard_ll_hdl(-1, 3, id(kbd))
        windll.user32.CallNextHookEx.assert_called_with(
            self.fake_kbhook_id, -1, 3, id(kbd))
        self.assertEqual(res, 0)

        # Setup a fresh mock object and arguments for _mouse_ll_hdl call
        windll.user32.CallNextHookEx = mock.Mock(return_value=0)
        mouse = win32structures.MSLLHOOKSTRUCT((11, 12), 0, 0, 0, 0)
        res = self.hook._mouse_ll_hdl(-1, 3, id(mouse))
        self.assertEqual(res, 0)
        windll.user32.CallNextHookEx.assert_called_with(
            self.fake_mousehook_id, -1, 3, id(mouse))

    def test_keyboard_hook_exception(self):
        """Test handling an exception in a keyboard hook"""
        self.hook.handler = _on_hook_event_with_exception
        windll.user32.CallNextHookEx = mock.Mock(return_value=0)
        kbd = win32structures.KBDLLHOOKSTRUCT(0, 0, 0, 0, 0)
        self.hook.keyboard_id = self.fake_kbhook_id

        # Verify CallNextHookEx is called even if there is an exception is raised
        self.assertRaises(ValueError, self.hook._keyboard_ll_hdl, -1, 3,
                          id(kbd))
        windll.user32.CallNextHookEx.assert_called()
        windll.user32.CallNextHookEx.assert_called_with(
            self.fake_kbhook_id, -1, 3, id(kbd))
        self.assertRaises(ValueError, self.hook._keyboard_ll_hdl, 0, 3,
                          id(kbd))
        windll.user32.CallNextHookEx.assert_called()
        windll.user32.CallNextHookEx.assert_called_with(
            self.fake_kbhook_id, 0, 3, id(kbd))

    def test_mouse_hook_exception(self):
        """Test handling an exception in a mouse hook"""
        self.hook.handler = _on_hook_event_with_exception
        windll.user32.CallNextHookEx = mock.Mock(return_value=0)
        mouse = win32structures.MSLLHOOKSTRUCT((11, 12), 0, 0, 0, 0)
        self.hook.mouse_id = self.fake_mousehook_id

        # Verify CallNextHookEx is called even if there is an exception is raised
        self.assertRaises(ValueError, self.hook._mouse_ll_hdl, -1, 3,
                          id(mouse))
        windll.user32.CallNextHookEx.assert_called()
        windll.user32.CallNextHookEx.assert_called_with(
            self.fake_mousehook_id, -1, 3, id(mouse))
        self.assertRaises(ValueError, self.hook._mouse_ll_hdl, 0, 3, id(mouse))
        windll.user32.CallNextHookEx.assert_called()
        windll.user32.CallNextHookEx.assert_called_with(
            self.fake_mousehook_id, 0, 3, id(mouse))

    @mock.patch.object(Hook, '_process_win_msgs')
    @mock.patch.object(Hook, 'is_hooked')
    def test_listen_loop(self, mock_is_hooked, mock_process_msgs):
        """Test running the main events loop"""
        atexit.register = mock.Mock(return_value=0)
        mock_is_hooked.side_effect = [1, 0]  # exit at a second loop
        mock_process_msgs.return_value = 0

        # mock hook IDs
        self.hook.keyboard_id = self.fake_kbhook_id
        self.hook.mouse_id = self.fake_mousehook_id

        # run the events loop
        self.hook.listen()

        # verify atexit.register calls
        atexit.register.assert_called()
        self.assertEqual(len(atexit.register.mock_calls), 2)
        name, args, kwargs = atexit.register.mock_calls[0]
        self.assertEqual(args[1], self.fake_kbhook_id)
        name, args, kwargs = atexit.register.mock_calls[1]
        self.assertEqual(args[1], self.fake_mousehook_id)

        # verify is_hooked method calls
        mock_is_hooked.assert_called()
        self.assertEqual(len(mock_is_hooked.mock_calls), 2)

        # verify _process_win_msgs method has been called
        mock_process_msgs.assert_called()
        self.assertEqual(len(mock_process_msgs.mock_calls), 1)

    @mock.patch.object(Hook, 'stop')
    def test_process_win_msg(self, mock_stop):
        """Test Hook._process_win_msgs"""
        # Mock external API
        windll.user32.PeekMessageW = mock.Mock(side_effect=[1, 0])
        windll.user32.TranslateMessage = mock.Mock()
        windll.user32.DispatchMessageW = mock.Mock()

        # Test processing the normal messages
        self.hook._process_win_msgs()
        windll.user32.PeekMessageW.assert_called()
        windll.user32.TranslateMessage.assert_called()
        windll.user32.DispatchMessageW.assert_called()

        # Test processing WM_QUIT
        def side_effect(*args):
            """Emulate reception of WM_QUIT"""
            args[0].contents.message = win32con.WM_QUIT
            return 1

        windll.user32.PeekMessageW = mock.Mock(side_effect=side_effect)
        self.assertRaises(SystemExit, self.hook._process_win_msgs)
        mock_stop.assert_called_once()

    def test_is_hooked(self):
        """Verify Hook.is_hooked method"""
        self.assertEqual(self.hook.is_hooked(), False)
        self.hook.mouse_is_hook = True
        self.assertEqual(self.hook.is_hooked(), True)
        self.hook.mouse_is_hook = False
        self.assertEqual(self.hook.is_hooked(), False)
        self.hook.keyboard_is_hook = True
        self.assertEqual(self.hook.is_hooked(), True)
        self.hook.keyboard_is_hook = False
        self.assertEqual(self.hook.is_hooked(), False)
        self.hook.hook(mouse=False, keyboard=False)
        self.assertEqual(self.hook.is_hooked(), False)
Exemple #11
0
    """Callback for keyboard and mouse events"""
    if isinstance(args, KeyboardEvent):
        if args.current_key == 'A' and args.event_type == 'key down' and 'Lcontrol' in args.pressed_key:
            print("Ctrl + A was pressed")

        if args.current_key == 'K' and args.event_type == 'key down':
            print("K was pressed")

        if args.current_key == 'M' and args.event_type == 'key down' and 'U' in args.pressed_key:
            hk.unhook_mouse()
            print("Unhook mouse")

        if args.current_key == 'K' and args.event_type == 'key down' and 'U' in args.pressed_key:
            hk.unhook_keyboard()
            print("Unhook keyboard")

    if isinstance(args, MouseEvent):
        if args.current_key == 'RButton' and args.event_type == 'key down':
            print("Right button pressed")

        if args.current_key == 'WheelButton' and args.event_type == 'key down':
            print("Wheel button pressed")


hk = Hook()
hk.handler = on_event
main_thread_id = win32api.GetCurrentThreadId()
t = Timer(5.0, on_timer)  # Quit after 5 seconds
t.start()
hk.hook(keyboard=True, mouse=True)
Exemple #12
0
 def run(self):
     hk = Hook()
     hk.handler = self.handleEvents
     hk.hook(keyboard=True, mouse=True)
Exemple #13
0
# def handleEvents(args):
#     global down
#     if isinstance(args, MouseEvent):
#         if args.current_key == 'LButton' and args.event_type == 'key up':
#             keyboard.press_and_release('ctrl+c')

#     if isinstance(args, KeyboardEvent):
#         if 'control' in args.current_key and args.event_type == 'key down':
#             down = True
#         if 'control' in args.current_key and args.event_type == 'key up':
#             down = False

#         if args.current_key == 'C' and down:
#             print(1)

# def onClipboardChanged()
#     data = clipboard.mimeData()
#     if data.hasText():
#         print(data.text())

# app = QApplication([])
# clipboard = app.clipboard()
# clipboard.dataChanged.connect(onClipboardChanged)

if __name__ == '__main__':
    print('no config.')
    hk = Hook()
    hk.handler = handleEvents
    hk.hook(keyboard=True, mouse=True)
Exemple #14
0
def __main__() -> None:
    hook = Hook()
    hook.handler = on_event
    hook.hook(keyboard=True, mouse=True)
    hook.listen()
class Win32HooksTests(unittest.TestCase):

    """Unit tests for the Win32Hook class"""

    def setUp(self):
        """Set some data and ensure the application is in the state we want"""
        self.logger = pywinauto.actionlogger.ActionLogger()
        self.hook = Hook()
        self.hook.handler = self._on_hook_event
        self.wait_time = 0.4
        self.short_wait_time = self.wait_time / 4.0
        self.timer = None
        self.keybd_events = []
        self.mouse_events = []
        self.app = None

        # prevent capturing keyboard keys when launching a test manually
        time.sleep(self.short_wait_time)

    def tearDown(self):
        """Close all hooks after tests"""
        self.keybd_events = []
        self.mouse_events = []
        if self.timer:
            self.timer.cancel()
        self.hook.stop()
        if self.app:
            self.app.kill()

    def _get_safe_point_to_click(self):
        """Run notepad.exe to have a safe area for mouse clicks"""

        mfc_samples_folder = os.path.join(
            os.path.dirname(__file__), r"..\..\apps\MFC_samples")
        if is_x64_Python():
            mfc_samples_folder = os.path.join(mfc_samples_folder, 'x64')
        sample_exe = os.path.join(mfc_samples_folder, "CmnCtrl1.exe")
        self.app = Application()
        self.app.start(sample_exe)
        self.app.CommonControlsSample.wait("ready")
        return self.app.CommonControlsSample.rectangle().mid_point()

    def _sleep_and_unhook(self):
        """A helper to remove all hooks after a pause"""
        time.sleep(self.short_wait_time)
        self.hook.stop()

    def trace(self, msg, *args):
        """Log the specified message"""
        self.logger.log(msg.format(*args))

    def _on_hook_event(self, args):
        """Callback for keyboard events"""
        if isinstance(args, KeyboardEvent):
            self.trace(
                "Win32HooksTests::_on_hook_event got KeyboardEvent: key={0} type={1}",
                args.current_key,
                args.event_type)
            self.keybd_events.append(args)
        elif isinstance(args, MouseEvent):
            self.trace(
                "Win32HooksTests::_on_hook_event got MouseEvent: key={0} type={1}",
                args.current_key,
                args.event_type)
            self.mouse_events.append(args)

    def _type_keys_and_unhook(self, key_strokes):
        """A timer callback to type key strokes and unhook"""
        send_keys(key_strokes)

        # Give a time to process the keys by the hook
        self._sleep_and_unhook()

    def test_keyboard_hook_unicode_sequence(self):
        """Test capturing a sequence of unicode keystrokes by a keyboard hook"""
        keys = u'uk'
        self.timer = Timer(self.wait_time, self._type_keys_and_unhook, [keys])
        self.timer.start()
        self.hook.hook(keyboard=True, mouse=False)
        # Continue here only when the hook will be removed by the timer
        _delete_keys_from_terminal(keys)
        self.assertEqual(len(self.keybd_events), 4)
        self.assertEqual(self.keybd_events[0].current_key, u'u')
        self.assertEqual(self.keybd_events[0].event_type, 'key down')
        self.assertEqual(len(self.keybd_events[0].pressed_key), 0)
        self.assertEqual(self.keybd_events[1].current_key, u'u')
        self.assertEqual(self.keybd_events[1].event_type, 'key up')
        self.assertEqual(len(self.keybd_events[1].pressed_key), 0)
        self.assertEqual(self.keybd_events[2].current_key, u'k')
        self.assertEqual(self.keybd_events[2].event_type, 'key down')
        self.assertEqual(len(self.keybd_events[2].pressed_key), 0)
        self.assertEqual(self.keybd_events[3].current_key, u'k')
        self.assertEqual(self.keybd_events[3].event_type, 'key up')
        self.assertEqual(len(self.keybd_events[3].pressed_key), 0)

    def test_keyboard_hook_parallel_pressed_keys(self):
        """Test capturing parallel pressed keys by a keyboard hook"""
        keys = u'+a'
        self.timer = Timer(self.wait_time, self._type_keys_and_unhook, [keys])
        self.timer.start()
        self.hook.hook(keyboard=True, mouse=False)
        # Continue here only when the hook will be removed by the timer
        _delete_keys_from_terminal(keys)
        self.assertEqual(len(self.keybd_events), 4)
        self.assertEqual(self.keybd_events[0].current_key, u'Lshift')
        self.assertEqual(self.keybd_events[0].event_type, 'key down')
        self.assertEqual(len(self.keybd_events[0].pressed_key), 0)
        self.assertEqual(self.keybd_events[1].current_key, u'A')
        self.assertEqual(self.keybd_events[1].event_type, 'key down')
        self.assertEqual(len(self.keybd_events[1].pressed_key), 0)
        self.assertEqual(self.keybd_events[2].current_key, u'A')
        self.assertEqual(self.keybd_events[2].event_type, 'key up')
        self.assertEqual(len(self.keybd_events[2].pressed_key), 0)
        self.assertEqual(self.keybd_events[3].current_key, u'Lshift')
        self.assertEqual(self.keybd_events[3].event_type, 'key up')
        self.assertEqual(len(self.keybd_events[3].pressed_key), 0)

    def _mouse_click_and_unhook(self, coords):
        """A timer callback to perform a mouse click and unhook"""
        click(coords=coords)

        # Give a time to process the mouse clicks by the hook
        self._sleep_and_unhook()

    def test_mouse_hook(self):
        """Test capturing a sequence of mouse clicks by hook"""

        # Get a safe point to click
        pt = self._get_safe_point_to_click()
        coords = [(pt.x, pt.y)]

        # Set a timer to perform a click and hook the mouse
        self.timer = Timer(self.wait_time, self._mouse_click_and_unhook, coords)
        self.timer.start()
        self.hook.hook(keyboard=False, mouse=True)
        # Continue here only when the hook will be removed by the timer
        self.assertEqual(len(self.mouse_events), 2)
        self.assertEqual(self.mouse_events[0].current_key, u'LButton')
        self.assertEqual(self.mouse_events[0].event_type, 'key down')
        self.assertEqual(self.mouse_events[0].mouse_x, pt.x)
        self.assertEqual(self.mouse_events[0].mouse_y, pt.y)
        self.assertEqual(self.mouse_events[1].current_key, u'LButton')
        self.assertEqual(self.mouse_events[1].event_type, 'key up')
        self.assertEqual(self.mouse_events[1].mouse_x, pt.x)
        self.assertEqual(self.mouse_events[1].mouse_y, pt.y)
class Win32HooksWithMocksTests(unittest.TestCase):

    """Unit tests for the Win32Hook class with mocks for low level dependencies"""

    def setUp(self):
        """Set some data and ensure the application is in the state we want"""
        self.hook = Hook()

        # Save pointers to original system calls before mocking
        self.CallNextHookEx = windll.user32.CallNextHookEx
        self.PeekMessageW = windll.user32.PeekMessageW
        self.TranslateMessage = windll.user32.TranslateMessage
        self.DispatchMessageW = windll.user32.DispatchMessageW
        self.atexit_register = atexit.register
        self.sys_exit = sys.exit
        self.fake_kbhook_id = 22
        self.fake_mousehook_id = 33

    def tearDown(self):
        """Cleanups after finishing a test"""
        self.hook.stop()

        # Restore the pointers to original system calls after mocking
        windll.user32.CallNextHookEx = self.CallNextHookEx
        windll.user32.PeekMessageW = self.PeekMessageW
        windll.user32.TranslateMessage = self.TranslateMessage
        windll.user32.DispatchMessageW = self.DispatchMessageW
        atexit.register = self.atexit_register
        sys.exit = self.sys_exit

    def test_none_hook_handler(self):
        """Test running a hook without a handler

        The next hook in chain still should be called
        Simulate an odd situation when we got a hook ID (a hook is inserted)
        but a handler for the hook processing wasn't supplied by a user
        """
        self.hook.keyboard_id = self.fake_kbhook_id
        self.hook.mouse_id = self.fake_mousehook_id
        self.hook.handler = None

        # replace the system API with a mock object
        windll.user32.CallNextHookEx = mock.Mock(return_value=0)
        # prepare arguments for _keyboard_ll_hdl call
        kbd = win32structures.KBDLLHOOKSTRUCT(0, 0, 0, 0, 0)
        res = self.hook._keyboard_ll_hdl(-1, 3, id(kbd))
        windll.user32.CallNextHookEx.assert_called_with(self.fake_kbhook_id, -1, 3, id(kbd))
        self.assertEqual(res, 0)

        # Setup a fresh mock object and arguments for _mouse_ll_hdl call
        windll.user32.CallNextHookEx = mock.Mock(return_value=0)
        mouse = win32structures.MSLLHOOKSTRUCT((11, 12), 0, 0, 0, 0)
        res = self.hook._mouse_ll_hdl(-1, 3, id(mouse))
        self.assertEqual(res, 0)
        windll.user32.CallNextHookEx.assert_called_with(self.fake_mousehook_id, -1, 3, id(mouse))

    def test_keyboard_hook_exception(self):
        """Test handling an exception in a keyboard hook"""
        self.hook.handler = _on_hook_event_with_exception
        windll.user32.CallNextHookEx = mock.Mock(return_value=0)
        kbd = win32structures.KBDLLHOOKSTRUCT(0, 0, 0, 0, 0)
        self.hook.keyboard_id = self.fake_kbhook_id

        # Verify CallNextHookEx is called even if there is an exception is raised
        self.assertRaises(ValueError, self.hook._keyboard_ll_hdl, -1, 3, id(kbd))
        windll.user32.CallNextHookEx.assert_called()
        windll.user32.CallNextHookEx.assert_called_with(self.fake_kbhook_id, -1, 3, id(kbd))
        self.assertRaises(ValueError, self.hook._keyboard_ll_hdl, 0, 3, id(kbd))
        windll.user32.CallNextHookEx.assert_called()
        windll.user32.CallNextHookEx.assert_called_with(self.fake_kbhook_id, 0, 3, id(kbd))

    def test_mouse_hook_exception(self):
        """Test handling an exception in a mouse hook"""
        self.hook.handler = _on_hook_event_with_exception
        windll.user32.CallNextHookEx = mock.Mock(return_value=0)
        mouse = win32structures.MSLLHOOKSTRUCT((11, 12), 0, 0, 0, 0)
        self.hook.mouse_id = self.fake_mousehook_id

        # Verify CallNextHookEx is called even if there is an exception is raised
        self.assertRaises(ValueError, self.hook._mouse_ll_hdl, -1, 3, id(mouse))
        windll.user32.CallNextHookEx.assert_called()
        windll.user32.CallNextHookEx.assert_called_with(self.fake_mousehook_id, -1, 3, id(mouse))
        self.assertRaises(ValueError, self.hook._mouse_ll_hdl, 0, 3, id(mouse))
        windll.user32.CallNextHookEx.assert_called()
        windll.user32.CallNextHookEx.assert_called_with(self.fake_mousehook_id, 0, 3, id(mouse))

    @mock.patch.object(Hook, '_process_win_msgs')
    @mock.patch.object(Hook, 'is_hooked')
    def test_listen_loop(self, mock_is_hooked, mock_process_msgs):
        """Test running the main events loop"""
        atexit.register = mock.Mock(return_value=0)
        mock_is_hooked.side_effect = [1, 0]  # exit at a second loop
        mock_process_msgs.return_value = 0

        # mock hook IDs
        self.hook.keyboard_id = self.fake_kbhook_id
        self.hook.mouse_id = self.fake_mousehook_id

        # run the events loop
        self.hook.listen()

        # verify atexit.register calls
        atexit.register.assert_called()
        self.assertEqual(len(atexit.register.mock_calls), 2)
        name, args, kwargs = atexit.register.mock_calls[0]
        self.assertEqual(args[1], self.fake_kbhook_id)
        name, args, kwargs = atexit.register.mock_calls[1]
        self.assertEqual(args[1], self.fake_mousehook_id)

        # verify is_hooked method calls
        mock_is_hooked.assert_called()
        self.assertEqual(len(mock_is_hooked.mock_calls), 2)

        # verify _process_win_msgs method has been called
        mock_process_msgs.assert_called()
        self.assertEqual(len(mock_process_msgs.mock_calls), 1)

    @mock.patch.object(Hook, 'stop')
    def test_process_win_msg(self, mock_stop):
        """Test Hook._process_win_msgs"""
        # Mock external API
        windll.user32.PeekMessageW = mock.Mock(side_effect=[1, 0])
        windll.user32.TranslateMessage = mock.Mock()
        windll.user32.DispatchMessageW = mock.Mock()

        # Test processing the normal messages
        self.hook._process_win_msgs()
        windll.user32.PeekMessageW.assert_called()
        windll.user32.TranslateMessage.assert_called()
        windll.user32.DispatchMessageW.assert_called()

        # Test processing WM_QUIT
        def side_effect(*args):
            """Emulate reception of WM_QUIT"""
            args[0].contents.message = win32con.WM_QUIT
            return 1
        windll.user32.PeekMessageW = mock.Mock(side_effect=side_effect)
        self.assertRaises(SystemExit, self.hook._process_win_msgs)
        mock_stop.assert_called_once()

    def test_is_hooked(self):
        """Verify Hook.is_hooked method"""
        self.assertEqual(self.hook.is_hooked(), False)
        self.hook.mouse_is_hook = True
        self.assertEqual(self.hook.is_hooked(), True)
        self.hook.mouse_is_hook = False
        self.assertEqual(self.hook.is_hooked(), False)
        self.hook.keyboard_is_hook = True
        self.assertEqual(self.hook.is_hooked(), True)
        self.hook.keyboard_is_hook = False
        self.assertEqual(self.hook.is_hooked(), False)
        self.hook.hook(mouse=False, keyboard=False)
        self.assertEqual(self.hook.is_hooked(), False)
Exemple #17
0
def on_event(args):
    """Callback for keyboard and mouse events"""
    if isinstance(args, KeyboardEvent):
        if args.current_key == 'A' and args.event_type == 'key down' and 'Lcontrol' in args.pressed_key:
            print("Ctrl + A was pressed");

        if args.current_key == 'K' and args.event_type == 'key down':
            print("K was pressed");

        if args.current_key == 'M' and args.event_type == 'key down' and 'U' in args.pressed_key:
            hk.unhook_mouse()
            print("Unhook mouse")

        if args.current_key == 'K' and args.event_type == 'key down' and 'U' in args.pressed_key:
            hk.unhook_keyboard()
            print("Unhook keyboard")

    if isinstance(args, MouseEvent):
        if args.current_key == 'RButton' and args.event_type == 'key down':
            print ("Right button pressed")

        if args.current_key == 'WheelButton' and args.event_type == 'key down':
            print("Wheel button pressed")

hk = Hook()
hk.handler = on_event
main_thread_id = win32api.GetCurrentThreadId()
t = Timer(5.0, on_timer)  # Quit after 5 seconds
t.start()
hk.hook(keyboard=True, mouse=True)