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
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.
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.)
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.)
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/
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.)
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)
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)
Dieser Satz erklärte den Fluss der japanischen Eingabe mit XIM. -Einführung einer Funktion (Beispielprogramm) zur Eingabe von Japanisch.