Приветствую хабровчане!

Вот уже пол года как мой основной Desktop работает на Ubuntu, о плюсах и минусах Linux писать не буду, пост не об этом.
Так вот… я к сожалению не владею слепым методом набора текста, да и не было смысла обучаться так как в окнах меня вполне сносно спасала программа PuntoSwitcher которой пользовался около 5-ти лет, однако её аналог Xneur на Ubuntu мягко говоря работал «не очень» и вовсе не работал в Skype.

Некоторое время я мирился с этим, потом пробовал безуспешно написать небольшую программку на Java.

Требования к программе:

  1. Быстрый запуск
  2. Иконка в трее для выхода из приложения и отмены конвертации
  3. Конвертация по глобальной комбинации клавиш


— это тот функционал которым я и пользовался в PuntoSwitcher.

image


И вот буквально этой ночью я решил пойти другим путём и задействовать sh.

Не претендую на универсальность метода, но на Kubuntu 15.10 работает как надо.

Принцип работы:

  1. На ярлык sh скрипта вешается комбинация клавиш
  2. После запуска с помощью xclip получаем выделенный текст
  3. Конвертируем его в противоположную раскладку
  4. Утилитой xdotool вставляем новый текст заместо выделенного
  5. Меняем раскладку на противоположную что бы продолжать набирать текст.


От слов к делу:
 #!/bin/bash 

oldtemp=`xclip -o` #скопировали текст
temp=`'/home/username/desktop/switch' "$oldtemp"` #конвертируем текст
xdotool keydown Shift+Control_L #сменили раскладку
sleep 1 
xdotool keyup Shift+Control_L
xdotool type "$temp" #печатаем новый текст
notify-send "$oldtemp
->
$temp" -t 2000 #сообщение о том что сменили раскладку (опционально)
exit 0


xdotool keydown / xdotool keyup использовал вместо xdotool key потому как последнее у меня срабатывало через раз.

Теперь про конвертацию текста.
Для этого я решил использовать отдельно программу написанную на с++ которая бы принимала текст, понимала в какую сторону его нужно конвертировать и отдавала бы уже нормальный текст в консоль.

До этого на С++ писать не приходилось, благо функционала у этой утилиты на уровне «Hello world».

Беременным детям со слабой психикой не смотреть
#include <iostream>

using namespace std;

std::string Toreplace(std::string text, std::string s, std::string d){
    for(int index=0; index=text.find(s, index), index!=std::string::npos;)    {
        text.replace(index, s.length(), d);
        index+=d.length();
    }
    return text;
}

int GetCurentLang(std::string str){
    int thislang = 0;
    const char *cstr = str.c_str();
    std::string russtr[66] = {"й","ц","у","к","е","н","г","ш","щ","з","х","ъ","ф","ы","в","а","п","р","о","л","д","ж","э","я","ч","с","м","и","т","ь","б","ю","ё","Й","Ц","У","К","Е","Н","Г","Ш","Щ","З","Х","Ъ","Ф","Ы","В","А","П","Р","О","Л","Д","Ж","Э","Я","Ч","С","М","И","Т","Ь","Б","Ю","Ё"};
    std::string engstr[56] =  {"q","w","e","r","t","y","u","i","o","p","[","]","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m","<",">","Q","W","E","R","T","Y","U","I","O","P","A","S","D","F","G","H","J","K","L","Z","X","C","V","B","N","M"};
    for (int i = 0; i < str.length() && thislang == 0; i++){
        for (int a = 0; a < 66; a++){
            if (russtr[a].compare(new char (cstr[i])) == true) {
                thislang = 1;
            }
        }
        for (int a = 0; a < 56; a++){
            if (engstr[a].compare(new char (cstr[i])) == true) {
                thislang = 2;
            }
        }
    }
    return thislang;
}

std::string TranslateToRu(std::string str){
    std::string translate = str;
    std::string replacein[67] = {"q","w","e","r","t","y","u","i","o","p","[","]","a","s","d","f","g","h","j","k","l",";","'","z","x","c","v","b","n","m",",",".","/","Q","W","E","R","T","Y","U","I","O","P","[","]","A","S","D","F","G","H","J","K","L",";","'","Z","X","C","V","B","N","M",",",".","/","&"};
    std::string replaceto[67] = {"й","ц","у","к","е","н","г","ш","щ","з","х","ъ","ф","ы","в","а","п","р","о","л","д","ж","э","я","ч","с","м","и","т","ь","б","ю",".","Й","Ц","У","К","Е","Н","Г","Ш","Щ","З","Х","Ъ","Ф","Ы","В","А","П","Р","О","Л","Д","Ж","Э","Я","Ч","С","М","И","Т","Ь","Б","Ю",".","?"};
    for (int i = 0; i < 67; i++){
        translate = Toreplace(translate, replacein[i], replaceto[i]);
    }
    return translate;
}

std::string TranslateToEng(std::string str){
    std::string translate = str;
    std::string replacein[67] = {"й","ц","у","к","е","н","г","ш","щ","з","х","ъ","ф","ы","в","а","п","р","о","л","д","ж","э","я","ч","с","м","и","т","ь","б","ю",".","Й","Ц","У","К","Е","Н","Г","Ш","Щ","З","Х","Ъ","Ф","Ы","В","А","П","Р","О","Л","Д","Ж","Э","Я","Ч","С","М","И","Т","Ь","Б","Ю",".","?"};
    std::string replaceto[67] = {"q","w","e","r","t","y","u","i","o","p","[","]","a","s","d","f","g","h","j","k","l",";","'","z","x","c","v","b","n","m",",",".","/","Q","W","E","R","T","Y","U","I","O","P","[","]","A","S","D","F","G","H","J","K","L",";","'","Z","X","C","V","B","N","M","<",">","/","&"};
    for (int i = 0; i < 67; i++){
        translate = Toreplace(translate, replacein[i], replaceto[i]);
    }
    return translate;
}




int main(int argc, char *argv[]) {
    std::string translate;
    int currentlang = GetCurentLang(argv[1]);
    if (currentlang == 2){
        translate = TranslateToRu(argv[1]);
    }else if (currentlang == 1){
        translate = TranslateToEng(argv[1]);
    }else{
        translate = "";
    }


    cout << translate << endl;
    return 0;
}



GetCurentLang Принимает весь текст целиком и ищет первый символ в русской или английской раскладке, если первый встретившийся нам символ в английской раскладке то значит нужно всё переводить в русскую (символы разумеется игнорируем)

TranslateToEng, TranslateToRu массив с буквами для каждого направления свой что бы в дальнейшем настроить замену более гибко.

почему std::string а не char[] — как я уже говорил с С++ не знаком, а в char[] кириллица не умещается… (или что-то вроде этого)

Пока конвертация идёт в одну сторону, т.е если написать:
Бвшм шв=ЭьфштЭЮdjnБ.вшмЮ


на выходе получим:

<div id='main'>djn</div>


целесообразно было бы «djn» конвертировать тоже, но тогда встанет вопрос с неправильным определением символов ",. /" и т.д
помимо этого текст выделенный через Ctrl+A в xclip не попадает, наверное вместо этого нужно использовать:

xdotool keyup Control_L+С

Комментарии (23)


  1. KirillovAlex
    17.03.2016 11:29
    +1

    "не владею слепым методом набора текста, да и не было смысла обучаться так как в окнах меня вполне сносно спасала программа PuntoSwitcher"

    Хм… она же только переключает раскладки, но никак не исправляет орфографию или дописывает слова… Спрашиваю, может я чего не знаю?


    1. zabbius
      17.03.2016 12:18
      +1

      там еще вроде куча всяких исправлений была типа двух заглавных букв и неорфографических опечаток (которые из-за попадания не в ту кнопку или из-за удвоения букв), но второе может оказать плодом моей буйной фантазии, уже давно сижу на xneur и глючит он только в libreoffice, даже в игрушках под вайном и то работает.


      1. prijutme4ty
        17.03.2016 12:43
        +1

        Вынужден вас поправить.
        В libreoffice и в GoldenDict он глючит фатально — зачастую после неудачной попытки переключения приходится перезапускать приложение. Изредка Double commander тоже падает при попытке сменить раскладку в переименовании файла.
        Время от времени вместо переключения раскладки набранного текста — меняет раскладку и выводит текст из буфера обмена.
        По факту не умеет игнорировать определенные программы. В итоге в новых версиях InteliJIdea любое нажатие Ctrl срабатывает как двойной Ctrl, который имеет специальный (и неотключаемый) смысл.


        1. funnybanana
          17.03.2016 16:47

          Вынужден и Вас поправить, в том то всё и дело что xNeur у каждого по разному работает, в зависимости от… не знаю от чего зависит =) но это факт. У некоторых он вполне нормально работает, а у меня… в общем сами смотрите: 1:48 мотайте


          1. prijutme4ty
            17.03.2016 16:53

            Да, такое тоже бывает. Причем ладно бы хоть детерминистично себя вел...


            1. Mingun
              17.03.2016 20:30

              И у меня тоже такое. Порой бывает, сносно работает, но чаще глючит не по детски. Для тех, кто не понял, что было на видео, поясню — после выбора текста и выполнения действия "Сменить раскладку выделенного" выделенное удаляется и вместо него вставляется многократно повторенное из буфера обмена с непонятным образом измененной раскладкой (у некоторых символов изменена, у некоторых нет).

              Я даже довольно подробно отписался в баге, но похоже, если самому не начать дебажить, с мертвой точки это дело не сдвинется. К сожалению, launchpad — та еще помойная дыра с непонятной навигацией сделанная только для того, чтобы напрочь отбить желание там что-либо искать, а так же то, что понять, где лежит исходный код xneur-а совершенно невозможно, исправление сих багов кем-либо кроме автора является просто фантастикой.


        1. Maccimo
          18.03.2016 16:12

          >> в новых версиях InteliJIdea любое нажатие Ctrl срабатывает как двойной Ctrl, который имеет специальный (и неотключаемый) смысл.

          Вы с двойным Shift не путаете?
          Он вполне себе отключается, достаточно назначить «Search Everywhere» другую горячую клавишу.


    1. funnybanana
      17.03.2016 12:34

      Действительно в PuntoSwitcher много чего было, был даже словарь автозамены который можно было самому настраивать, к примеру пишу я "for" нажимаю ctrl+Enter и вуаля

      for ($i=0; $i<count($arr); $i++){
             // 
      }

      но с переходом на SublimeText нужда в таких комбинациях отпала из-за наличия внутри snippet

      сама галочка "Автоматически переключать раскладку" в PuntoSwitcher у меня всегда была отключена.


  1. mva
    17.03.2016 12:52
    -6

    Просто интересно, товарищ автор пробовал XNeur и не понравилось или вообще о нём не слышал?

    И, кстати, чтобы два раза не вставать:

    Иконка в трее для выхода из приложения и отмены конвертации

    1) странная необходимость иконки для выхода (вместо хоткея на остановку слежения),
    2) ещё более странная необходимость иконки для отмены конвертации (вместо того, чтобы отменять тоже глобальным хоткеем).

    Имхо


    1. nazarpc
      17.03.2016 17:42
      +2

      На самом деле для меня (я не автор статьи) основная проблема в том, что начиная примерно с Ubuntu 13.10 gXneur перестал работать практически совсем. Сначала он по 2 буквы вставлял, сейчас в 16.04 не работает вовсе, разве что иконку языка показывает. У автора gXneur, видимо, больше нет времени на разработку.


      1. mva
        17.03.2016 20:43

        Ну, у него такое бывает, да. Но мне всё же было интересно с нуля ли автор решил строить велосипеды или ознакомился с аналогами :)


    1. mva
      17.03.2016 20:42
      -3

      // в очередной раз у меня возник уже обычный для хабра вопрос: почему товарищи молча-минусующие не удосуживаются аргументрировать свою позицию в виде ответа на коммент? :-/


      1. iroln
        17.03.2016 22:02
        +3

        может быть, потому что автор написал в статье про xneur, а вы этого не заметили, потому что не читали, но комментарий оставили?


        1. mva
          17.03.2016 22:25

          Возможно, конечно, я и вправду плохо смотрел, но на момент публикации комментария я несколько раз перечитывал статью в поисках упоминания XNeur, и не находил оного. Но ладно, возможно я и в самом деле плохо читал


  1. Eltaron
    17.03.2016 14:28

    Ваша программа на C++ может быть заменена на два grep и два tr (точнее, sed y//, т.к. tr не дружит с юникодом).
    И ещё меня смущает else{ translate = ""; }. Выделил цифры, нажал хоткей, цифры стерлись — это вроде бы не очень логичное поведение. Хотя, ^Z тут спасет, так что это можно признать и фичей.


    1. funnybanana
      17.03.2016 16:58

      цифры не сотрутся, ведь я использую xdotool type (хотя мог бы текст вносить в буфер и в нужный момент тем же xdotool посылать Control+V что было бы намного быстрее, но и цифры бы тогда действительно стирались), так вот xdotool type "" — не нажмет никакой клавиши, текст останется выделенным...

      и на будущее смогу сделать что-то вроде:

      if [ temp == "" ] then
           # вывожу сообщение что конвертация невозможна или ещё чего =)
      enif

      а на счёт sed тут же на хабре читал про него, но… честно признаться не разобрался..


  1. PlatinumThinker
    18.03.2016 10:32

    Использую kbdd для того чтобы запомнить свою раскладку для каждого окна. Потому что чаще всего я пишу на одном языке в окне. Всякие PuntoSwitcher никогда не устраивали, потому что творили какую то фигню


  1. iroln
    20.03.2016 21:45

    Кстати, автор xneur есть на хабре — это Andrew_Crew_Kuznetsov. Андрей, может отпишетесь здесь, как там вообще дела с разработкой? Заброшено или нет? Какие планы по развитию проекта?


    1. Andrew_Crew_Kuznetsov
      21.03.2016 11:17
      +1

      Спрашивали — отвечаем. Проект не заброшен, но какое может быть развитие, если все фишки в общем-то реализованы? Периодически пересобираю под новые версии Ubuntu, на которой сижу, вот и вся поддержка.

      По поводу "тут работает — тут не работает" уже устал пояснять. При зоопарке дистрибутивов, DE и тулкитов всегда что-то где-то будет не работать. Делаешь костыль для одного, отваливается другое…


      1. zabbius
        21.03.2016 14:42

        Справедлив ли этот ответ для libreoffice? если я правильно понял, в нем не работает почти везде.


        1. Andrew_Crew_Kuznetsov
          21.03.2016 16:56

          Да вот, как на зло, у меня в libreoffice работает, а без повторения глюка у себя я и костыль даже не придумаю.

          А вообще что вы имеете ввиду? Какую "неработу"?


  1. Andrew_Crew_Kuznetsov
    21.03.2016 11:34

    Ну касательно темы топика, то подобное я вижу на Хабре и обсуждениях xneur ежегодно уже лет 10. Этот вариант с хардкором раскладок, да еще и отдельной прогой, вообще в конце рейтинга. Скриптом красивей было бы.

    А если прогу писать, то уж озаботился бы получением раскладок и соответствия букв программно.