示例#1
0
    def start(self) -> mp.Process:
        """ Starts the async window-focus watcher and the ml/eyetracker module.
        """
        # If async watcher already running
        if self._async_proc_win is not None and self._async_proc_win.is_alive():
            warn('HUD State Manager already running.')

        # Else, not running -- start it
        else:
            # Start the state watcher
            ctx = mp.get_context('fork')
            self._async_signal_q_win = ctx.Queue(maxsize=1)
            self._async_output_q_win = ctx.Queue(maxsize=1)
            self._async_proc_win = ctx.Process(
                target=self._async_winstate_watcher, 
                args=(self._async_signal_q_win, self._async_output_q_win))
            self._async_proc_win.start()

            # Start the eyetracker
            self._gazetracker.open()
            self._gazetracker.start()
            
            # Give time to spin up
            sleep(1)

            # Start the user pos guide updater
            self._async_proc_pos = Thread(
                target=self._async_userpos_watcher, 
                args=(self._gazetracker, self.hud.status_panel))
            self._async_proc_pos.start()

        return self._async_proc_win
示例#2
0
    def prev_active_window(self):
        """ Returns an Xlib.Window obj for the previously active window.
        """
        # Request prev active window ID from async queue
        try:
            self._async_signal_q_win.put_nowait(SIGNAL_REQUEST_PREV_ACTIVE_WINDOW)
        except AttributeError:
            warn('Requested win state but Win State Watcher not yet started.')

        # Receive ID from asyc queue and return its derived window obj
        window_id = self._async_output_q_win.get()
        return self._disp.create_resource_object('window', window_id)
示例#3
0
    def stop(self) -> mp.Process:
        """ Stops the async focus watcher and eyetracker, and performs cleanup.
        """
        # Unset any keybd modifier toggles the user may have set
        self._reset_keyb_modifers(toggle_btnviz=False)

        # Send kill signal to the asynch procs
        try:
            self._async_signal_q_win.put_nowait(SIGNAL_STOP)
        except AttributeError:
            warn('Received STOP but HUD State Manager not yet started.')
        except mp.queues.Full:
            pass
        else:
            self._gazetracker.stop()
            self._gazetracker.close()

        return self._async_proc_win
示例#4
0
    def payload_run_external(self, **kwargs):
        """ Runs the external cmd given by the payload.

            :param kwargs: Arg 'payload' is expected.
        """
        self._focus_prev_active_win()

        # Extract kwarg
        payload = kwargs['payload']     # (str) Well-formatted python list

        # Ensure cmd given as a list of the cmd and its args
        cmd = eval(payload)
        if not cmd or not isinstance(cmd, list):
            raise ValueError(f'Invalid cmd format: {payload}')

        # Run the cmd
        proc = Popen(cmd, stderr=PIPE)
        stderr = proc.communicate()[1]
        proc.wait()

        # If there were build errors, quit
        if stderr and not stderr.decode().startswith('Created symlink'):
            warn(f'Cmd "{cmd}" stderr output: \n{stderr}')
                HUDButton(widget=None,
                          text=txt,
                          alt_text=None,
                          payload=key_id,
                          payload_type='keystroke'))

        print(f'Button read: {key} <{key_id}>')

    # Map buttons from keystrokes until ESC pressed
    with keyboard.Listener(on_press=on_press) as listener:
        listener.join()  # Stop listening/mapping btns

    # Write resulting layout to json, prompting to overwrite iff exists
    outfile = Path(OUTPUT_DIR, f'{args.panel_name}.{OUTPUT_EXT}')

    if outfile.exists():
        warn(f'File already exists: {outfile}')

        if input('Overwrite [y|N]? ') != 'y':
            print('Done. Results not written.')
            exit()

    with open(outfile, 'w') as f:
        json.dump(panel_btn_map,
                  f,
                  indent=4,
                  default=json_helper,
                  separators=(',', ': '))

    print(f'Done. Wrote results to {outfile}.')
示例#6
0
    def payload_keyboard_toggle_modifer(self, **kwargs):
        """ Updates the keyboard controller to reflect the given toggle key
            press. E.g. To toggle shift key on/off. In the process, focus is
            returned to the previously focused window.

            :param kwargs: Args 'btn' and 'payload' are expected.
        """
        self._focus_prev_active_win()

        # Extract kwargs
        payload = kwargs['payload']     # (int) Key vk code
        sender = kwargs['btn']          # (HUDPanel.HUDButton) Payload sender
        
        # Ensure modifier is supported
        if payload == VK_NUMLOCK:
            raise NotImplementedError('NumLock')
        elif payload == VK_SCROLLLOCK:
            raise NotImplementedError('ScrollLock')

        # Convert payload to KeyCode and denote capslock status
        keycode = self._keyboard._KeyCode.from_vk(payload)
        
        # If payload is for capslock, handle as a single-click modifier
        if payload == VK_CAPSLOCK:
            self._keyboard.press(keycode)
            self._keyboard.release(keycode)
            self.hud.set_btn_viz_toggle(
                sender, toggle_on=self._keyboard._caps_lock)

        # Else, if payload is the hold-modifer btn
        elif payload == VK_MODLOCK:
            toggle_down = not self._keyboard_hold_modifiers
            self._keyboard_hold_modifiers = toggle_down
            self.hud.set_btn_viz_toggle(sender, toggle_on=toggle_down)
            self._reset_keyb_modifers() if not toggle_down else None
            
        # Else, handle press/releases modifier (ex: alt, shift, etc.)
        else:
            with self._keyboard.modifiers as modifiers:
                modifier = self._keyboard._as_modifier(keycode)

                if not modifier:
                    raise ValueError(f'Unsupported modifier: {keycode}')

                # If btn not previously in the down state, send keypress
                if modifier not in [m for m in modifiers]:
                    toggle_down = True
                    self._keyboard.press(keycode)
                    self._keyboard_active_modifier_btns.append(sender)

                # else, send key release
                else:
                    toggle_down = False
                    try:
                        self._keyboard_active_modifier_btns.remove(sender)
                    except ValueError:
                        # Will occur if, say, l_shift set but r_shift clicked
                        warn('Attempted to unset a modifier that was not set.')
                        return
                    else:
                        self._keyboard.release(keycode)

                # Update btn state according to new toggle state
                self.hud.set_btn_viz_toggle(sender, toggle_on=toggle_down)
                if modifier == self._keyboard._Key.shift:
                    self.hud.keyb_panel.set_btn_text(use_alt_text=toggle_down)