TTF_RenderUTF8 with non-UTF8 character

Hello,

I’m just wondering why TTF_RenderUTF8 does not support printing
characters that are not (I support UTF8).

My problem, I used gettext to write some french on my screen, my drawing
functions always use TTF_RenderUTF8 and it works, my text that
contains some accents like ‘?’ ‘?’ ‘?’ are written correctly.

However, if I wait for user input, I try to fill a char buffer and print
it on the screen (e.g let the user write his name).

So I read the SDL_keysym unicode member and add it to the buffer, but
then when using TTF_RenderUTF8, the output is broken, only squares are
written (like missing characters)…

In fact, when I press a key like ‘a’, ‘b’ the unicode member will be set
to the ASCII character (normal) but it will also set it for ‘?’ which
value is 233, that’s probably why I get a bad font rendering.

Please try my source code just below, put this font directly in the same
directory as the executable:

– font –
http://markand.malikania.fr/DejaVuSans.ttf

– code –
#include <stdio.h>
#include <stdbool.h>
#include <err.h>

#include <SDL.h>
#include <SDL_ttf.h>

void
addchar(char *buf, size_t len, uint16_t c)
{
size_t max = BUFSIZ - len;

if ((c & 0xFF80) == 0)
	snprintf(&buf[len], max, "%c", c & 0x7F);
else
	snprintf(&buf[len], max, "%c%c",
	    c & 0xFF, (c >> 8) & 0xFF);

}

int
main(void)
{
SDL_Surface *sc, *rd;
SDL_Event ev;
SDL_Color fg = { 255, 255, 255 };
SDL_Rect geo;
TTF_Font *ft;

bool		running;
char		buf[BUFSIZ] = { 0 };

char		fake_e[2];

if (SDL_Init(SDL_INIT_VIDEO) < 0)
	errx(1, "%s", SDL_GetError());
if (TTF_Init() < 0)
	errx(1, "%s", SDL_GetError());
if (!(sc = SDL_SetVideoMode(400, 200, 32, SDL_HWSURFACE)))
	errx(1, "%s", SDL_GetError());
if (!(ft = TTF_OpenFont("DejaVuSans.ttf", 10)))
	errx(1, "%s", SDL_GetError());

SDL_EnableUNICODE(1);

running = true;
while (running) {
	while (SDL_PollEvent(&ev)) {
		if (ev.type == SDL_QUIT) {
			running = false;
		} else if (ev.type == SDL_KEYDOWN) {
			addchar(buf, strlen(buf), ev.key.keysym.unicode);
		}
	}

	SDL_FillRect(sc, NULL, SDL_MapRGB(sc->format, 0, 0, 0));

	/*
	 * First render a correct text that will works, NOTE: calling
	 * strlen("abcd?") should *not* return 5 but 6 because of the
	 * wide char
	 */
	geo.x = geo.y = 10;
	rd = TTF_RenderUTF8_Blended(ft, "abcd?", fg);
	SDL_BlitSurface(rd, NULL, sc, &geo);
	if (rd)
		SDL_FreeSurface(rd);

	/*
	 * Render the broken input from user, press the '?' key if
	 * you have one on your keyboard. It will prints some square
	 * because the caracter is truncated to a one-byte char.
	 */
	geo.y += 20;
	rd = TTF_RenderUTF8_Blended(ft, buf, fg);
	SDL_BlitSurface(rd, NULL, sc, &geo);
	if (rd)
		SDL_FreeSurface(rd);

	/*
	 * For people that do not have a '?' on their keyboard, I
	 * simulate the case where you press it, the unicode member
	 * is set to '233' probably a Latin character.
	 */

	geo.y += 20;
	fake_e[0] = 233; fake_e[1] = '\0';
	rd = TTF_RenderUTF8_Blended(ft, fake_e, fg);
	SDL_BlitSurface(rd, NULL, sc, &geo);
	if (rd)
		SDL_FreeSurface(rd);

	SDL_Flip(sc);
	SDL_Delay(100);
}

}

Cheers,–
David Demelier