[LINUX] XIM (X Input Method) Japanischer Eingabefluss

Erstellt im März 2018

"Was ist der japanische Eingang des X Window Systems?" Der Autor, der dies glaubte, untersuchte den Fluss japanischer Beiträge. Dies ist ein Satz über C-Sprache und X11-Programmierung. Verwendetes Betriebssystem: ubuntu16.04

Programme, die keine japanische Eingabe unterstützen

Erstellen Sie zunächst ein Programm zur Eingabe von Zeichen über die Tastatur.

example01.c


#include <stdio.h>
#include <locale.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

int main(void)
{
    Display* dpy = XOpenDisplay(NULL);

    Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 100, 100, 0, 0, 0);
    XMapRaised(dpy, win);
    XSync(dpy, False);

    XSelectInput(dpy, win, KeyPressMask | KeyReleaseMask);

    XEvent ev = {};
    while(1){
        XNextEvent(dpy, &ev);
        switch(ev.type){
            case KeyPress: {
                KeySym keysym = NoSymbol;
                char text[1024] = {};

				XLookupString((XKeyEvent *)&ev, text, sizeof(text) - 1, &keysym, NULL);
                printf("Got chars: (%s)\n", text);
				
                if(keysym == XK_Escape){
                    puts("Exiting because escape was pressed.");
                    return 0;
                }

            }
			break;
        }
    }

	return 0;
}

Die Kompilierungsparameter sind wie folgt. gcc -o example01 example01.c -lX11

Wenn Sie es von einem Terminalemulator (z. B. einem GNOME-Terminal) kompilieren und ausführen, werden die Zeichen, die Sie in das Fenster eingeben, einfach auf dem Terminalemulator gedruckt.

Programm, das japanische Eingaben unterstützt

Dieses Programm ist eine Verbesserung des obigen Programms, um japanische Eingaben zu ermöglichen.

example02.c


#include <stdio.h>
#include <locale.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

int main(void){

#if 1
    setlocale(LC_ALL, "");
#endif

    Display* dpy = XOpenDisplay(NULL);

    Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 100, 100, 0, 0, 0);
    XMapRaised(dpy, win);
    XSync(dpy, False);

#if 1
    XSetLocaleModifiers("");

    XIM xim = XOpenIM(dpy, 0, 0, 0);
    if(!xim){
        // fallback to internal input method
        XSetLocaleModifiers("@im=none");
        xim = XOpenIM(dpy, 0, 0, 0);
    }

    XIC xic = XCreateIC(xim,
                        XNInputStyle,   XIMPreeditNothing | XIMStatusNothing,
                        XNClientWindow, win,
                        XNFocusWindow,  win,
                        NULL);
    XSetICFocus(xic);
#endif

    XSelectInput(dpy, win, KeyPressMask | KeyReleaseMask);

    XEvent ev = {};
    while(1){
        XNextEvent(dpy, &ev);

#if 1
        if(XFilterEvent(&ev, None) == True) continue;
#endif

        switch(ev.type){
            case KeyPress: {
                KeySym keysym = NoSymbol;
                char text[1024] = {};

#if 1
                Xutf8LookupString(xic, &ev.xkey, text, sizeof(text) - 1, &keysym, NULL);
                printf("Got chars: (%s)\n", text);
#else 
				XLookupString((XKeyEvent *)&ev, text, sizeof(text) - 1, &keysym, NULL);
                printf("Got chars: (%s)\n", text);
#endif
				

                // example of responding to a key
                if(keysym == XK_Escape){
                    puts("Exiting because escape was pressed.");
                    return 0;
                }
            }
            break;
        }
    }

  return 0;

}

Die Kompilierungsparameter sind wie folgt. gcc -o example02 example02.c -lX11

Wenn Sie Japanisch in das X11-Programm eingeben können (z. B. xterm), können Sie auch Japanisch in dieses Programm eingeben. (Referenz-URL für dieses Programm https://gist.github.com/baines/5a49f1334281b2685af5dcae81a6fa8a)

Ich habe dem Programm einige Funktionen hinzugefügt, aber es gibt vier Funktionen, die in direktem Zusammenhang mit dem IM-Server stehen.

  XIM xim = XOpenIM()	//Stellen Sie mit dem XIM-Protokoll eine Verbindung zum IM-Server her
  XIC xic = XCreateIC()	//Erstellen eines Kontexts mit dem IM-Server
  XSetICFocus()         //Fokus setzen
  XFilterEvent()	//Ereignis an IM-Server senden

Anschließend wird das Schlüsselereignis auf zwei Arten mit dem IM-Server ausgetauscht.

  XNextEvent()        //Empfangen Sie Ereignisse vom IM-Server
  XFilterEvent()      //Senden Sie ein Ereignis an den IM-Server

(IM-Server bezieht sich auf fcitx, ibus usw.)

Grober Fluss japanischer Eingaben

図.gif

Wie gezeigt, empfängt das X11-Programm das Schlüsselereignis mit der XNextEvent-Funktion und entscheidet, ob das Ereignis mit der XFilterEvent-Funktion an den IM-Server gesendet wird. Wenn die XFilterEvent-Funktion das Ereignis an den IM-Server sendet, gibt sie den Rückgabewert als True zurück.

Das X11-Programm empfängt mithilfe der XNextEvent-Funktion auch wichtige Ereignisse vom IM-Server. Selbst wenn Sie das Ereignis von diesem IM-Server an die XFilterEvent-Funktion übergeben, wird der Rückgabewert als False zurückgegeben und nicht erneut an den IM-Server gesendet.

(Die Interaktion zwischen IM-Server und IME wird in diesem Artikel nicht erwähnt.)

IM-Server

Gehen wir etwas tiefer und informieren uns über den IM-Server. Der IM-Server wird mit einer Funktion namens IMdkit implementiert. Ich habe den Programmcode unter der folgenden URL gefunden, aber er wird nicht gepflegt und es wird ein Kompilierungsfehler angezeigt. https://www.x.org/releases/unsupported/lib/IMdkit/

Bei der weiteren Suche stellte ich fest, dass ibus und fcitx die IMdkit-Funktion mit ihren eigenen Änderungen verwenden, und ich konnte die IMdkit-Quelle von der folgenden URL herunterladen. https://github.com/fcitx/fcitx/tree/master/src/frontend/xim/lib

Das Beispielprogramm des IM-Servers wurde von der folgenden URL heruntergeladen. https://www.x.org/releases/unsupported/lib/IMdkit/Xi18n_sample/

Kompilieren von sampleIM (IM-Server)

Da der heruntergeladene Programmcode nicht so kompiliert werden kann, wie er ist, habe ich ein IMdkit und einen Beispiel-IM-Server mit einigen Änderungen unter der folgenden URL vorbereitet. http://ai56go.ivory.ne.jp/sample/sampleIM.zip

Extrahieren Sie diese Zip-Datei und Sie finden das Build-Verzeichnis. Wechseln Sie in dieses Build-Verzeichnis und geben Sie den folgenden Befehl ein, um das sampleIM-Programm zu erstellen.

chmod 755 build.sh
chmod 755 build2.sh
./build.sh
./build2.sh

(Da der Quellcode von sampleIM.c alt ist, werden viele Warnmeldungen angezeigt, aber das sampleIM-Programm wird erstellt.)

Ausführung von sampleIM (IM-Server)

export XMODIFIERS=@im=sampleIM
./sampleIM &
xterm

So starten Sie xterm, indem Sie in der richtigen Reihenfolge eingeben. (Wenn Sie den Hinweis xterm nicht haben, verwenden Sie stattdessen das oben eingeführte Beispiel 02. GNOME-Terminals usw. kommunizieren mit dem IM-Server über andere Methoden als XIM, sodass Sie ihn hier nicht verwenden können.)

Wenn Sie in xterm "Shift + Leertaste" eingeben und dann einen Buchstaben über die Tastatur eingeben, Die im Terminalemulator eingegebenen Zeichen, mit denen sampleIM gestartet wurde, werden angezeigt. Im Fall eines tatsächlichen IM-Servers kommuniziert er zu diesem Zeitpunkt mit dem IME, um die japanische Konvertierung zu verarbeiten.

Wenn Sie "Strg + K" eingeben "" Dies ist eine bestimmte Zeichenfolge aus IM. "" Und sie wird in xterm angezeigt. Durch Eingabe von "Shift + Leertaste" am Ende können Sie Zeichen in xterm normal eingeben.

Dieses BeispielIM Shift + Space Schaltereingang Strg + k bestätigt Da es jedoch nicht in Japanisch konvertiert wird, ist die durch Bestätigung zurückgegebene Zeichenfolge immer dieselbe.

Um sampleIM zu beenden, überprüfen Sie die Prozess-ID mit ps und beenden Sie sie wie unten gezeigt.

ps | grep sampleIM
kill (Prozess ID)

Erklärung von sampleIM

Dieses sampleIM hat die Mindestfunktionen als IM-Server. Die japanische Konvertierung ist ein IME-Job, daher werde ich in diesem Artikel nicht darauf eingehen.

Betrachtet man die Funktionsweise von sampleIM aus Sicht des Programms, Zunächst in Zeile 398 von sampleIM.c     ims = IMOpenIM(dpy, Es gibt und der IM-Server wird initialisiert. Zeile 401 als Argument dieser IMOpenIM-Funktion     IMServerName, imname, Es gibt. Dieser imname Wert ist "sampleIM" Es muss mit dem oben eingegebenen Wert von "export XMODIFIERS = @ im = sampleIM" übereinstimmen.

Dann auf Linie 425     IMProtocolHandler, MyProtoHandler, Und geben Sie die Rückruffunktion an (hier MyProtoHandler-Funktion).

Dann von 440 Zeilen     XNextEvent(dpy, &event); Empfängt ein Schlüsselereignis von einem X11-Programm (z. B. xterm) und Zeile 441 nur, wenn das Ereignis aus einem X11-Programm stammt     if (XFilterEvent(&event, None) == True)       continue; Die XFilterEvent-Funktion von heißt MyProtoHandler-Funktion, gibt True als Rückgabewert zurück und fährt fort.

249 Zeilen     MyProtoHandler(ims, call_data) Führt die Verarbeitung als IM-Server durch. Wenn sampleIM angereichert ist, wird diese MyProtoHandler-Funktion angereichert.

Die API von IMdkit wird in der folgenden URL beschrieben. https://www.x.org/releases/unsupported/lib/IMdkit/doc/API.text

Die von IMdkit benötigten Funktionen sind wie folgt und nicht viele.

XIMS IMOpenIM(Display display,...)
char *IMSetIMValues(XIMS ims,...)
char *IMGetIMValues(XIMS ims,...)
void IMCloseIM(XIMS ims)
int IMPreeditStart(XIMS ims, XPointer im_protocol)
int IMPreeditEnd(XIMS ims, XPointer im_protocol)
void IMForwardEvent(XIMS ims, XPointer im_protocol)
void IMCommitString(XIMS ims, XPointer im_protocol)
int IMCallCallback(XIMS ims, XPointer im_protocol)

Schließlich

Dieser Satz erklärte den Fluss der japanischen Eingabe mit XIM. -Einführung einer Funktion (Beispielprogramm) zur Eingabe von Japanisch.

Recommended Posts

XIM (X Input Method) Japanischer Eingabefluss
Japanische Eingabe mit Pyautogui