Каретка, как индикатор текущей раскладки

Есть хорошая тема, показывать текущую раскладку цветом каретки. Каретка — это та мигающая палочка, из которой вылезает текст, если что. А курсор — это мышиный указатель. По крайней мере, в терминах ресурсов Windows. Но для пользователей и она в большинстве случаев — курсор.

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

Я впервые прочитал о таком способе индикации на сайте Артёма Горбунова а Илья Бирман тут рассказывает о своей реализации этой идеи на Маке.

Ну конечно, я примерил идею на винду. Что мы имеем в смысле её реализации средствами WinAPI? Виндоус умеет создавать 3 типа кареток: линию (горизонтальную и вертикальную), блок и пользовательский битмап. Созданная каретка рисуется инвертированным цветом фона, точнее not (bgcolor xor bgcolor).

Первое, что приходит в голову, это старый добрый хук на смену раскладки и последующее создание каретки нужного цвета от имени текущего приложения. Но не тут-то было. Это вопрос, который приоткрывает завесу того борделя, который творится в написании приложений третьими (а также вторыми и даже первыми) разработчиками. Word, например, должен как-то рисовать мигающую палку на пол-экрана, когда кто-нибудь захочет сделать масштаб 400% и шрифт 72 размера. Он не пользуется системной функцией отображения каретки, он сам рисует свои палки, а каретку стыдливо прячет. Я нагло внедрился к нему в процесс и просто попросил показать каретку, он этого явно не ожидал и на клиентской части окна стал появляться нестёртый мусор.

Редакторы, сделанные на Java, вообще чихать хотели на системную каретку и настройку частоты её мигания. Они рисуют там что-то свое, мигающее по собственному таймеру. Список можно продолжать. Чего стоят одни браузеры со своими элементами формы и собственным видением единственно православной каретки.

Так что CreateCaret от имени приложения не годится, потому что неизвестно, какую каретку создавать. Может у приложения вот такая каретка в виде бабочки, как узнать хандлу этого битмапа? Нет, промышленное решение из этого не получится, один гнусный хакинг. Хотя (вроде бы) Aml Maple умеет красить карету в разные цвета, но я не проверял.

Я думал и об окне, плавающем рядом с кареткой, но такой подход может вызвать у многих пользователей эпилепсию. Ещё неплохая, по-моему, мысль, рисовать прямо на захученном окне средствами GDI, только приложение после переключения всё равно нарисует своё барахло, а чтобы постоянно перерисовывать каретку нужным цветом нужно в адресном пространстве каждого процесса оставлять дополнительный поток, что ли — вот приложения обрадуются!

Ну хорошо, давайте подумаем. Задача состоит в том, чтобы не косить глаза в угол монитора, а по виду самой каретки определить текущий язык.

Предусмотреть все варианты отображения кареток в разных приложениях условно нереально. Что остается?

Частота мерцания!

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

Частота мерцания курсора — это законный параметр винды, в панели управления:

Управляется функциями SetCaretBlinkTime, GetCaretBlinkTime.

Итак: делаю службу, которая загружает длл с хуком для события на переключение раскладки. А в hook-функции написано, к примеру:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
LRESULT CALLBACK hookProc (int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0)
    {
        if (nCode == HSHELL_LANGUAGE)
        {
            LANGID inputLang = LOWORD (lParam);

            char szLocaleData [255];
            GetLocaleInfo (inputLang,
                           LOCALE_SENGLANGUAGE,
                           szLocaleData, sizeof (szLocaleData));
           
            if (_tcscmp (szLocaleData, _T("Russian")) == 0)
            {
                SetCaretBlinkTime (200); // ну к примеру
            }
            else
            {
                SetCaretBlinkTime (1000); // к примеру
            }
        }
    }

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

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

blink.zip (90 Кб)

В архиве 4 файла:

blink.exe служба
blink.dll длл-ка с хуком
install.bat регистрирует и стартует службу(должен лежать и запускаться из той же папки, где лежит blink.exe)
uninstall.bat останавливает и удаляет службу

Ничего в реестр не пишется, ведётся лог в темповой папке.

Для установки нужно запустить install.bat. Для удаления uninstall.bat. Это оригинально. Как и предупреждение о том, что я, как и все разработчики, снимаю с себя всякую ответственность за вашу карму и возможные стихийные бедствия, источником которых (как вы можете подумать) может стать это ПО. Могу добавить, что работает все стабильно (у меня дома и на работе на 2-х машинах). Софтина делает то же, что и апплет панели управления, не больше.

После удаления службы вы всегда можете в панели управления установить обратно свою частоту мерцания курсора. Пробовал в W2k, XP. (upd: попробовал в Висте — не работает, может быть, займусь этим).

Но! Во многих прогах частота мерцания каретки не изменяется из-за описанных выше причин. Некоторые окна нуждаются в деактивации/активации, чтобы изменения частоты вступили в силу. В настоящих виндюшных эдит-боксах все без проблем, в визуал студии тоже, в общем, хотите — посмотрите.

И в заключение на тему индикации текущей раскладки:

ЭТО ВСЁ ВООБЩЕ НЕ НУЖНО, ПОКА ЕСТЬ PUNTO SWITCHER

Спасибо за внимание.

UPD:

Посмотрел Маплю. Всё ясно. Создаёт каретку и показывает её. В ворде такое же поведение, как я наблюдал (остаётся мусор):
maplja

Java-проги тоже игнорируют её. Это не годится. Это вина не Мапли, просто надо думать дальше.

12.05.2009 • Метки:  • Рубрики: Разработка ПО

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

  1. Семеныч 13.05.2009 07:34

    Ну мигает, да.Только зачем? Пунтосвичер все решает, имхо

  2. Yanis 13.05.2009 09:26

    2 Семеныч
    А что решает Пунто? По моему он решает проблему преобразования текста напечатанного в неверной раскладке. А требуется индикация текущей раскладки. Это разные задачи, хоть и решают в конечном итоге одну и ту же проблему.

  3. Павел Малинников 13.05.2009 12:34

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

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

  4. Алисей 13.05.2009 19:30

    Что если в зависимости от раскладки менять цвет панели задач? Это возможно сделать? Я пробовал Maple, но когда занят своими делами глаз не успевает схватывать цвет такого маленького кусочка, идея не работает.

  5. Павел Малинников 13.05.2009 23:21

    Смена цвета панели задач, по-моему, неплохая идея, гораздо заметнее, чем [Ru] в углу экрана. Может быть, немного крамольно вторгаться в цветовое пространство пользователя, но можно было бы не красным цветом красить, а выполнить в какой-нибудь приличной гамме, вынести цвета в настройку.

    Насчёт реализации — можно попробовать, в рамках того же этюда. Кстати, вы пробовали его запускать?

  6. Павел Малинников 13.05.2009 23:29

    Ещё, можно было бы цвет заголовка окна менять в зависимости от языка. Правда, тоже может быть далековато от каретки.

  7. Алисей 14.05.2009 19:18

    Попробовал сегодня попользоваться день. Эта индикация приятнее, чем смена цвета курсора. Заработала даже в терминале!
    Но всё равно происходят ошибки. Кликаю мышкой в поле ввода и тут же начинаю писать, одно действие следует за другим, без задержки на размышления о том, стоит ли сменить раскладку. Поэтому раскладку нужно знать ещё до того, как я перейду в поле ввода.
    Дальше, допустим, я уже ошибся, стёр букву, переключил раскладку. Но у переключателя в Windows есть интересная особенность - он глючит. Не могу понять как именно, может не реагирует на некоторые комбинации нажатий-отпусканий, факт в том, что иногда по четыре раза пытаешься переключиться, каждый раз стирая буквы. Всё это автоматически, потому что думаешь не о раскладке, а о том что пишешь.
    В некоторых ситуациях ввод происходит вообще без курсора - например поиск по первым буквам слова в файловом менеджере. Кажется что файла нет, но на самом деле выбрана неправильная раскладка.

    Пользуюсь Пунто Свитчером, автоматическое переключение раскладки отключено, потому что программировать иначе невозможно, раскладку последнего слова меняю по Pause/Break. Это удобно, но не решает всех проблем.
    Если решите провести эксперимент со сменой цвета панели задач/заголовка окна - это будет супер.

  8. Carc 08.06.2009 02:23

    М-да... Ворд конечно всю малину мне обломал в Мапле, но и это поправимо - да всё никак руки не дойдут. На сейчас немного с новой версий 2.30 расквитаюсь, и можно поковырять каретку поосновательнее - благо мысли кое-какие есть, как побеждать этот мусор.

  9. ArtIMen 09.01.2010 20:13

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

    Как где-то подсмотрел "сорри, что воспользовался статьёй не по назначению".

  10. Павел Малинников 09.01.2010 21:02

    2 ArtIMen:

    Да, sc полезная штука. Но екзешник должен быть сделан, как служба. Хотя, через Srvany можно запустить как службу любой екзешник.

  11. Программер 27.01.2011 11:33

    Ваше много писанины, равно как и идея Пунто свитчера, убиваются одним фактом: у меня ЧЕТЫРЕ раскладки клавиатуры и переключаю я их комбинациями от Alt-Shift-1 до Alt-Shift-4. Вот тогда и понимаешь, как это всё жутко неудобно.

  12. Совсем не программер 09.08.2012 08:35

    У меня тоже 4 раскладки и это до жути неудобно, пунто свитчер давно оключен, не распознает языки. Короче с проблемой и неудобствами почти смирилась m(=_=')m...

    Павел Малинников

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

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

  13. Timeon 20.10.2012 15:11

    Интересная реализация. Пользовался AmlMaple но при автозагрузке почему-то вместе с ним другие программы часто некорректно загружаются. Я не очень разбирался почему это происходит, но когда удалил его все стало нормально. Сам сейчас пишу прогу которая как пунто свитчер отображает флаг страны в области уведомлений, но больше ничего не делает. И хочу сделать чтоб она распознавала вообще все раскладки которые есть в Windows.

Ваш комментарий:

 

 


Только просмотр (без публикации)