Beispiel #1
0
    def from_string(cls, key_sequence_string):
        modifiers_key_state = ModifiersKeyState()
        func_pattern_match = cls.FUNC_PATTERN.match(key_sequence_string)
        if func_pattern_match:
            return cls(Function(func_pattern_match.group(cls.FUNC_NAME_STRING), func_pattern_match.group(cls.ARGS_STRING)))
        pattern_match = cls.SURROUNDED_PATTERN.match(key_sequence_string)
        if pattern_match:
            key_string = pattern_match.group(cls.KEY_STRING)
            if pattern_match.group(cls.WINDOWS_STRING):
                modifiers_key_state.windows = True
            if pattern_match.group(cls.ALT_STRING):
                modifiers_key_state.alt = True
            if pattern_match.group(cls.CONTROL_STRING):
                modifiers_key_state.control = True
            if pattern_match.group(cls.SHIFT_STRING):
                modifiers_key_state.shift = True
        else:
            key_string = key_sequence_string

        for key_class in cls.KEY_CLASSES:
            key, shift = key_class.from_string(key_string, modifiers_key_state.shift)
            if key is not None:
                modifiers_key_state.shift = shift
                return cls(key, modifiers_key_state.presses())
        else:
            return cls(NoneKey.NONE, modifiers_key_state.presses())
Beispiel #2
0
    def __init__(self, parent = None):
        QObject.__init__(self, parent = parent)

        # フックマネージャーを生成
        self.hook_manager = pyHook.HookManager()
        # KeyDown, KeyUpで呼ばれる関数を設定
        self.hook_manager.KeyDown = self.on_keyboard_event
        self.hook_manager.KeyUp= self.on_keyboard_event

        self.modifiers_key_state = ModifiersKeyState()

        self.timer = QTimer(self)
        self.timer.setInterval(800)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.on_timeout)
        self.timer_running = False

        self.window_dict = dict()
        self.candidates = deque()

        self.key_sequences = deque()
        self.window_id = None
        self.clipboard = Clipboard()
        self.current_node = None
        self.root_node = KeyDictNode(dict())
        for mode in Mode:
            self.root_node.set_key_dictionary(mode)
        for shortcuts_info in shortcuts_tuple:
            shortcuts_info.set_mode_shortcuts(self.root_node)
        self.current_exe_name = ""
        self._mode = Mode.NORMAL
        self.set_mode_node()
        self.waiting_return_key = ""
        self.func_dict = FuncDictDecorator.func_dict()
Beispiel #3
0
class EnVimKey(QObject):

    about_to_quit = pyqtSignal()
    changed_mode = pyqtSignal(str, str, int)
    about_to_search = pyqtSignal(object)

    def __init__(self, parent = None):
        QObject.__init__(self, parent = parent)

        # フックマネージャーを生成
        self.hook_manager = pyHook.HookManager()
        # KeyDown, KeyUpで呼ばれる関数を設定
        self.hook_manager.KeyDown = self.on_keyboard_event
        self.hook_manager.KeyUp= self.on_keyboard_event

        self.modifiers_key_state = ModifiersKeyState()

        self.timer = QTimer(self)
        self.timer.setInterval(800)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.on_timeout)
        self.timer_running = False

        self.window_dict = dict()
        self.candidates = deque()

        self.key_sequences = deque()
        self.window_id = None
        self.clipboard = Clipboard()
        self.current_node = None
        self.root_node = KeyDictNode(dict())
        for mode in Mode:
            self.root_node.set_key_dictionary(mode)
        for shortcuts_info in shortcuts_tuple:
            shortcuts_info.set_mode_shortcuts(self.root_node)
        self.current_exe_name = ""
        self._mode = Mode.NORMAL
        self.set_mode_node()
        self.waiting_return_key = ""
        self.func_dict = FuncDictDecorator.func_dict()


    @FuncDictDecorator.inner_func("insert")
    def change_to_insert_mode(self):
        self._mode = Mode.INSERT
        self.set_mode_node()
        self.changed_mode.emit("Mode", "Insert", 500)
        print("insert")

    @FuncDictDecorator.inner_func("normal")
    def change_to_normal_mode(self):
        self._mode = Mode.NORMAL
        self.set_mode_node()
        self.changed_mode.emit("Mode", "Normal", 500)
        print("normal")

    @FuncDictDecorator.inner_func("visual")
    def change_to_visual_mode(self):
        self._mode = Mode.VISUAL
        self.set_mode_node()
        self.changed_mode.emit("Mode", "Visual", 500)
        print("visual")

    @FuncDictDecorator.inner_func("focus")
    def set_window_focus(self, search_window_name):
        def match_window_name(window_handle, dummy):
            window_title = str(win32gui.GetWindowText(window_handle))
            if window_name_pattern.match(window_title):
                self.target_window_handle = window_handle

        self.target_window_handle = None
        window_name_pattern = re.compile(search_window_name)
        win32gui.EnumWindows(match_window_name, "")
        if self.target_window_handle:
            win32gui.SetForegroundWindow(self.target_window_handle)
            win32gui.ShowWindow(self.target_window_handle, win32con.SW_MAXIMIZE)

    @FuncDictDecorator.inner_func("quit")
    def quit_envimkey(self):
        self.about_to_quit.emit()

    @FuncDictDecorator.inner_func("copy")
    def copy_to_clipboard(self,text):
        self.before_text = self.clipboard.get()
        self.clipboard.set(text)

    @FuncDictDecorator.inner_func("rollback")
    def rollback_to_clipboard(self):
        self.clipboard.set(self.before_text)

    def set_mode_node(self):
        self.current_node = self.root_node.dictionary[self._mode]
        # self.print_dict(self.root_node.dictionary)

    def timer_start(self):
        print("start")
        self.timer_running = True
        self.timer.start()

    def timer_stop(self):
        print("stop")
        self.timer.stop()
        self.timer_running = False
        self.set_mode_node()
        if self.waiting_return_key:
            self.emulate_keys(self.waiting_return_key)
            self.waiting_return_key = None
            self.key_sequences.clear()
        if self.key_sequences:
            self.emulate_keys(KeySequences.from_sequences(self.key_sequences).action_atoms)
            self.key_sequences.clear()

    def emulate_keys(self, keys):
        print(keys)
        for action_atom in keys:
            if action_atom.type == ActionType.PRESS:
                if action_atom.extended:
                    win32api.keybd_event(action_atom.info, 0, win32con.KEYEVENTF_EXTENDEDKEY | 0, 0)
                else:
                    win32api.keybd_event(action_atom.info, 0, 0, 0)
                # win32api.keybd_event(action_atom.info, 0, win32con.KEYEVENTF_EXTENDEDKEY | win32con.KEYEVENTF_KEYUP, 0)
                win32api.keybd_event(action_atom.info, 0, win32con.KEYEVENTF_KEYUP, 0)
            elif action_atom.type == ActionType.DOWN:
                win32api.keybd_event(action_atom.info, 0, 0, 0)
            elif action_atom.type == ActionType.UP:
                win32api.keybd_event(action_atom.info, 0, win32con.KEYEVENTF_KEYUP, 0)
            else:
                func_arg = action_atom.info.args
                if func_arg is not None:
                    getattr(self, self.func_dict[action_atom.info.text])(func_arg)
                else:
                    getattr(self, self.func_dict[action_atom.info.text])()

    def search(self, key_text, exe_name):
        # self.print_dict(self.current_node.dictionary)
        print(exe_name)
        self.waiting_return_key = ""
        if not(self.timer_running):
            try:
                self.current_node = self.current_node.dictionary[exe_name]
            except KeyError:
                # マッチする実行ファイル名が登録されていない場合
                self.timer_stop()
                return
        try:
            node = self.current_node.dictionary[key_text]
            self.current_node = node
            # ノードの辞書が空で、結果が確定する場合
            if not(node.dictionary):
                self.key_sequences.clear()
                self.timer_stop()
                self.emulate_keys(node.return_key)
                return
            # 結果の候補が存在し、一定時間待機する必要がある場合
            if node.has_return_key:
                self.timer_start()
                self.waiting_return_key = node.return_key
                return
            # マッチしたが次の入力がなければ結果が確定しない場合
            self.timer_start()
            return
        # マッチするキーが存在しない場合
        except KeyError:
            if len(self.key_sequences) == 1:
                self.key_sequences.clear()
                self.timer_stop()
                return SearchResultType.NOT_MATCH_BREAK
            self.timer_stop()
            return

    def on_keyboard_event(self, event):
        # 自分でエミュレートしたイベントならそのままイベントを通す
        if event.Injected:
            # print(event.KeyID)
            return True

        # デバッグ用にescを押したら終了するようにしておく
        if event.KeyID == 27:
            self.timer.stop()
            self.about_to_quit.emit()
            return False

        window_id = event.Window
        # 前回のイベントとwindow_idが異なれば
        if self.window_id != window_id:
            self.window_id = window_id
            # キーイベントを受け取るアプリケーションのexe名を取得
            self.current_exe_name = self.get_exe_name(window_id)
            print(self.current_exe_name)

        code = event.KeyID
        # event.Transitionはpressなら0, releaseなら128
        is_press_event = not(event.Transition)
        # モディファイアーが押されているかチェックし、modifiers_key_stateの状態を更新する
        pressed_modifier = self.modifiers_key_state.pressing(code, is_press_event)

        # モディファイアーが押されていれば以降の処理をしない
        if pressed_modifier:
            print("modifier", code)
            return True

        # キーがReleaseされるイベントなら以降の処理をしない
        if not(is_press_event):
            return True

        # キーコードとモディファイアーの状態をもとにキーシークエンスを生成
        seq = KeySequence.from_code(code, self.modifiers_key_state.presses())

        self.key_sequences.append(seq)

        search_result = self.search(seq.text, self.current_exe_name)

        if search_result == SearchResultType.NOT_MATCH_BREAK:
            return True

        # Falseを返すとイベントを無視し、Trueを返すとイベントを処理する
        return False

    def get_exe_name(self, window_id):
        try:
            base_exe_name = self.window_dict[window_id]
        except KeyError:
            # プロセスIDを取得
            thread_id, process_id = GetWindowThreadProcessId(window_id)
            # プロセスハンドルを取得
            process_handle = OpenProcess(PROCESS_VM_READ|PROCESS_QUERY_INFORMATION, 0, process_id)
            # キーを受け取るアプリケーションのexe名を取得
            name = GetModuleFileNameEx(process_handle, 0)
            # .exeを除く
            base_exe_name = os.path.basename(name)[:-4]
            self.window_dict[window_id] = base_exe_name
        return base_exe_name

    def _window_enum_callback(self, hwnd, wildcard):
        is_visible = win32gui.IsWindowVisible(hwnd)
        if not(is_visible):
            return

        title = str(win32gui.GetWindowText(hwnd))
        if title != "" and title != "Program Manager":
            try:
                exe_name = self.get_exe_name(hwnd)
            except:
                exe_name = ""
            self.candidates.append((title, exe_name, hwnd))

    def find_window_wildcard(self):
        self.candidates.clear()
        win32gui.EnumWindows(self._window_enum_callback, "")

    @FuncDictDecorator.inner_func("search")
    def search_exe(self):
        self.find_window_wildcard()
        self.about_to_search.emit(self.candidates)

    def key_unlock(self):
        # キーボードフックを解除する
        self.hook_manager.UnhookKeyboard()
        self.thread().quit()

    def keylock(self):
        # キーボードフックを開始する
        self.hook_manager.HookKeyboard()
        pythoncom.PumpWaitingMessages()

    def print_dict(self, d, depth = 0):
        def print_indent(depth, *args, **kwargs):
            print(" "*8*depth, *args, **kwargs)

        for x, y in d.items():
            if len(y.dictionary):
                print_indent(depth, x)
                self.print_dict(y.dictionary, depth + 1)
            if y.has_return_key:
                print_indent(depth, x, y.return_key)

    def on_timeout(self):
        print("timeout")
        self.timer_stop()