?

Log in

No account? Create an account

Emacs input method и иксовый переключатель раскладки клавиатуры - БЭСМ-6

2004, Apr 5

16:48:00 - Emacs input method и иксовый переключатель раскладки клавиатуры

Share Next Entry

Опубликовано также в флеймерской эхе RU.GNU.

По некотором исследовании emacs я осознал, что его внутренний переключатель раскладок (у него раскладка называется input method) гораздо лучше, чем родной иксовый тем, что соображает, в каком месте редактора я нахожусь, и включает/выключает интерпретацию другой раскладки соответственно. Особенно актуально это стало тогда, когда в свежих xlib от XFree86 Ctrl-русская_буква перестало работать как Ctrl-клавиатурно_соответствующая_латинская_буква. Чтобы ввести какую-нибудь команду, стало нужно переключаться на латиницу. Задалбывает, однако.

Если пользоваться емаксовым переключателем как есть, то задалбывает другое - в emacs и в других программах переключатель разный. Вернее, переключатели - я предпочитаю на кириллицу и на латиницу переключаться разными жестами. Логика очевидна (и я в упор не понимаю, почему люди пользуются переключателями типа toggle) - если я знаю, в какой раскладке я собираюсь набирать следующее слово (а я, как ни странно, обычно таки знаю), мне уже не нужно соображать, в какой раскладке я сейчас - я просто переключаюсь на нужную.


Первая мысль, которая мне пришла в голову на эту тему - берем xxkb (я все равно им пользуюсь), указываем ему (в ~/.xxkbrc), что у emacs не надо переключать группу:

XXkb.app_list.wm_class_class.alt_group1: emacs Emacs


а емаксу, соответственно (в ~/.emacs) - что надо по ним переключать раскладку:

(global-set-key [key-12] '(lambda () (interactive) (inactivate-input-method)))
(global-set-key [S-key-14] '(lambda () (interactive) (unless current-input-method (toggle-input-method))))
(define-key isearch-mode-map [key-12] '(lambda () (interactive) (if current-input-method (isearch-toggle-input-method) (isearch-update))))
(define-key isearch-mode-map [S-key-14] '(lambda () (interactive) (if current-input-method (isearch-update) (isearch-toggle-input-method))))


(переключатель на латиницу у меня на ISO_First_Group, повешенной на CapsLock, emacs видит ее как key-12, на кириллицу - на ISO_Last_Group, повешенной на Shift-CapsLock, emacs видит ее как S-key-14).

Все довольно просто. И на Debian woody, в том числе и с пакетом XFree86 версии 4.2.1 (собирался ради адекватной реакции на псевдографику в xterm, доступен на 45.free.net), работает. Пробуем пустить на Debian sarge (с той же версией XFree, но иной версией пакета) - облом. Там в xlibs что-то поменяли (и я бы сказал, поменяли правильно), но в результате емаксу ISO_* не отдаются. Он их просто не видит.

Я страдал недели две, Ваня Паскаль (автор xxkb и самого внятного из известных мне изложений устройства XKB свидетель. И с помощью его советов я таки нашел счастье. Итак.

Спасает нас программа, которая видит клавиши на низком уровне и раньше всех - window manager. В моем случае - fvwm.

Для переключения в емаксе выбираем клавишу Multi_key - без модификаторов на латиницу, с Shift - на кириллицу. Выбор произволен - достаточно, чтобы emacs ее видел. Emacs ее видит как [space]. ruslat.c:

/* $Revision$
   Compile with
   gcc ruslat.c -L/usr/X11R6/lib -lX11 -o ~/bin/emacs_ruslat
*/
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <stdio.h>

int main (int argc, char **argv)
{
        long id;
        Display *dpy;
        XKeyEvent ev;
        if (argc < 3) {
                fprintf(stderr, "Usage: %s window_id r|l\n");
                return 1;
        }
        id = strtol(argv[1], NULL, 0);
        dpy = XOpenDisplay(NULL);
        ev.type = KeyPress;
        ev.window = id;
        ev.display = dpy;
        ev.root = RootWindow(dpy, DefaultScreen(dpy));
        ev.state = (argv[2][0]=='r'?ShiftMask:0);
        ev.keycode = XKeysymToKeycode(dpy, XK_Multi_key);
        if (!XSendEvent(dpy, id, False, 0,  (XEvent *)&ev)) return 2;
        XSync(dpy, False);
        ev.type = KeyRelease;
        if (!XSendEvent(dpy, id, False, 0,  (XEvent *)&ev)) return 2;
        XSync(dpy, False);
        if (argc >3) fprintf(stderr, "Passed %s to 0x%lx\n", argv[2], id);
        return 0;
}


~/.fvwm2rc:

DestroyFunc RusLat
AddToFunc RusLat
+ "I" Current (Emacs) Exec emacs_ruslat $[w.id] $0
# для fvwm 2.4.6, который в woody, надо вместо $[w.id] написать просто
# $w - я предпочел пересобрать 2.4.16 из sarge, заодно оторвав ему gtk.

Key ISO_First_Group	W	N	Function RusLat l
Key ISO_Last_Group	W	S	Function RusLat r


Внимание: на woody, если писать модификатор A, срабатывают оба назначения (что естественно - keycode-то один), и отрабатывает второе. На sarge, когда я поначалу перепутал порядок и написал A W, почему-то все работало; дальше проверять не стал. Поэтому модификаторы разные.

В .emacs прописываем то же самое, но меняем key-12 и key-14 на space.

Эффекты.



  1. При переключении раскладок происходит моргание (окно emacs
    на мгновение теряет фокус). Но меня это не очень раздражает. Даже
    немножко наоборот - есть визуальное подтверждение того, что раскладка
    сменилась, _в локусе внимания_. Еще можно цвет курсора поменять,
    наверное. Но лениво - он вряд ли локален для буфера по умолчанию...


  2. Более правильно было бы сделать emacs_ruslat не запускающимся
    каждый раз по нажатию на такую кнопку, а постоянно связанным с fvwm. Но
    пока лениво - на ноутбуке (P133) торможение от запуска незаметно. Со
    временем, может, и сделаю...


  3. Порой от такой жизни срывает крышу мозилле. Свежей, на gtk2. Закономерности пока не отследил. Срывает странно - то там все вообще отказывается переключаться, то переключается только после второго нажатия, причем после первого вообще отказываются вводиться буквы. Второе вроде бы прошло после того, как я добавил KeyRelease (до этого было только KeyPress), что крайне странно - на мозиллу-то оно не запускается... Update: не, нифига не прошло, естественно.




Current Mood: accomplished