как изменить метод ввода при нажатии <esc> в vim?

Мои действия по редактированию:

  1. Введите несколько китайских слов в режиме вставки.
  2. Нажмите, чтобы вернуться в обычный режим.
  3. Нажимать <shift>изменить метод ввода на английский язык.
  4. Нажимайте клавиши в обычном режиме.

Я хочу реализовать "Нажмите <esc>вернуться в обычный режим, а также изменить метод ввода на английский язык.".

В Windows у Xshell есть предварительная возможность реализовать именно то, что я хочу. Но после обновления ОС Xshell работает некорректно.

Мне также нужна эта функция в Linux. У меня есть Raspberry pi 4 под управлением ОС Raspbian. Я использую Терминатор в Raspbian.

Как я могу реализовать это в Win10 и Raspbian?

1 ответ

Я нашел способ работать на windows10. (Не проверяйте другие ОС Windows).

В моих настройках win10 у меня есть только китайский метод ввода пиньинь, других нет.

Идея ниже.

  1. использовать pynputслушать <esc>выпуск ключа.
  2. используйте и , чтобы найти текущее окно фокуса.
  3. использовать ctypesс imm32DLL для получения текущего типа языка.
  4. используйте отправить сообщение, чтобы сфокусировать окно, измените язык на английский, если текущий китайский.

Код ставится ниже.

      
#!/usr/bin/env python3

# pip install pynput
# pip install pywin32

from pynput.keyboard import Key, Listener, Controller
from os import system
import os
import signal
import ctypes
from ctypes import wintypes
import win32api
import win32process
import win32gui
import time

KEY = Key.esc
keyboard = Controller()

user32 = ctypes.WinDLL(name="user32")
imm32 = ctypes.WinDLL(name="imm32")

class GUITHREADINFO(ctypes.Structure):
    _fields_ = [
        ("cbSize", wintypes.DWORD),
        ("flags", wintypes.DWORD),
        ("hwndActive", wintypes.HWND),
        ("hwndFocus", wintypes.HWND),
        ("hwndCapture", wintypes.HWND),
        ("hwndMenuOwner", wintypes.HWND),
        ("hwndMoveSize", wintypes.HWND),
        ("hwndCaret", wintypes.HWND),
        ("rcCaret", wintypes.RECT),

    ]

    def __str__(self):
        ret = "\n" + self.__repr__()
        start_format = "\n  {0:s}: "
        for field_name, _ in self. _fields_[:-1]:
            field_value = getattr(self, field_name)
            field_format = start_format + ("0d{1:016d}" if field_value else "{1:}")
            ret += field_format.format(field_name, field_value)
        rc_caret = getattr(self, self. _fields_[-1][0])
        ret += (start_format + "({1:d}, {2:d}, {3:d}, {4:d})").format(self. _fields_[-1][0], rc_caret.top, rc_caret.left, rc_caret.right, rc_caret.bottom)
        return ret


def handler(signum, frame):
    print("get signal")
    os._exit(-1)

def GetGUIThreadInfo(win32, tid, info):
    GetGUIThreadInfo_func = getattr(win32, "GetGUIThreadInfo")
    GetGUIThreadInfo_func.argtypes = [wintypes.DWORD, ctypes.POINTER(GUITHREADINFO)]
    GetGUIThreadInfo_func.restype = wintypes.BOOL
    info.cbSize = ctypes.sizeof(GUITHREADINFO)
    return GetGUIThreadInfo_func(tid, ctypes.byref(info))

def set_window_english(h_wnd, tmp):
    h_imc = imm32.ImmGetDefaultIMEWnd(h_wnd)
    WM_IME_CONTROL=643
    IMC_GETCONVERSIONMODE=0x01
    status = win32api.SendMessage(h_imc, WM_IME_CONTROL, IMC_GETCONVERSIONMODE, 0)
    # status != 0: means chinese.
    # status == 0: means english.
    print(h_wnd, win32gui.GetWindowText(h_wnd), win32gui.GetClassName(h_wnd), status)
    if status != 0:
        # IMC_SETCONVERSIONMODE=2
        ret = win32api.SendMessage(h_imc, WM_IME_CONTROL, 2, 0) 
    
def change_to_english():
    h_wnd = win32gui.GetForegroundWindow()
    tid, pid = win32process.GetWindowThreadProcessId(h_wnd)
    info = GUITHREADINFO()
    if GetGUIThreadInfo(user32, tid, info):
        #print(info)
        #print(win32gui.GetWindowText(info.hwndFocus), win32gui.GetClassName(info.hwndFocus))
        set_window_english(info.hwndFocus, None)

def on_press(key):
    pass
        
def on_release(key):
    if key == KEY:
        change_to_english()
       
signal.signal(signal.SIGINT, handler)

listener = Listener(
        #on_press=on_press,
        on_release=on_release)

listener.start()
while True:
    #pass
    time.sleep(100)

Трудная часть - получить текущее окно фокуса.

win32gui.FindWindowа также win32gui.FindWindowExне могу найти дочерние окна.

win32gui.EnumChildWindowможет сделать работу, но это слишком медленно для xshell.

GetFocusпросто верните 0, я не знаю, почему.

GetGUIThreadInfoработает хорошо, но не запакован pywin32. Я нашел способ обернуть его в этой ссылке . Это метод, который я использую.

Другие вопросы по тегам