L'histoire de l'affichage des personnages dans l'entrée japonaise de Kivy

En juillet 2018, la dernière version de Kivy (1.10.1) est sortie. Voici l'écran IME La demande d'extraction de contenu a été adoptée et IME fonctionne et le japonais en cours de saisie s'affiche.

Contenu

Bien qu'il s'agisse de la bibliothèque GUI de Python "Kivy", il existe un problème en raison du fait que le japonais (IME) ne s'affiche pas lors de la saisie du japonais dans l'entrée de texte dans l'environnement Windows / MacOS. Cette fois, nous avons étudié la raison pour laquelle il n'était pas affiché et avons pris des mesures pour le rendre visible. Le système d'exploitation de vérification est Windows.

Pourquoi le japonais n'est pas affiché

Tout d'abord, Kivy, comme illustré ci-dessous, la couche basse réalise diverses fonctions par des bibliothèques comme OpenGL.

architecture.png

Parmi eux, la saisie de caractères est réalisée en utilisant SDL.

Réalisation de la saisie de texte en SDL

La source est extraite du Tutoriel de l'entrée de texte SDL.


    SDL_StartTextInput();
    while (!done) {
        SDL_Event event;

        if (SDL_PollEvent(&event)) {
            switch (event.type) {
                case SDL_QUIT:
                    /*Fin*/
                    done = SDL_TRUE;
                    break;
                case SDL_TEXTINPUT:
                    /*Ajouter un nouveau texte à la fin du texte*/
                    strcat(text, event.text.text);
                    break;
                case SDL_TEXTEDITING:
                    /*
Mettre à jour le texte non converti.
Mettre à jour la position du curseur.
Convertir la longueur de la sélection(si possible).
                    */
                    composition = event.edit.text;
                    cursor = event.edit.start;
                    selection_len = event.edit.length;
                    break;
            }
        }
        Redraw();
    }

}

En regardant cela, vous pouvez voir que l'événement "SDL_TEXTINPUT" est émis lors de la saisie de caractères et que l'événement "SDL_TEXTEDITING" est émis lors de l'utilisation de l'IME.

À propos de la réception d'événements de SDL dans Kivy

Dans cet esprit, jetons un œil au [code source github] de kivy (https://github.com/kivy/kivy). C'est core / window / _window_sdl2.pyx Qui reçoit l'événement de SDL et le traite. pyx) fonction "poll". La fonction d'interrogation reçoit l'événement de SDL et émet l'événement avec la fonction _event_loop de window_sdl2.py. En regardant le code de la fonction "poll", il ressemble à ceci:

    def poll(self):
        cdef SDL_Event event
        cdef int rv

        with nogil:
            rv = SDL_PollEvent(&event)
        if rv == 0:
            return False

        action = None
        if event.type == SDL_QUIT:
            return ('quit', )
        elif event.type == SDL_DROPFILE:
            return ('dropfile', event.drop.file)
        elif event.type == SDL_MOUSEMOTION:
            x = event.motion.x
            y = event.motion.y
            return ('mousemotion', x, y)
            
~ Omis ~

        elif event.type == SDL_KEYDOWN or event.type == SDL_KEYUP:
            action = 'keydown' if event.type == SDL_KEYDOWN else 'keyup'
            mod = event.key.keysym.mod
            scancode = event.key.keysym.scancode
            key = event.key.keysym.sym
            return (action, mod, key, scancode, None)
        elif event.type == SDL_TEXTINPUT: ★
            s = event.text.text.decode('utf-8')
            return ('textinput', s)
        else:
            #    print('receive unknown sdl event', event.type)
            pass

Comme vous pouvez le voir, ** L'entrée de caractères et l'événement "textinput" sont renvoyés en réponse à l'événement "SDL_TEXTINPUT" lorsque l'entrée de caractères est confirmée, mais il est émis par SDL lors de l'entrée (IME). Il n'y a aucun traitement à effectuer en réponse à l'événement "SDL_TEXTEDIT". ** ** C'est la raison pour laquelle les caractères ne sont pas affichés lors de la saisie du japonais.

Rendre possible l'affichage des caractères saisis au Japon

Maintenant que je connais la raison, je vais réfléchir à ce qu'il faut faire ensuite. En termes de traitement, je pense que la procédure suivante devrait être ajoutée en premier.

À propos de la source réelle

@souan a ajouté pull request à kivy lui-même. De plus, en tant qu'exemple de programme, il est placé sur github.

Exemple d'émission d'un événement textedit: https://github.com/Adachinski/kivy/tree/textedit_patch_smple Exemple d'utilisation: https://github.com/Adachinski/kivy_textedit_sample

Ce qui suit concerne la source réelle.

Ajout de l'événement "SDL_TEXTEDIT"

Source: https://github.com/kivy/kivy/pull/5109

Ajout du processus lorsque SDL_TEXTEDIT est reçu dans la fonction d'interrogation du fichier kivy / core / window / _window_sdl2.pyx.

    def poll(self):
        cdef SDL_Event event
        cdef int rv

        with nogil:
            rv = SDL_PollEvent(&event)
        if rv == 0:
            return False


~ Omis ~

        elif event.type == SDL_TEXTINPUT: 
            s = event.text.text.decode('utf-8')
            return ('textinput', s)
            
        elif event.type == SDL_TEXTEDITING:★ Ajouter un événement
            s = event.edit.text.decode('utf-8')★ Entrez les caractères de IME
            return ('textedit', s)
        else:
            #    print('receive unknown sdl event', event.type)
            pass

À propos, ce fichier est un fichier pyx, vous devez donc le créer avec cython et recréer la bibliothèque. Comme kivy est OpenGL + SDL, il était difficile de créer l'environnement, et je construisais l'environnement de construction avec Windows, mais cela a pris 2 à 3 jours. Les détails sur la construction de l'environnement seront publiés à une date ultérieure.

Postscript: J'ai rédigé un article sur la création d'un environnement pour les entrées japonaises.

Ajouter un événement "textedit"

Source: https://github.com/Adachinski/kivy/tree/textedit_patch_smple

Pour ce faire, modifiez window_sdl2.py. https://github.com/Adachinski/kivy/commits/textedit_patch_smple/kivy/core/window/window_sdl2.py

Les points de correction sont les suivants.

class WindowSDL(WindowBase):

    __events__ = ('on_textedit',)★ Ajout
 
~ Omis ~
        def _mainloop(self):
        EventLoop.idle()

        # for android/iOS, we don't want to have any event nor executing our
        # main loop while the pause is going on. This loop wait any event (not
        # handled by the event filter), and remove them from the queue.
        # Nothing happen during the pause on iOS, except gyroscope value sent
        # over joystick. So it's safe.
        while self._pause_loop:
            self._win.wait_event()
            if not self._pause_loop:
                break
            self._win.poll()

        while True:
            event = self._win.poll()
            if event is False:
                break
            if event is None:
                continue

            action, args = event[0], event[1:]
            if action == 'quit':
                if self.dispatch('on_request_close'):
                    continue
                EventLoop.quit = True
                self.close()
                break
~ Omis ~


            elif action == 'textinput':
                text = args[0]
                self.dispatch('on_textinput', text)
            elif action == 'textedit':★ Ajout de texte
                text = args[0]
                self.dispatch('on_textedit', text)

            # unhandled event !
            else:
                Logger.trace('WindowSDL: Unhandled event %s' % str(event))
    

~ Omis ~
    def on_textedit(self, text):★ Ajout
        pass

Exemple d'utilisation réelle utilisant l'événement "textedit"

Source: https://github.com/Adachinski/kivy_textedit_sample

Héritez de la classe "TextInput" dans TextInputIME.py et ajoutez-en une nouvelle J'ai créé une classe "TextInputIME". Nous déclarons également la variable testtext comme StringProperty. Lorsque le traitement de l'événement textedit arrive, le caractère saisi est stocké dans testtext. Après cela, dans le fichier kv, le contenu du testtext est affiché dans Label.

L'écran de fonctionnement réel est le suivant.

Entrer

editing.png

Au fur et à mesure que vous tapez, les caractères que vous saisissez apparaissent sur l'étiquette IME (zone grise).

Après avoir confirmé l'entrée

complete.png Lorsque vous appuyez sur la touche Entrée et tapez, les caractères que vous tapez seront affichés dans l'entrée de texte.

Ce qui n'est pas possible actuellement

J'ai réussi à afficher le japonais que je tapais, mais je n'ai pas pu faire ce qui suit en raison d'un problème (spécification?) Côté SDL.

Cependant, ce contenu en lui-même n'est pas un facteur très critique personnellement, de sorte que la situation actuelle est indécise.

Recommended Posts

L'histoire de l'affichage des personnages dans l'entrée japonaise de Kivy
L'histoire de la confusion entre la production japonaise et Django
[Note] Les caractères japonais sont déformés avec atom-runner
L'histoire que FastAPI peut prendre la suprématie
L'histoire que scipy a soudainement arrêté de se charger
L'histoire que XGBoost a finalement été installé
Comment gérer le problème de déformation des caractères japonais lors de la sortie de journaux à l'aide du formateur de journaux JSON
Quelle est la raison pour laquelle l'homme n'affiche pas les commandes de base en japonais?
Bug où les fichiers statiques ne sont pas affichés sur le serveur de développement AppEngine
L'histoire qui s'inscrit dans l'installation de pip
Une histoire lorsque j'utilisais IntelliJ sous Linux et que je ne pouvais pas saisir le japonais