Переключатель раскладки клавиатуры по принципу OS X
Исходники программы доступны по адресу 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 или кто просто изучает программирование.
Комментарии (2)
25 августа 2016 в 08:05
0↑
↓
MacSwitch.exe не является приложением Win32.Это только у меня?
25 августа 2016 в 08:32
0↑
↓
но лично я знаю людей, у которых 4 языка это норма и для них переключение языков доставляет некоторые неудобства из-за чего выбирать нужный язык приходится кликом мышки, а не комбинацией кнопок.
Не знаю, как вы пользуетесь тремя и более языками, но способ OS X мне кажется как раз неудобным. У меня, например, три активных языка, и в то короткое время, когда я пользовался маком, весьма раздражало, что я не мог произвольно переключать между языками простым сочетанием клавиш — нужно смотреть на экран и выбирать язык (если он не в списке последних двух).
В Windows сочетание типа alt+shift переключает языки по кругу, а ещё можно задать конкретное сочетание для конкретного языка, например, LeftAlt+Shift+1.