Saisie de texte SDL 2

Remarques sur mon code

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Salut à tous,

Je voudrais quelques remarques sur ce code qui permet de gérer la saisie en SDL 2. Le texte est affiché dans la console et il y a une gestion du copier-coller à l'aide de Ctrl + C et de Ctrl + V. Le code n'est pas commenté et certains noms de variables ne sont pas très bien choisis. Le code peut être amélioré (par exemple, on peut utiliser de la réallocation dynamique pour augmenter la taille de la chaine au fur et à mesure de la saisie). Quasiment tout le code est dans le main. Ce code sera adapté pour être utilisé dans un tutoriel que je suis en train de rédiger sur la SDL 2 et la mise en place de fonctions sera faite à ce moment. Voici le code en question :

 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <SDL2/SDL.h>
#include <stdio.h>
#include <string.h>
#define LEN_MAX 80

void copy(char *src, char *dst, int len)
{
    while(len-- && (*dst++ = *src++));
}

int main(int argc, char* args[])
{
    SDL_Window *window = NULL;
    int quit = SDL_FALSE;
    char rep[LEN_MAX] = {0};
    int len = 0, l;
    if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        fprintf(stderr, "Erreur SDL_Init : %s", SDL_GetError());
        goto Fin;
    }
    window = SDL_CreateWindow("Text Input", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 500, 500, SDL_WINDOW_SHOWN);
    if(NULL == window)
    {
        fprintf(stderr, "Erreur SDL_CreateWindow : %s", SDL_GetError());
        goto Quit;
    }
    SDL_Event event;
    SDL_StartTextInput();
    while(!quit)
    {
        SDL_WaitEvent(&event);
        if(event.type == SDL_QUIT)
            quit = SDL_TRUE;
        else if( event.type == SDL_KEYDOWN)
        {
            if(event.key.keysym.sym == SDLK_ESCAPE)
                quit = SDL_TRUE;
            if(event.key.keysym.sym == SDLK_BACKSPACE && len > 0)
            {
                rep[len - 1] = 0;
                len--;
            }
            if(event.key.keysym.sym == SDLK_v && (SDL_GetModState() & KMOD_CTRL) && SDL_HasClipboardText())
            {
                char *tmp = SDL_GetClipboardText();
                l = strlen(tmp);
                if(LEN_MAX - 1 - len - l > 0)
                {
                    copy(tmp, (rep + len), l);
                    len += l;
                }
                else
                {
                    copy(tmp, (rep + len), LEN_MAX - 1 - len);
                    len = LEN_MAX - 1;
                }
            }
            if(event.key.keysym.sym == SDLK_c && (SDL_GetModState() & KMOD_CTRL))
                SDL_SetClipboardText(rep);
        }
        else if(event.type == SDL_TEXTINPUT)
        {
            l = strlen(event.text.text);
            if(LEN_MAX - 1 - len - l > 0)
            {
                copy(event.text.text, (rep + len), l);
                len += l;
            }
            else
            {
                copy(event.text.text, (rep + len), LEN_MAX - 1 - len);
                len = LEN_MAX - 1;
            }
        }
        printf("%s\n", rep);
    }
    SDL_StopTextInput();
Quit:
    if(window)
        SDL_DestroyWindow(window);
    SDL_Quit();
Fin:
    return 0;
}

Merci d'avance pour vos commentaires.

Édité par Karnaj

Je fais un carnage si ce car nage car je nage, moi, Karnaj ! - Tutoriels LaTeX - Contribuez à un tutoriel Ruby

+0 -0

Cette réponse a aidé l'auteur du sujet

Coucou,

  • Tu devrais utiliser les fonctions standard (/ et pourquoi pas POSIX) comme strncpy, strdup, puts, …
  • len (celui dans main et celui dans copy) devrait être de type size_t.
  • La déclaration des variables au début de la fonction ça complique la lecture du code.
  • SDL_WaitEvent, SDL_SetClipboardText, SDL_GetClipboardText, printf peuvent échouer.
  • Tu devrais ajouter un retour à la ligne pour les messages d'erreur lignes 19 et 25.
  • SDL_DestroyWindow peut être appelé avec un pointeur NULL, dans ce cas-ci, SDL_GetError va retourner le message "invalid window".
  • La valeur retournée par SDL_GetClipboardText doit être libérée avec SDL_free. Et du coup la copie dans rep ne sert pas à grand chose, il faudrait juste garder un pointeur pour cette valeur.
  • Tu peux mettre int main(void) vu que tu n'utilise pas argc et args (qu'on appele généralement argv).
+0 -0
Auteur du sujet
  • Tu devrais utiliser les fonctions standard (/ et pourquoi pas POSIX) comme strncpy, strdup, puts, …

C'est ce que je vais faire.

  • len (celui dans main et celui dans copy) devrait être de type size_t.

Je vais changer ça.

  • SDL_WaitEvent, SDL_SetClipboardText, SDL_GetClipboardText, printf peuvent échouer.

Je vais remplacer printf par puts et vérifier les retours.

  • SDL_DestroyWindow peut être appelé avec un pointeur NULL, dans ce cas-ci, SDL_GetError va retourner le message "invalid window".

Je trouve que c'est plutôt une bonne habitude de vérifier la valeur des choses que l'on veut libérer. Surtout pour un tutoriel. Tu penses que je devrais quand même supprimer le test ?

  • La valeur retournée par SDL_GetClipboardText doit être libérée avec SDL_free. Et du coup la copie dans rep ne sert pas à grand chose, il faudrait juste garder un pointeur pour cette valeur.

Pour un tutoriel ce n'est pas mieux de copier cette chaîne de caractère, histoire d'avoir quelque chose de plus simple ? Je garderais le pointeur sur cette valeur quand je ferais la version avec une taille non fixée en utilisant l'allocation dynamique.

  • Tu peux mettre int main(void) vu que tu n'utilise pas argc et args (qu'on appele généralement argv).

Pourquoi j'ai écrit args ? o_O Par contre, les arguments sont obligatoires, le main de la SDL doit être de cette forme.

Merci pour tes remarques. Je vais mettre à jour le code du premier post en les prenant en compte.

Édité par Karnaj

Je fais un carnage si ce car nage car je nage, moi, Karnaj ! - Tutoriels LaTeX - Contribuez à un tutoriel Ruby

+0 -0

Je trouve que c'est plutôt une bonne habitude de vérifier la valeur des choses que l'on veut libérer. Surtout pour un tutoriel. Tu penses que je devrais quand même supprimer le test ?

À toi de voir, j'ai juste indiqué que le comportement est défini dans ce cas-ci. Souvent, quand on a une fonction de libération, elle accepte qu'on lui passe NULL, donc il est inutile de tester ce cas-ci.

Pour un tutoriel ce n'est pas mieux de copier cette chaîne de caractère, histoire d'avoir quelque chose de plus simple ? Je garderais le pointeur sur cette valeur quand je ferais la version avec une taille non fixée en utilisant l'allocation dynamique.

Pour le coup, je pense qu'il serait bien plus simple d'avoir un pointeur vers les données retournées par SDL_GetClipboardText plutôt que de devoir faire une copie à chaque fois… En plus ça fait moins d'erreurs à gérer.

Édité par superlama

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte