IS_LINUX = sys.platform.startswith('linux') EMASK_V_ALL = \
    EMASK_V_EFUNC \
    | EMASK_V_HOTKEY \
    | EMASK_V_HOTSEQ EMASK_V_EFUNC = 1 EMASK_V_HOTKEY = 2 EMASK_V_HOTSEQ = 4 HOTKEY_INFO_K_HOTKEY_FUNC = 'hotkey_func' HOTKEY_INFO_K_HOTKEY_ORIG_SPEC = 'hotkey_orig_spec' HOTKEY_INFO_K_HOTKEY_PATTERN = 'hotkey_pattern' HOTKEY_INFO_K_HOTKEY_TUPLES = 'hotkey_tuples' HOTKEY_INFO_K_HOTKEY_TYPE = 'hotkey_type' HOTKEY_INFO_K_NEED_HOTKEY_INFO_LIST = 'need_hotkey_info_list' HOTKEY_TYPE_V_DN = 'dn' HOTKEY_TYPE_V_KS = 'ks' HOTKEY_TYPE_V_UP = 'up' HOTKEY_TYPES = {
    HOTKEY_TYPE_V_DN,
    HOTKEY_TYPE_V_UP,
    HOTKEY_TYPE_V_KS,
} def tag_call_in_main_thread_exists(func):
    """
    Test whether given function has `call in main thread` tag.
    """
    # Return tag attribute's value
    return getattr(func, _TAG_CALL_IN_MAIN_THREAD, False) def tag_call_with_info_exists(func):
    """
    Test whether given function has `call with info` tag.
    """
    # Return tag attribute's value
    return getattr(func, _TAG_CALL_WITH_INFO, False) def add_task(self, func):
    """
    Add task function to be run in the task manager's thread pool.

    :param func: Task function.

    :return: None.
    """
    # Create wrapper function
    def func_wrapper():
        try:
            # Call given function
            func()

        # If have error
        except BaseException:
            # Get traceback message
            tb_msg = format_exc()

            # Get error message
            msg = (
                '# Error calling function in task thread:\n'
                '---\n{0}---\n'
            ).format(tb_msg)

            # Print error message
            sys.stderr.write(msg)

    # Run the wrapper function in the thread pool
    self._thread_pool.apply_async(func_wrapper) EVK_MOUSE_WHEEL_DOWN = 11002 EVK_MOUSE_WHEEL_UP = 11001 MAP_MOUSE_UP_VK_TO_DN_VK = {
    VK_MOUSE_LEFT_UP: VK_MOUSE_LEFT_DOWN,
    VK_MOUSE_RIGHT_UP: VK_MOUSE_RIGHT_DOWN,
    VK_MOUSE_MIDDLE_UP: VK_MOUSE_MIDDLE_DOWN,
} MAP_X11_NAME_TO_WIN_VK = {
    'space': VK_SPACE,
    'Escape': VK_ESCAPE,
    'BackSpace': VK_BACK,
    'Return': VK_RETURN,
    'Tab': VK_TAB,
    'Caps_Lock': VK_CAPITAL,
    'Shift_L': VK_LSHIFT,
    'Shift_R': VK_RSHIFT,
    'Control_L': VK_LCONTROL,
    'Control_R': VK_RCONTROL,
    'Super_L': VK_LWIN,
    'Super_R': VK_RWIN,
    'Alt_L': VK_LMENU,
    'Alt_R': VK_RMENU,
    'Menu': VK_APPS,
    'F1': VK_F1,
    'F2': VK_F2,
    'F3': VK_F3,
    'F4': VK_F4,
    'F5': VK_F5,
    'F6': VK_F6,
    'F7': VK_F7,
    'F8': VK_F8,
    'F9': VK_F9,
    'F10': VK_F10,
    'F11': VK_F11,
    'F12': VK_F12,
    'F13': VK_F13,
    'F14': VK_F14,
    'F15': VK_F15,
    'F16': VK_F16,
    'F17': VK_F17,
    'F18': VK_F18,
    'F19': VK_F19,
    'F20': VK_F20,
    'F21': VK_F21,
    'F22': VK_F22,
    'F23': VK_F23,
    'F24': VK_F24,
    '0': VK_KEY_0,
    '1': VK_KEY_1,
    '2': VK_KEY_2,
    '3': VK_KEY_3,
    '4': VK_KEY_4,
    '5': VK_KEY_5,
    '6': VK_KEY_6,
    '7': VK_KEY_7,
    '8': VK_KEY_8,
    '9': VK_KEY_9,
    'a': VK_KEY_A,
    'b': VK_KEY_B,
    'c': VK_KEY_C,
    'd': VK_KEY_D,
    'e': VK_KEY_E,
    'f': VK_KEY_F,
    'g': VK_KEY_G,
    'h': VK_KEY_H,
    'i': VK_KEY_I,
    'j': VK_KEY_J,
    'k': VK_KEY_K,
    'l': VK_KEY_L,
    'm': VK_KEY_M,
    'n': VK_KEY_N,
    'o': VK_KEY_O,
    'p': VK_KEY_P,
    'q': VK_KEY_Q,
    'r': VK_KEY_R,
    's': VK_KEY_S,
    't': VK_KEY_T,
    'u': VK_KEY_U,
    'v': VK_KEY_V,
    'w': VK_KEY_W,
    'x': VK_KEY_X,
    'y': VK_KEY_Y,
    'z': VK_KEY_Z,
    'A': VK_KEY_A,
    'B': VK_KEY_B,
    'C': VK_KEY_C,
    'D': VK_KEY_D,
    'E': VK_KEY_E,
    'F': VK_KEY_F,
    'G': VK_KEY_G,
    'H': VK_KEY_H,
    'I': VK_KEY_I,
    'J': VK_KEY_J,
    'K': VK_KEY_K,
    'L': VK_KEY_L,
    'M': VK_KEY_M,
    'N': VK_KEY_N,
    'O': VK_KEY_O,
    'P': VK_KEY_P,
    'Q': VK_KEY_Q,
    'R': VK_KEY_R,
    'S': VK_KEY_S,
    'T': VK_KEY_T,
    'U': VK_KEY_U,
    'V': VK_KEY_V,
    'W': VK_KEY_W,
    'X': VK_KEY_X,
    'Y': VK_KEY_Y,
    'Z': VK_KEY_Z,
    'grave': VK_OEM_3,
    'minus': VK_OEM_MINUS,
    'equal': VK_OEM_PLUS,
    'bracketleft': VK_OEM_4,
    'bracketright': VK_OEM_6,
    'backslash': VK_OEM_5,
    'semicolon': VK_OEM_1,
    'apostrophe': VK_OEM_7,
    'comma': VK_OEM_COMMA,
    'period': VK_OEM_PERIOD,
    'slash': VK_OEM_2,
    'Insert': VK_INSERT,
    'Delete': VK_DELETE,
    'Home': VK_HOME,
    'End': VK_END,
    'Page_Up': VK_PRIOR,
    'Next': VK_NEXT,
    'Up': VK_UP,
    'Left': VK_LEFT,
    'Right': VK_RIGHT,
    'Down': VK_DOWN,
    'Print': VK_SNAPSHOT,
    'Scroll_Lock': VK_SCROLL,
    'Pause': VK_PAUSE,
    'Num_Lock': VK_NUMLOCK,
    'P_Divide': VK_DIVIDE,
    'P_Multiply': VK_MULTIPLY,
    'P_Subtract': VK_SUBTRACT,
    'P_Add': VK_ADD,
    'P_Delete': VK_DECIMAL,
    'P_Enter': VK_RETURN,
    'P_Insert': VK_NUMPAD0,
    'P_End': VK_NUMPAD1,
    'P_Down': VK_NUMPAD2,
    'P_Next': VK_NUMPAD3,
    'P_Left': VK_NUMPAD4,
    'P_Begin': VK_NUMPAD5,
    'P_Right': VK_NUMPAD6,
    'P_Home': VK_NUMPAD7,
    'P_Up': VK_NUMPAD8,
    'P_Page_Up': VK_NUMPAD9,
} VK_MOUSE_WHEEL = 522
from collections import OrderedDict
from collections import deque
from contextlib import contextmanager
from functools import partial
from traceback import format_exc
from .compat import IS_LINUX
from .const import EMASK_V_ALL
from .const import EMASK_V_EFUNC
from .const import EMASK_V_HOTKEY
from .const import EMASK_V_HOTSEQ
from .const import HOTKEY_INFO_K_HOTKEY_FUNC
from .const import HOTKEY_INFO_K_HOTKEY_ORIG_SPEC
from .const import HOTKEY_INFO_K_HOTKEY_PATTERN
from .const import HOTKEY_INFO_K_HOTKEY_TUPLES
from .const import HOTKEY_INFO_K_HOTKEY_TYPE
from .const import HOTKEY_INFO_K_NEED_HOTKEY_INFO_LIST
from .const import HOTKEY_TYPE_V_DN
from .const import HOTKEY_TYPE_V_KS
from .const import HOTKEY_TYPE_V_UP
from .const import HOTKEY_TYPES
from .event_manager import EventManager
from .hotkey_spec_parser import tag_call_in_main_thread_exists
from .hotkey_spec_parser import tag_call_with_info_exists
from .task_manager import add_task
from .virtualkey import EVK_MOUSE_WHEEL_DOWN
from .virtualkey import EVK_MOUSE_WHEEL_UP
from .virtualkey import MAP_MOUSE_UP_VK_TO_DN_VK
from .virtualkey import MAP_X11_NAME_TO_WIN_VK
from .virtualkey import VK_MOUSE_WHEEL
import sys
import time
        :param mouse_wm: Whether is handler for mouse wheel or mouse move \
            events.

        :return: Whether propagate the event.
        """
        # If given event is mouse event
        if 'mouse' in event.MessageName:
            # Get the mouse event's virtual key
            vk = event.Message

            # 4BIVS
            # If the virtual key is mouse wheel
            if vk == VK_MOUSE_WHEEL:
                # If mouse wheel is scrolling up
                if event.Wheel > 0:
                    # Use wheel-up extended virtual key
                    vk = EVK_MOUSE_WHEEL_UP

                # If mouse wheel is scrolling down
                elif event.Wheel < 0:
                    # Use wheel-down extended virtual key
                    vk = EVK_MOUSE_WHEEL_DOWN

                # If mouse wheel is not scrolling up or down
                else:
                    # Raise error
                    assert 0, event.Wheel

        # If given event is not mouse event
        else:
            # If the platform is Linux,
            # it means the event object's `Key` field contains the key name but
            # `KeyID` field not contains virtual key.
            if IS_LINUX:
                # Convert the key name to virtual key
                event.KeyID = MAP_X11_NAME_TO_WIN_VK.get(event.Key, 0)

            # Get the event's virtual key
            vk = event.KeyID

        # Remove the virtual key from the currently down list to avoid adding
        # duplicate below
        self._vk_down_remove(vk)

        # Remove outdated virtual keys from currently down list
        self._vk_down_remove_outdated()

        # Add the virtual key to the currently down list
        self._vk_down_add(vk)

        # Whether propagate the event.
        # None means use the default.
        propagate = None

        # If event function mask is enabled
        if self._emask & EMASK_V_EFUNC:
            # Call all event functions
            propagate = self._efunc_call_all(event, propagate=propagate)

        # Whether hotkey is found
        hotkey_is_found = False

        # If propagation is not stopped,
        # and hotkey function mask is enabled.
        if (propagate is not False) and (self._emask & EMASK_V_HOTKEY):
            # Find and call hotkey function
            hotkey_is_found, propagate = self._hotkey_find_and_call(
                hotkey=self.vk_down_list(),
                hotkey_type=HOTKEY_TYPE_V_DN,
                event=event,
                propagate=propagate,
            )

        # If is not mouse wheel or mouse move event handler,
        # and hotkey is not found,
        # and propagation is not stopped,
        # and key-sequence function mask is enabled.
        if (not mouse_wm) \
                and (not hotkey_is_found) \
                and (propagate is not False) \
                and (self._emask & EMASK_V_HOTSEQ):
            # Find and call key-sequence function
            hotkey_is_found, propagate = self._hotseq_find_and_call(
                vk=vk, event=event, propagate=propagate
            )

        # If is mouse wheel or mouse move event handler
        if mouse_wm:
            # Remove the mouse event's virtual key because it has no
            # corresponding up event
            self._vk_down_remove(vk)

        # Decide whether propagate the event
        propagate = (not hotkey_is_found) or (propagate is True)

        # Return whether propagate the event
        return propagate

    def _key_up_hdlr(self, event):
        """
        Key-up event handler.

        :param event: Event object.

        :return: Whether propagate the event.
        """
        # If given event is mouse event
        if 'mouse' in event.MessageName:
            # Get the mouse event's virtual key
            vk = event.Message

            # Get the up event's corresponding down event's virtual key
            vk_dn = MAP_MOUSE_UP_VK_TO_DN_VK.get(vk, None)

            # Ensure the down event's virtual key is found
            assert vk_dn is not None
        else:
            # If the platform is Linux,
            # it means the event object's `Key` field contains the key name but
            # `KeyID` field not contains virtual key.

            if IS_LINUX: