Предистория

Этот cказ о том, как мне надоело приглядываться к раскладке клавиатуры, и я решил проблему попутно освоив нестолько фичей в программировании и не только

Есть одна маленькая, но изматывающая боль, знакомая почти каждому, кто много печатает. Ты смотришь на экран, пальцы уверенно бегут по клавиатуре, мысль сформулирована… и на выходе получается:

ghbdtn
ytt gjyzk
plfybt yf rjywt

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

  • Прищуриться

  • Найти индикатор

  • Осознать ошибку

  • Нажать SUPER_ПРОБЕЛ или Alt+Shift

  • Перепечатать

  • Вздохнуть

И так — десятки раз в день. В какой-то момент я понял: я не обязан так жить.

Идея

Я захотел простую вещь: не угадывать, какая раскладка включена не искать глазами мелкий индикатор не ломать поток мысли А просто сразу понимать, на каком языке я печатаю.

Решение

Сделать лампу, которая:

  • явно и наглядно показывает текущую раскладку

  • видна сразу, без фокусировки взгляда

  • не мешает работе

  • не требует каждый раз думать о ней

Теперь раскладка:

  • сообщает о себе сама

  • не требует внимания

  • не превращает набор текста в мини-квест

Результат

  • Больше нет ghbdtn вместо «привет»

  • Больше нет случайных заклинаний в коде

  • Больше нет лишних пауз и раздражения

SUPER_ПРОБЕЛ снова просто сочетание клавиш, а не лотерея

Пальцы печатают. Голова думает. Глаза отдыхают.

Зачем этот проект

Потому что:

  • это реально мешает работе

  • это проблема, которую все терпят

  • её можно решить один раз и забыть

Если ты когда-нибудь:

  • печатал абракадабру из-за раскладки

  • злился на себя за «опять не посмотрел»

  • ххотел, чтобы компьютер был чуть внимательнее к тебе

  • значит, ты - целевая аудитория.

Эпилог

«Обойдемся без эпилога, далее - подробное описание проекта со схемами и исходниками».

KeyLamp

Описание проекта

KeyLamp — это проект, который сочетает аппаратную и программную части для создания устройства, показывающего текущую раскладку клавиатуры с помощью RGB-светодиода. Система состоит из нескольких компонентов, которые работают совместно для обеспечения удобного отображения состояния клавиатуры в реальном времени.

Цель — предоставить удобный индикатор раскладки клавиатуры в виде лампы, управляемой через USB-соединение, которая изменяет цвет в зависимости от текущей раскладки (например, us для английской раскладки и ru для русской).

Как это выглядит:

KeyLanmpVideo
KeyLampVideo

Проект включает следующие компоненты:

  1. Python-сервис для отслеживания раскладки клавиатуры в Linux и управления подключенным устройством.

  2. Arduino-скетч для управления RGB-светодиодами, отображающими цвет текущей раскладки.

  3. GNOME-плагин для интеграции с GNOME Shell и обмена данными о раскладке через D-Bus.

  4. Изготовление корпуса (или аналогичная физическая часть), которая представляет собой корпус устройства, куда устанавливаются компоненты.


Архитектура

1. Сборка электронной схемы и Arduino-скетч

  • Описание: Инструкция по сборке электронной схемы лампы и Скетч для Arduino, который управляет RGB-светодиодом, меняя цвет в зависимости от полученных через последовательный порт данных.

  • Основные задачи:

    • Получение данных о цвете от Python-сервиса через последовательный порт.

    • Управление RGB-светодиодами для отображения цвета.

Клонируй репозиторий и читай README.md

git clone https://github.com/lshnls/keylamp-arduino.git

2. GNOME Shell plugin

  • Описание: Расширение для GNOME Shell, которое отслеживает текущую раскладку клавиатуры и передаёт эти данные через D-Bus в другие приложения.

  • Задачи:

    • Слушает изменения раскладки клавиатуры.

    • Отправляет события через D-Bus, чтобы другие компоненты (например, Python-сервис) могли использовать эти данные.

Клонируй репозиторий и читай README.md

git clone https://github.com/lshnls/keylamp-gnome-plugin.git

3. Python-сервис

  • Описание: Python-скрипт, который отслеживает изменения раскладки клавиатуры через D-Bus и отправляет соответствующий код цвета в Arduino.

  • Задачи:

    • Подключение к D-Bus GNOME для отслеживания раскладки.

    • Отправка кодов цветов по USB через последовательный порт.

    • Поддержка нескольких раскладок и цветов.\

Клонируй репозиторий и читай README.md

git clone https://github.com/lshnls/keylamp-python-service.git

4. Сборка схемы и изготовление корпуса

  • Описание: Физический корпус, в который размещаются все компоненты (Arduino, светодиоды и другие элементы). Куб или аналогичная форма — это решение для компактного и эстетичного размещения устройства.

  • Задачи:

    • Создание схемы электронного устройства

    • Защита электронных компонентов.

    • Создание удобного и функционального вида устройства.

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

Материалы:

  • Эпоксидная смола

  • Диффузиант

  • Силиконовая форма куба 7x7x7 см.

  • Защитные перчатки и маска при работе с химическими веществами

Советы:

  • Используйте эпоксидную смолу для больших объемов заливки (от 70 мм.)

  • Тщательно перемешивайте компоненты смолы и диффузиант, удалите пузыри с помощью технического фена.

  • USB кабель подключите перед заливкой, а его конец погрузите в смолу вместе с собранной ранее схемой arduino (неразъемное соединение будет надежнее).


Лицензия

MIT License — используй, дорабатывай, улучшай.

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


  1. jarkevithwlad
    09.02.2026 19:05

    а идея то хороша, можно привязать к rgb подсветке внутри пк, что бы не делать спец лампу
    p.s. недавно захотел себе сделать переключение языка по КАПСУ в win 11 и пришлось свой вариант написать, а то на autohotkey античит Battlefield 6 жаловался...

    source (с#)

    да писала нейронка, но работает безотказно, вроде как последняя версия (если не ошибся с файлом), а затем для exe делаем автозапуск от админа и работает везде (во всех окнах и приложениях)

    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    class Program
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int VK_CAPITAL = 0x14;
    
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;
    
        static void Main()
        {
            TurnOffCapsLock();
    
            _hookID = SetHook(_proc);
    
            MSG msg;
            while (GetMessage(out msg, IntPtr.Zero, 0, 0))
            {
                TranslateMessage(ref msg);
                DispatchMessage(ref msg);
            }
    
            UnhookWindowsHookEx(_hookID);
        }
    
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
    
                if (vkCode == VK_CAPITAL)
                {
                    SendAltShift();
                    return (IntPtr)1;
                }
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
    
        private static void SendAltShift()
        {
            keybd_event(0x12, 0, 0, 0);
            keybd_event(0x10, 0, 0, 0);
            keybd_event(0x10, 0, 0x0002, 0);
            keybd_event(0x12, 0, 0x0002, 0);
        }
    
        private static void TurnOffCapsLock()
        {
            if ((GetKeyState(VK_CAPITAL) & 0x0001) != 0)
            {
                keybd_event(VK_CAPITAL, 0x45, 0, 0);
                keybd_event(VK_CAPITAL, 0x45, 0x0002, 0);
            }
        }
    
        private static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }
    
        private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
    
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
    
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);
    
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);
    
        [DllImport("user32.dll")]
        static extern bool GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
    
        [DllImport("user32.dll")]
        static extern bool TranslateMessage([In] ref MSG lpMsg);
    
        [DllImport("user32.dll")]
        static extern IntPtr DispatchMessage([In] ref MSG lpMsg);
    
        [DllImport("user32.dll")]
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
    
        [DllImport("user32.dll")]
        static extern short GetKeyState(int nVirtKey);
    
        [StructLayout(LayoutKind.Sequential)]
        public struct MSG
        {
            public IntPtr hwnd;
            public uint message;
            public IntPtr wParam;
            public IntPtr lParam;
            public uint time;
            public Point pt;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct Point
        {
            public int x;
            public int y;
        }
    }
    


    1. Lshnls Автор
      09.02.2026 19:05

      Можно переключать подсветку клавиатуры, но моя клавиатура, к сожалению без RGB


  1. UniInter
    09.02.2026 19:05

    Прикольно, конечно. Но неужели человек не знаком с Punto Switcher?


    1. Lshnls Автор
      09.02.2026 19:05

      Вполне знаком, но для меня не подходит.

      Самая боль:

      • переключает язык не вовремя,

      • ломает пароли,

      • путается в аббревиатурах и коде.
        В итоге править текст вручную быстрее, чем “умный” алгоритм.

      • подозрения в слежке? Доверяете ему пароли?


      1. UniInter
        09.02.2026 19:05

        Твои боли в программе купируются:

        | переключает язык не вовремя
        Предусмотрено отключение автоматического переключения (остается только по горячим клавишам).

        | ломает пароли
        Предусмотрено отключение Punto в избранных программах.

        | путается в аббревиатурах
        Предусмотрено ведение словаря слов, на какие не реагировать.

        | подозрения в слежке
        Использую версию Punto до ее покупки Яндексом. Подозрений нет.

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


        1. Lshnls Автор
          09.02.2026 19:05

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


          1. dedmagic
            09.02.2026 19:05

            Так, ещё раз -- можно ОТКЛЮЧИТЬ автопереключение раскладки, что убирает все Ваши проблемы, в т.ч. непредсказуемость ввода.

            В этом случае Punto Switcher используется в двух случаях:
            - если вы начали набирать в неправильной раскладке и сразу (в пределах одного слова) это увидели - нажимаете Pause;
            - если набрано уже много слов в неправильной раскладке - выделяете этот текст и нажимаете Shift+Pause.
            В обоих случаях текст "чинится", ещё и переключение в нужную раскладку происходит.


  1. andreymal
    09.02.2026 19:05

    там, в углу экрана, мелким шрифтом притаилась надпись EN или RU

    setxkbmap -option grp_led:scroll


    1. 0xdead926e
      09.02.2026 19:05

      и какой-нибудь echo kbd-scrolllock > /sys/class/leds/чопопало/trigger, да.

      правда возможно сначала придется написать этому чемупопало драйвер светодиода.


    1. Lshnls Автор
      09.02.2026 19:05

      У меня нет индикатора Scroll Lock на клавиатуре :)


  1. LinkToOS
    09.02.2026 19:05

    Слушает изменения раскладки клавиатуры.

    В реальном времени? Или по событию (нажатие клавиш, переключение окон)?


    1. Lshnls Автор
      09.02.2026 19:05

      Плагин для Gnome генерирует DBUS событие при переключении раскладки. Служба на основе программы на python ждет события переключения и дает сигнал на смену цвета в контроллер arduino


      1. LinkToOS
        09.02.2026 19:05

        По событию читается (передается в качестве аргумента) реальное состояние раскладки, или происходит изменение цвета относительно предыдущего запомненного состояния?
        Если переключаются два окна, в которых разные раскладки, это событие отрабатывается?


        1. Lshnls Автор
          09.02.2026 19:05

          Передается реальное состояние раскладки. Если настроены разные раскладки для разных окон, то при переходе от одного окна к другому цвет меняется.


  1. mikhailushakov
    09.02.2026 19:05

    Ну, в целом довольно неплохо, а предусмотрено ли то, что языков в раскладке будет не 2, а допустим, мне ещё периодически нужны всякие умляуты или ещё что-то более специфическое


    1. Lshnls Автор
      09.02.2026 19:05

      В плагин и программу легко добавить дополнительные языки и коды цветов для RGB-светодиода.


  1. alcotel
    09.02.2026 19:05

    Кубик красивый получился, тоже попробую как-нибудь такой собрать.

    Для RGB-светодиода не обязательно целую ардуину ставить. Достаточно одного адаптера USB-RS485. Требование к адаптеру: он должен работать в 7-битном режиме на скорости 3 Мбит/с. Например, FTDI.


    1. Lshnls Автор
      09.02.2026 19:05

      Так-же можно использовать вместо 3-х резисторов 1, если взять Адресный светодиод WS2812B


      1. alcotel
        09.02.2026 19:05

        Да, я адресный и имел в виду. Уже потом на гитхабе схему увидел.


  1. maxidler
    09.02.2026 19:05

    Идея красивая. Но я уже лет 15 пользуюсь более практичным решением. Когда смотришь на экран, а не на клавиатуру - максимум, что успеваешь набрать в неправильной раскладке - 3 символа. Более того, я все эти годы, на всех ОС настраиваю переключение раскладки по CapsLock (ну а для чего она еще нужна?), и лампочка на кнопке показывает мне раскладку. Тут правда возникнут проблемы у тех, кто использует более двух раскладок.


    1. Lshnls Автор
      09.02.2026 19:05

      Когда вводишь пароль или слово начинается с 'C" это не работает :)


  1. dedmagic
    09.02.2026 19:05

    А не надо высматривать мелкий текст на экране – у меня вот прямо сейчас вообще индикация раскладки отсутствует (спрятана).
    Нужно просто вместо ПЕРЕКЛЮЧЕНИЯ раскладки использовать два разных хоткея для ВКЛЮЧЕНИЯ нужной (En/Ru). В этом случае перед началом набора просто тыкается нужный хоткей, и, независимо от того, какая раскладка была до этого, набор начинается в правильной.

    В Windows это можно сделать даже стандартными средствами системы, но там очень неудобные (для меня) варианты предлагаются, поэтому я использую Punto Switcher (En на левом Ctrl, Ru на правом).


  1. DungeonLords
    09.02.2026 19:05

    Оффтоп. Почему не получила распространение моя идея? Выделив текст и переключив раскладку, получаем смену раскладки для уже напечатанного текста.


    1. dedmagic
      09.02.2026 19:05

      Punto Switcher, Shift+Pause


  1. slair
    09.02.2026 19:05

    есть православная xneur, может озвучивать нажатия
    то есть без всякой индикации, на слух можно понять в какой раскладке производится ввод
    само собой, автопереключение — зло, отключаю всегда во всяких punto/ninja/xneur

    одна беда, что делать, когда придёт wayland