воскресенье, 4 августа 2019 г.

Yet another keyboard layout switcher

Русская версия заметки доступна по ссылке.

I know about Punto Switcher, X Neural Switcher and some other similar software to switch layout for typed text:
Руддщб Цщкдв! → Hello, World! (and/or backwards, Hello, World! → Руддщб Цщкдв!)


But I have issues with applications running on Wine when I use XNeur, and can use Punto in Windows or Mac OS only. Besides both of them are too excess functionality for me, so I don't need automation for text editing. Sure, this software have many other useful features for text typing, but for me is enough, that after I use keyboard hotkeys text by the left of cursor get changed from one keyboard layout to another and when it works for applications, which running on Wine.

And I after tips of many intelligence people of Internet, who say "You need a software? Code it by yourself!", I made Python 3 script to "switch over" typed text.

The script works only when you need to change text and its does following:
– cut the part of text (by the left of cursor to the line's start or, if there is parameters on start, it can be a selected text or also last word – characters after closest left space);
– change each character of cutted text from first layout to founded by number of place character of second layout (it is trying to find out right layouts is with first three characters of cutted text);
– puts result of modification on same place it was before cut.

Features of the script:
– required Python 3 installed and some components of automatization (it is works like you press keyboard hotkeys to cut text to the clipboard and paste modified text after);
– no graphical user interface to interact with;
– if you need to change something what the script does, you should change the script;
– you can completely change layouts (character strings) by yourself;
– if script doesn't find any character in string to change, it just skip this;
– if text to change contains characters of both layouts, all of them will be changed to another (Руддщб World! → Hello, Цщкдв!)
– it doesn't scan keyboard keys pressed;
– the hotkey for running the script is set by you yourself (use different combinations to start with different parameters)

I didn't test how script working on Windows!
In Ubuntu-like distros you may need to install additional components (besides Python 3 itself). You can find it out with running script in the terminal. Use "delay" to get few time to move focus to application with typed text before script will start:
sleep 3 && python3 <path_to_script>
(to avoid typing whole path to the file just use drag-n-drop into terminal window; you have as much seconds as pointed after sleep command)

Terminal commands to install additional components (as superuser):
sudo apt install python3-pip
sudo pip3 install setuptools
sudo pip3 install pyperclip pyautogui xlib
sudo apt install python3-tk python3-dev

And, of course, you can find code of the script right here. I putted it as open source in hope to make some people's life and/or work easier. Safe the code as file with "py" extension, it is standard extension for Python scripts, for example: "Swtchr.py":

#! /usr/bin/python3

"""
# This script wrote in Python 3.
# It is very simple variation of XNeur and PuntoSwitcher, wich works with apps running on Wine
#
# Usage: Put hotkeys in you system (like [Ctrl]+[R_Win]) to start script,
#        use this hotkeys to change typed text from 1st keyboard layout to 2nd.
#
# Requirements: module to work with clipboard
#               'pyperclip',
#               modules of automatization
#               'pyautogui' и 'xlib'
#
# Mikhail Vinakov, 2019-06-14
# 2019-08-01: Added parameters to start with: -lastword и -selected
"""


import pyautogui, time, sys

no_pyperclip = False

clpbrd_strg = ""
layout_01 = "`~@#$%^&" +\
            "qwertyuiop[]QWERTYUIOP{}asdfghjkl;'\\ASDFGHJKL:\"|zxcvbnm,./ZXCVBNM<>?"
layout_02 = "ёЁ\"№;%:?" +\
            "йцукенгшщзхъЙЦУКЕНГШЩЗХЪфывапролджэ\\ФЫВАПРОЛДЖЭ/ячсмитьбю.ЯЧСМИТЬБЮ,"

try:                                    # Trying to import necessary module
    import pyperclip                    # If failed no point to run further
except ImportError:
    no_pyperclip = True

def computing():
    if no_pyperclip == True:
        print("Required module to work with clipboard: pyperclip")
        quit()
    elif len(layout_01) != len(layout_02):
        print("Strings of characters (layout_01 и layout_02) mismatch by length!")
        quit()
    else:
        workaround()

def workaround():
    pyperclip.copy("")

    time.sleep(.1)
    if len(sys.argv) < 2:
        pyautogui.hotkey("shift", "home")

        time.sleep(.3)
        pyautogui.hotkey("ctrl", "x")
    elif sys.argv[1] == "-selected":
        pyautogui.hotkey("ctrl", "x")
    elif sys.argv[1] == "-lastword":
        pyautogui.hotkey("shift", "ctrl", "left")

        time.sleep(.3)
        pyautogui.hotkey("ctrl", "x")
    else:
        print("Unknown parameter:", sys.argv[1])
        quit()
    fixed_text = magic(pyperclip.paste())
    pyperclip.copy(fixed_text)

    time.sleep(.1)
    pyautogui.hotkey("ctrl", "v")

def magic(text):
    if len(text) < 1:
        quit()
    elif len(text) < 3:                 # Let's compare which string's characters are more
        first_x = 1                     # Odd numbers are desirable for comparison
    else:
        first_x = 3

    chars_01, chars_02 = 0, 0
    for i in range(first_x):            # Which layout's characters are more : 01 или 02?
        if text[i] in layout_01:
            chars_01 += 1
        elif text[i] in layout_02:
            chars_02 += 1
    if chars_01 > chars_02:
        layout = layout_01 + layout_02 + layout_01
    else:
        layout = layout_02 + layout_01 + layout_02

    new_text = ""
    for c in range(len(text)):          # Skip character if not represented in strings
        if not text[c] in layout:
            new_text = new_text + text[c]
        else:
            new_text = new_text + layout[layout.find(text[c])+len(layout_01)]
    return new_text

clpbrd_strg = pyperclip.paste()         # Save current clipboard to variable
computing()
pyperclip.copy(clpbrd_strg)             # Restore clipboard from variable
clpbrd_strg = ""


Found out, if application with text to change is running on Wine, after script done right [Ctrl] key looks like still pressed (I use that key with hotkeys to start script). Issue was fixed when I add few lines of code to the script at the end. It's how if you press and release right [Ctrl] key again:

# Fix issue if right [Ctrl] key looks like still pressed
pyautogui.keyDown("ctrlright")
time.sleep(.1)
pyautogui.keyUp("ctrlright")

You can run script in standard mode, when will change text by the left of cursor to the line's start ([Shift] + [Home] hotkeys pressed), and also with one of following parameters:
– "-lastword" – change last word before cursor only
– "-selected" – change selected text only

Комментариев нет:

Отправить комментарий

Если у вас есть что сказать и/или вы не согласны с изложенным в посте – оставьте комментарий. Регистрации не требуется.

If you think I'm wrong and/or you have to say something – fill free to write comment. No sign up required.