Tutorial de SDL – Parte 32 – Entrada de texto e Manipulação da área de transferência

Continuando nossa série de artigos traduzidos do site lazyfoo.net, agora veremos como realizar uma das tarefas mais comuns em jogos: ler a entrada de dados do teclado. Nesse artigo estaremos obtendo o texto usando os recursos de entrada de dados e manipulação da área de trabalho do SDL 2.

            //Main loop flag
            bool quit = false;
            //Event handler
            SDL_Event e;
            //Set text color as black
            SDL_Color textColor = { 0, 0, 0, 0xFF };
            //The current input text.
            std::string inputText = "Some Text";
            gInputTextTexture.loadFromRenderedText( inputText.c_str(), textColor );
            //Enable text input
            SDL_StartTextInput();

Antes de entrarmos no loop principal declaramos uma string para armazenar nosso texto e renderiza-lo em um textura. Chamamos então SDL_StartTextInput para que as funcionalidades de entrada de texto do SDL sejam ativadas.

            //While application is running
            while( !quit )
            {
                //The rerender text flag
                bool renderText = false;
                //Handle events on queue
                while( SDL_PollEvent( &e ) != 0 )
                {

Queremos apenas atualizar a entrada de texto quando precisarmos, assim teremos uma flag para indicar se precisamos atualizar a textura.

                    //Special key input
                    else if( e.type == SDL_KEYDOWN )
                    {
                        //Handle backspace
                        if( e.key.keysym.sym == SDLK_BACKSPACE && inputText.length() > 0 )
                        {
                            //lop off character
                            inputText.pop_back();
                            renderText = true;
                        }
                        //Handle copy
                        else if( e.key.keysym.sym == SDLK_c && SDL_GetModState() & KMOD_CTRL )
                        {
                            SDL_SetClipboardText( inputText.c_str() );
                        }
                        //Handle paste
                        else if( e.key.keysym.sym == SDLK_v && SDL_GetModState() & KMOD_CTRL )
                        {
                            inputText = SDL_GetClipboardText();
                            renderText = true;
                        }
                    }

Haverão alguns teclas especiais que queremos lidar. Quando o usuário pressiona a barra de espaço, queremos remover o último caractere da string.
Quando o usuário estive pressionando control e apertar a tecla c, queremos copiar o texto atual para a área de transferência usando SDL_SetClipboardText. Você pode verificar se a tecla control está pressionada com SDL_GetModState.
Quando o usuário usa a combinação ctrl + v, queremos pegar o texto da área de transferência usando SDL_GetClipboardText. Também observe que sempre que alterarmos o conteúdo da string ajustamos a flag de atualização.

                    //Special text input event
                    else if( e.type == SDL_TEXTINPUT )
                    {
                        //Not copy or pasting
                        if( !( ( e.text.text[ 0 ] == 'c' || e.text.text[ 0 ] == 'C' ) && ( e.text.text[ 0 ] == 'v' || e.text.text[ 0 ] == 'V' ) && SDL_GetModState() & KMOD_CTRL ) )
                        {
                            //Append character
                            inputText += e.text.text;
                            renderText = true;
                        }
                    }
                }

Com a entrada de texto ativada, toda vez que você pressionar uma tecla também será gerado um evento SDL_TextInputEvents o que simplifica as coisas como o pressionamento da tecla shift e do caps lock. Aqui primeiro queremos verificar que não estamos lendo um evento control c/control v pois iremos ignorar esses, já que já lidamos com esses eventos. Se não se tratar de um evento desses tipos, nós anexamos o caractere em nossa string.

                //Rerender text if needed
                if( renderText )
                {
                    //Text is not empty
                    if( inputText != "" )
                    {
                        //Render new text
                        gInputTextTexture.loadFromRenderedText( inputText.c_str(), textColor );
                    }
                    //Text is empty
                    else
                    {
                        //Render space texture
                        gInputTextTexture.loadFromRenderedText( " ", textColor );
                    }
                }

Se a flag de atualização do texto a ser renderizado foi ajustada, renderizamos a textura novamente. Um pequeno ajuste que temos aqui é que se tivermos uma string vazia, renderizamos uma espaço, pois SDL_ttf não renderiza uma string vazia.

                //Clear screen
                SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
                SDL_RenderClear( gRenderer );
                //Render text textures
                gPromptTextTexture.render( ( SCREEN_WIDTH - gPromptTextTexture.getWidth() ) / 2, 0 );
                gInputTextTexture.render( ( SCREEN_WIDTH - gInputTextTexture.getWidth() ) / 2, gPromptTextTexture.getHeight() );
                //Update screen
                SDL_RenderPresent( gRenderer );
            }

No final do loop principal nós renderizamos o texto sendo exibido e a entrada de texto.

            //Disable text input
            SDL_StopTextInput();
Uma vez que tivermos finalizado com a entrada de texto, desativamos esse recurso, pois quando ativamos ele temos alguma sobrecarga no programa.

Baixe os arquivo de mídia e do código fonte para o exemplo desse artigo aqui.