File size: 5,178 Bytes
cc0dd3c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# Copyright (c) OpenMMLab. All rights reserved.
import logging
from collections import defaultdict
from contextlib import contextmanager
from threading import Event
from typing import Optional

logger = logging.getLogger('Event')


class EventManager():
    """A helper class to manage events.

    :class:`EventManager` provides interfaces to register, set, clear and
    check events by name.
    """

    def __init__(self):
        self._events = defaultdict(Event)

    def register_event(self, event_name: str, is_keyboard: bool = False):
        """Register an event. A event must be registered first before being
        set, cleared or checked.

        Args:
            event_name (str): The indicator of the event. The name should be
                unique in one :class:`EventManager` instance
            is_keyboard (bool): Specify weather it is a keyboard event. If so,
                the ``event_name`` should be the key value, and the indicator
                will be set as ``'_keyboard_{event_name}'``. Otherwise, the
                ``event_name`` will be directly used as the indicator.
                Default: ``False``
        """
        if is_keyboard:
            event_name = self._get_keyboard_event_name(event_name)
        self._events[event_name] = Event()

    def set(self, event_name: str, is_keyboard: bool = False):
        """Set the internal flag of an event to ``True``.

        Args:
            event_name (str): The indicator of the event
            is_keyboard (bool): Specify weather it is a keyboard event. See
                ``register_event()`` for details. Default: False
        """
        if is_keyboard:
            event_name = self._get_keyboard_event_name(event_name)
        self._events[event_name].set()
        logger.info(f'Event {event_name} is set.')

    def wait(self,
             event_name: str = None,
             is_keyboard: bool = False,
             timeout: Optional[float] = None) -> bool:
        """Block until the internal flag of an event is ``True``.

        Args:
            event_name (str): The indicator of the event
            is_keyboard (bool): Specify weather it is a keyboard event. See
                ``register_event()`` for details. Default: False
            timeout (float, optional): The optional maximum blocking time in
                seconds. Default: ``None``

        Returns:
            bool: The internal event flag on exit.
        """
        if is_keyboard:
            event_name = self._get_keyboard_event_name(event_name)
        return self._events[event_name].wait(timeout)

    def is_set(self,
               event_name: str = None,
               is_keyboard: Optional[bool] = False) -> bool:
        """Check weather the internal flag of an event is ``True``.

        Args:
            event_name (str): The indicator of the event
            is_keyboard (bool): Specify weather it is a keyboard event. See
                ``register_event()`` for details. Default: False
        Returns:
            bool: The internal event flag.
        """
        if is_keyboard:
            event_name = self._get_keyboard_event_name(event_name)
        return self._events[event_name].is_set()

    def clear(self,
              event_name: str = None,
              is_keyboard: Optional[bool] = False):
        """Reset the internal flag of en event to False.

        Args:
            event_name (str): The indicator of the event
            is_keyboard (bool): Specify weather it is a keyboard event. See
                ``register_event()`` for details. Default: False
        """
        if is_keyboard:
            event_name = self._get_keyboard_event_name(event_name)
        self._events[event_name].clear()
        logger.info(f'Event {event_name} is cleared.')

    @staticmethod
    def _get_keyboard_event_name(key):
        """Get keyboard event name from the key value."""
        return f'_keyboard_{chr(key) if isinstance(key,int) else key}'

    @contextmanager
    def wait_and_handle(self,
                        event_name: str = None,
                        is_keyboard: Optional[bool] = False):
        """Context manager that blocks until an evenet is set ``True`` and then
        goes into the context.

        The internal event flag will be reset ``False`` automatically before
        entering the context.

        Args:
            event_name (str): The indicator of the event
            is_keyboard (bool): Specify weather it is a keyboard event. See
                ``register_event()`` for details. Default: False

        Example::
            >>> from mmpose.apis.webcam.utils import EventManager
            >>> manager = EventManager()
            >>> manager.register_event('q', is_keybard=True)

            >>> # Once the keyboard event `q` is set, ``wait_and_handle``
            >>> # will reset the event and enter the context to invoke
            >>> # ``foo()``
            >>> with manager.wait_and_handle('q', is_keybard=True):
            ...     foo()
        """
        self.wait(event_name, is_keyboard)
        try:
            yield
        finally:
            self.clear(event_name, is_keyboard)