Я достаточно давно пользуюсь OS X и привык к его удобной системе переключения языков. Отличие от переключения в Windows состоит в том, что на маке переключение языков происходит между двумя последними использовавшимися. До тех пор, пока в Windows два языка — это не создает проблем, но лично я знаю людей, у которых 4 языка это норма и для них переключение языков доставляет некоторые неудобства из-за чего выбирать нужный язык приходится кликом мышки, а не комбинацией кнопок. И вот так, после очередного удаления/установки третьего языка, было решено написать простой переключатель раскладки клавиатуры для себя, а заодно получить полезный опыт.

Исходники программы доступны по адресу https://bitbucket.org/Ezbar/languageswitcher/overview. Для тех кто хочет попробовать программу и не заниматься компиляцией найдут бинарник в разделе Downloads.

Какие задачи пришлось решать:

— перехват нажатий комбинации Win + Пробел
— смена раскладки для активной программы
— пропадание фокуса активной программы, после смены раскладки

Рассмотрим каждый случай отдельно. Для перехвата нажатий мы будем использовать функции API и установим хук для WH_KEYBOARD_LL. Значение констант и всю обвязку вызова хука можно посмотреть в коде.

Функция проверки нажатия комбинации для переключения языка
static IntPtr IgnoreWin_Space(int nCode, IntPtr wParam, IntPtr lParam)
        {
            Boolean spacePressed = false;
            var keyInfo = (KbHookParam)Marshal.PtrToStructure(lParam, typeof(KbHookParam));

            if (nCode == HC_ACTION)
            {                
                if ((int)wParam == WM_KEYDOWN)
                {
                    if (keyInfo.VkCode == (int)Keys.Space)
                    {
                        spacePressed = true;                        
                        kSpace = true;
                    }
                    else
                        kSpace = false;

                    // нажат одновременно левый виндовс
                    if (GetAsyncKeyState(Keys.LWin) < 0)
                        kWin = true;
                    else
                    {
                        kWin = false;
                    }

                    if (kWin && kSpace)
                    {                        
                        if (spacePressed)
                        {
                            Bar.SetLanguage("");
                            Bar.Show(); // сбивает фокус, пофиксим в конструкторе
                            return (IntPtr)1; //just ignore the key press
                        }
                    }
                }
            }
            if ((int)wParam == WM_KEYUP)
            {
                if (keyInfo.VkCode == (int)Keys.LWin)
                {                    
                    kWin = false;
                    Bar.DoHide();
                    string HEX = Bar.getHex();
                    uint WM_INPUTLANGCHANGEREQUEST = 0x0050;
                    uint KLF_ACTIVATE = 1;
                    PostMessage(GetForegroundWindow(), WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, LoadKeyboardLayout(HEX, KLF_ACTIVATE));
                }                
            }

            return CallNextHookEx(HookHandle, nCode, wParam, lParam);
        }       


Смена раскладки для активной программы так же производится через вызов API функцией PostMessage. Для этого мы получаем дискриптор активного приложения и отправляем ему сообщение для смены раскладки. Шестнадцатеричный код для кодировки языка мы получаем из функции ответственной за получение всех установленных языков в систему и их порядок переключения.

Смена раскладки для активной программы
string HEX = Bar.getHex();
uint WM_INPUTLANGCHANGEREQUEST = 0x0050;
uint KLF_ACTIVATE = 1;
PostMessage(GetForegroundWindow(), WM_INPUTLANGCHANGEREQUEST, IntPtr.Zero, LoadKeyboardLayout(HEX, KLF_ACTIVATE));


Пропадание фокуса активной программы можно было наблюдать при вводе текста, например, в адресной строке браузера. После переключения языка пропадал фокус в текстом поле, где происходил набор. Оказалось что это очень просто исправляется в конструкторе.

Код для конструктора
// Show a Form without stealing focus
protected override bool ShowWithoutActivation
{
     get { return true; }
}


В итоге я получил хороший опыт и маленькую, но полезную программу, которая облегчает жизнь, если у вас установлено больше двух ракладок клавиатуры. Буду признателен за любые комментарии и советы и прошу прощение за допущенные мною орфографические ошибки, а так же за возможно сумбурное изложение мыслей. Автор самоучка и, возможно, некоторые вещи называет не своими именами. Всем спасибо за внимание. Надеюсь, публикация будет кому-то полезной, например у кого на одном компьютере живет OSX+Windows или кто просто изучает программирование.
Поделиться с друзьями
-->

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


  1. zeit-geist
    25.08.2016 08:05

    MacSwitch.exe не является приложением Win32.

    Это только у меня?


    1. Ezbar
      25.08.2016 09:05

      скачал файл и проверил на трех компьютерах (Win 10 и Win 7) — работает


      1. zeit-geist
        25.08.2016 10:07

        у меня win2k3
        возможно собрать под эту ось?


        1. izzholtik
          25.08.2016 10:12
          +1

          (на всякий случай проверил год отправки комментария)

          Судя по тому, что вы пытаетесь твикать систему, она используется не в качестве управляющего модуля для какого-то старого оборудования, а как основная. Зачем?..


        1. Pakos
          25.08.2016 10:43

          Под XP(2k3) нужна сборка net-программы x86, а не AnyCPU, иначе ЭТО.


        1. Ezbar
          25.08.2016 12:36

          https://bitbucket.org/Ezbar/languageswitcher/downloads/MacSwitch (x86 net 3.5).exe пересобрал, надеюсь заработает.


      1. LoadRunner
        25.08.2016 10:09
        +1

        Чем Вам нативный Win+Space в Windows 10 не угодил?
        Для систем помладше я ещё понимаю, но в Windows 10\8 эта программа бесполезна.

        Кстати, компилировали под какой .net Framework?


        1. Ezbar
          25.08.2016 10:23
          +1

          .net 4.52. Чем не угодил нативный: у меня на одном компьютере установлена OSX и Windows. Основное время я провожу в маке и пользуюсь маковской клавиатурой. И когда я иногда загружаю виндовс, то в силу вступает привычка. Я переключаю языки не задумываясь, как привык и наличие третьего языка в виндовсе сильно раздражало. Виндовс переключает языки по порядку, а мак — между двумя последними, которые использовали. Сначала в виндовсе не хватало возможности регулировать громкость с маковской клавиатуры, но это легко исправляется через BootCamp 5/6. Ситауцию с переключением пришлось решать написанием этой программы.


          1. LoadRunner
            25.08.2016 10:36

            А чем обусловлен выбор .net 4.52? Потому что по умолчанию? Отсюда и проблемы запуска на XP\2003 могут быть.

            А переключение между двумя последними языками… Видимо, я не понимаю этой прелести потому, что никогда не использовал больше двух.
            Но в Windows есть такая фича, как «метод ввода» — на одну и ту же раскладку можно навешать больше одного языка и переключать другим сочетанием. Таким образом, для переключения на редко используемый язык надо делать нажатия на два разных сочетания клавиш.
            Не знаю, как на маке переключиться на третью почти не используемую раскладку, но способ Windows мне кажется удобнее.


            1. Ezbar
              25.08.2016 10:45

              Выбор ничем не обсуславливался. Делал для себя. Исходники в открытом доступе. Каждый желающий может скомпилировать. Если с этим проблемы, то могу скомпилировать под необходимый фреймверк. Все дело в привычке, а привычки у всех разные. На третью и любую другую раскладке в маке можно переключиться так же как в виндовсе. Разница только в первом нажатии Win+Space. Виндовс переключает на следующий в списке язык, мак — на предыдущий. При последующих нажатиях и мак и виндовс просто переключают по кругу (пока ужерживаем кнопку Win, она же Cmd на маковской клавиатуре).


        1. wtigga
          25.08.2016 11:34
          -1

          Господи, я даже не знал про Win+Space, спасибо. Жаль не по центру отображается, как в маке, было бы куда удобнее.


  1. wtigga
    25.08.2016 08:32
    +5

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


    Не знаю, как вы пользуетесь тремя и более языками, но способ OS X мне кажется как раз неудобным. У меня, например, три активных языка, и в то короткое время, когда я пользовался маком, весьма раздражало, что я не мог произвольно переключать между языками простым сочетанием клавиш — нужно смотреть на экран и выбирать язык (если он не в списке последних двух).

    В Windows сочетание типа alt+shift переключает языки по кругу, а ещё можно задать конкретное сочетание для конкретного языка, например, LeftAlt+Shift+1.


    1. wtigga
      25.08.2016 09:20

      Хотя, конечно, фиксированные сочетания для языков в винде периодически слетают. (интересно, когда пофиксят? с семёрки ещё баг).


      1. TechPriest
        25.08.2016 15:19

        Есть способ обохода этого бага — после настройки сочетаний клавиш нужно применить их к лок-скрину. (Control Panel\Clock, Language, and Region\Language\Advanced settings -> Apply language settings to welcome screen)


  1. terziele
    25.08.2016 09:37
    +1

    У самого три языка и переключение по кругу с помощью Shift+CapsLock вполне удобно. Знаешь, что, например, русский третий в списке, а английский на первом месте — нажимаешь сочетание два раза => профит.
    А от фразы "… приходится выбирать кликом мыши...", мне почему-то представляется человек только вчера познакомившийся с «ентим вашим камплютером».

    Но за статью все же спасибо.


    1. CrazyLazy
      25.08.2016 23:31

      У меня Windows 7 и я не вижу где выбрать Shift+CapsLock. Это наверное только в новых версиях или с использованием доп программы (PuntoSwitcher например)? Или, возможно, это где-то в другом месте устанавливается? Не подскажите?


      1. terziele
        26.08.2016 09:10

        У меня Debian просто. :D


  1. ErshoFF
    25.08.2016 09:55

    На двух мониторах надпись «Язык» показывается только на основном, вне зависимости от активного окна.
    Также виснет окно пока не закроется надпись на панели задач.
    Windows 7.


  1. maks1mm
    25.08.2016 13:58
    +2

    Уже много лет что на винде что на линуксе использую хоткей из трёх клавиш для каждого из трёх языков в системе.
    Например english — Alt+Shift+1, russian Alt+Shift+2 и тд.
    Нажимается легко одной рукой в слепую, настолько удобно что не нужно никаких сторонних приложений и танцов с бубнами.
    У винды эта возможность есть прямо в настройках, у линукса прописывается новый хоткей и вешается специальная команда и делов то.


  1. AliceRamsy
    25.08.2016 13:58

    Есть яндексовский Punto Switcher, переключения раскладки «по кругу» использую стандартную комбинацию ALT+SHIFT, а для рус и англ в Punto Switcher настроил на рус одно нажатие на CTRL, а для англ одно нажатие на SHIFT, для меня удобно.


  1. adasoft
    25.08.2016 14:02
    +1

    а скайп не подвисает при использовании Вашей переключалки?


    1. Ezbar
      25.08.2016 14:03

      скачал последнюю версию скайпа для проверки — не виснет. так же проверил в Skype Preview из Windows 10 — тоже не виснет.


      1. adasoft
        25.08.2016 14:12

        действительно не виснет, но проверил и своё приложение — тоже перестал зависать Скайп при переключении, видимо что-то починили в консерватории.

        А вот интересно — на экране показываются сообщения «English» и «русский» — это виндовс такие строки отдает, с разной капитализацией первой буквы или в программе так заложено?


        1. Ezbar
          25.08.2016 14:25

          Виндовс так отдает. Я ничего не меняю. Исходный код программы доступен по ссылке в статье.


      1. CrazyLazy
        25.08.2016 22:52

        Попробавал. У меня подвисают все программы — Windows 7 SP1 x64 ENG (раскладки: English (United Kingdom) + RUS + UKR). Skype при этом запущен (v7.26.80.101).

        Выключил Skype — все равно подвисает но уже намного быстрее отходит (раза в 2 наверное)… но все равно занимает где-то секунды 3. Когда подвисает то видно что появляется окошко (в панельке задач) этой вот программы (сужу по стандартной VS иконке).


  1. MichaelBorisov
    25.08.2016 14:18

    Вот сколько за последние 20 лет добавлялось дополнительных клавиш на клавиатуры, но специальную клавишу переключения языка никто до сих пор не добавил! А такая клавиша была почти на всех советских компьютерах для переключения «Рус/лат».


    1. ruikarikun
      25.08.2016 14:48

      Вот сколько за последние 20 лет добавлялось дополнительных клавиш на клавиатуры

      Внезапно, ни одной! Все экзотические клавиши уже были на Microsoft Natural keyboard 22 года назад, в 1994 году.


    1. EndUser
      25.08.2016 21:29
      +1

      При этом Scroll Lock реализует разве что Excel.
      А где и когда использовался SysReq я так и не узнал.


  1. Alexxius
    25.08.2016 20:56

    В Windows, начиная с Win7 переключение языков можно повесить на сочетания ctrl + 1… ctrl + 0, До Win7 это делалось через alt + shift + цифра. У меня 5 языков и прекрасно работает.


  1. Spiritschaser
    25.08.2016 22:16
    +1

    > на маке переключение языков происходит между двумя последними использовавшимися.
    Кстати, на винде есть переключение языков И клавиатур.
    Например:
    Французский язык с французской и английской клавиатурами
    Русский язык с русской и английской клавиатурами
    Эстонский язык с эстонской и английской клавиатурами

    Такое использование полностью меняет user experience.


  1. Kuprijan
    26.08.2016 00:37

    Что-то не вижу, — где на Win10 можно назначать сочетания клавиш — очень помогло бы — как и писал автор — 4 раскладки не хухры мухры… (Русский, татарский (иногда приходится писать на нём), английский и японский (изучаю его, и порой бывает нужно написать на нём что-то, да и вообще Japanese IME прикольная чтука)


    1. LoadRunner
      26.08.2016 09:25

      Там же, где и в любой другой Windows:

      Панель управления - Язык - Дополнительные параметры - Изменить сочетания клавиш языковой панели


  1. Myrddin
    31.08.2016 00:43

    Спасибо за утилитку — сам после мака с трудом привыкаю к виндовому переключению.

    С удивлением обнаружил, что системные комбинации срабатывают даже при последовательном нажатии с очень маленькой задержкой. С еще бОльшим удивлением обнаружил, что примерно в 80 % случаев, я именно последовательно их и нажимаю. Соответсвенно при использовании утилиты часто вместо смены языка открывается меню пуск. Я — единственный с таким рассинхроном?