1 /*
2   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
3 
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7 
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely.
11 */
12 /* A simple program to test the Input Method support in the SDL library (2.0+)
13    If you build without SDL_ttf, you can use the GNU Unifont hex file instead.
14    Download at http://unifoundry.com/unifont.html */
15 
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 
20 #include "SDL.h"
21 #ifdef HAVE_SDL_TTF
22 #include "SDL_ttf.h"
23 #endif
24 
25 #include "SDL_test_common.h"
26 
27 #define DEFAULT_PTSIZE 30
28 #ifdef HAVE_SDL_TTF
29 #ifdef __MACOSX__
30 #define DEFAULT_FONT "/System/Library/Fonts/华文细黑.ttf"
31 #elif __WIN32__
32 /* Some japanese font present on at least Windows 8.1. */
33 #define DEFAULT_FONT "C:\\Windows\\Fonts\\yugothic.ttf"
34 #else
35 #define DEFAULT_FONT "NoDefaultFont.ttf"
36 #endif
37 #else
38 #define DEFAULT_FONT "unifont-9.0.02.hex"
39 #endif
40 #define MAX_TEXT_LENGTH 256
41 
42 static SDLTest_CommonState *state;
43 static SDL_Rect textRect, markedRect;
44 static SDL_Color lineColor = {0,0,0,255};
45 static SDL_Color backColor = {255,255,255,255};
46 static SDL_Color textColor = {0,0,0,255};
47 static char text[MAX_TEXT_LENGTH], markedText[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
48 static int cursor = 0;
49 #ifdef HAVE_SDL_TTF
50 static TTF_Font *font;
51 #else
52 #define UNIFONT_MAX_CODEPOINT 0x1ffff
53 #define UNIFONT_NUM_GLYPHS 0x20000
54 /* Using 512x512 textures that are supported everywhere. */
55 #define UNIFONT_TEXTURE_WIDTH 512
56 #define UNIFONT_GLYPHS_IN_ROW (UNIFONT_TEXTURE_WIDTH / 16)
57 #define UNIFONT_GLYPHS_IN_TEXTURE (UNIFONT_GLYPHS_IN_ROW * UNIFONT_GLYPHS_IN_ROW)
58 #define UNIFONT_NUM_TEXTURES ((UNIFONT_NUM_GLYPHS + UNIFONT_GLYPHS_IN_TEXTURE - 1) / UNIFONT_GLYPHS_IN_TEXTURE)
59 #define UNIFONT_TEXTURE_SIZE (UNIFONT_TEXTURE_WIDTH * UNIFONT_TEXTURE_WIDTH * 4)
60 #define UNIFONT_TEXTURE_PITCH (UNIFONT_TEXTURE_WIDTH * 4)
61 #define UNIFONT_DRAW_SCALE 2
62 struct UnifontGlyph {
63     Uint8 width;
64     Uint8 data[32];
65 } *unifontGlyph;
66 static SDL_Texture **unifontTexture;
67 static Uint8 unifontTextureLoaded[UNIFONT_NUM_TEXTURES] = {0};
68 
69 /* Unifont loading code start */
70 
dehex(char c)71 static Uint8 dehex(char c)
72 {
73     if (c >= '0' && c <= '9')
74         return c - '0';
75     else if (c >= 'a' && c <= 'f')
76         return c - 'a' + 10;
77     else if (c >= 'A' && c <= 'F')
78         return c - 'A' + 10;
79     return 255;
80 }
81 
dehex2(char c1,char c2)82 static Uint8 dehex2(char c1, char c2)
83 {
84     return (dehex(c1) << 4) | dehex(c2);
85 }
86 
validate_hex(const char * cp,size_t len,Uint32 * np)87 static Uint8 validate_hex(const char *cp, size_t len, Uint32 *np)
88 {
89     Uint32 n = 0;
90     for (; len > 0; cp++, len--)
91     {
92         Uint8 c = dehex(*cp);
93         if (c == 255)
94             return 0;
95         n = (n << 4) | c;
96     }
97     if (np != NULL)
98         *np = n;
99     return 1;
100 }
101 
unifont_init(const char * fontname)102 static int unifont_init(const char *fontname)
103 {
104     Uint8 hexBuffer[65];
105     Uint32 numGlyphs = 0;
106     int lineNumber = 1;
107     size_t bytesRead;
108     SDL_RWops *hexFile;
109     const size_t unifontGlyphSize = UNIFONT_NUM_GLYPHS * sizeof(struct UnifontGlyph);
110     const size_t unifontTextureSize = UNIFONT_NUM_TEXTURES * state->num_windows * sizeof(void *);
111 
112     /* Allocate memory for the glyph data so the file can be closed after initialization. */
113     unifontGlyph = (struct UnifontGlyph *)SDL_malloc(unifontGlyphSize);
114     if (unifontGlyph == NULL)
115     {
116         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for glyph data.\n", (int)(unifontGlyphSize + 1023) / 1024);
117         return -1;
118     }
119     SDL_memset(unifontGlyph, 0, unifontGlyphSize);
120 
121     /* Allocate memory for texture pointers for all renderers. */
122     unifontTexture = (SDL_Texture **)SDL_malloc(unifontTextureSize);
123     if (unifontTexture == NULL)
124     {
125         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d KiB for texture pointer data.\n", (int)(unifontTextureSize + 1023) / 1024);
126         return -1;
127     }
128     SDL_memset(unifontTexture, 0, unifontTextureSize);
129 
130     hexFile = SDL_RWFromFile(fontname, "rb");
131     if (hexFile == NULL)
132     {
133         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to open font file: %s\n", fontname);
134         return -1;
135     }
136 
137     /* Read all the glyph data into memory to make it accessible later when textures are created. */
138     do {
139         int i, codepointHexSize;
140         size_t bytesOverread;
141         Uint8 glyphWidth;
142         Uint32 codepoint;
143 
144         bytesRead = SDL_RWread(hexFile, hexBuffer, 1, 9);
145         if (numGlyphs > 0 && bytesRead == 0)
146             break; /* EOF */
147         if ((numGlyphs == 0 && bytesRead == 0) || (numGlyphs > 0 && bytesRead < 9))
148         {
149             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n");
150             return -1;
151         }
152 
153         /* Looking for the colon that separates the codepoint and glyph data at position 2, 4, 6 and 8. */
154         if (hexBuffer[2] == ':')
155             codepointHexSize = 2;
156         else if (hexBuffer[4] == ':')
157             codepointHexSize = 4;
158         else if (hexBuffer[6] == ':')
159             codepointHexSize = 6;
160         else if (hexBuffer[8] == ':')
161             codepointHexSize = 8;
162         else
163         {
164             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Could not find codepoint and glyph data separator symbol in hex file on line %d.\n", lineNumber);
165             return -1;
166         }
167 
168         if (!validate_hex((const char *)hexBuffer, codepointHexSize, &codepoint))
169         {
170             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal number in hex file on line %d.\n", lineNumber);
171             return -1;
172         }
173         if (codepoint > UNIFONT_MAX_CODEPOINT)
174             SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Codepoint on line %d exceeded limit of 0x%x.\n", lineNumber, UNIFONT_MAX_CODEPOINT);
175 
176         /* If there was glyph data read in the last file read, move it to the front of the buffer. */
177         bytesOverread = 8 - codepointHexSize;
178         if (codepointHexSize < 8)
179             SDL_memmove(hexBuffer, hexBuffer + codepointHexSize + 1, bytesOverread);
180         bytesRead = SDL_RWread(hexFile, hexBuffer + bytesOverread, 1, 33 - bytesOverread);
181         if (bytesRead < (33 - bytesOverread))
182         {
183             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n");
184             return -1;
185         }
186         if (hexBuffer[32] == '\n')
187             glyphWidth = 8;
188         else
189         {
190             glyphWidth = 16;
191             bytesRead = SDL_RWread(hexFile, hexBuffer + 33, 1, 32);
192             if (bytesRead < 32)
193             {
194                 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Unexpected end of hex file.\n");
195                 return -1;
196             }
197         }
198 
199         if (!validate_hex((const char *)hexBuffer, glyphWidth * 4, NULL))
200         {
201             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Malformed hexadecimal glyph data in hex file on line %d.\n", lineNumber);
202             return -1;
203         }
204 
205         if (codepoint <= UNIFONT_MAX_CODEPOINT)
206         {
207             if (unifontGlyph[codepoint].width > 0)
208                 SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "unifont: Ignoring duplicate codepoint 0x%08x in hex file on line %d.\n", codepoint, lineNumber);
209             else
210             {
211                 unifontGlyph[codepoint].width = glyphWidth;
212                 /* Pack the hex data into a more compact form. */
213                 for (i = 0; i < glyphWidth * 2; i++)
214                     unifontGlyph[codepoint].data[i] = dehex2(hexBuffer[i * 2], hexBuffer[i * 2 + 1]);
215                 numGlyphs++;
216             }
217         }
218 
219         lineNumber++;
220     } while (bytesRead > 0);
221 
222     SDL_RWclose(hexFile);
223     SDL_Log("unifont: Loaded %u glyphs.\n", numGlyphs);
224     return 0;
225 }
226 
unifont_make_rgba(Uint8 * src,Uint8 * dst,Uint8 width)227 static void unifont_make_rgba(Uint8 *src, Uint8 *dst, Uint8 width)
228 {
229     int i, j;
230     Uint8 *row = dst;
231 
232     for (i = 0; i < width * 2; i++)
233     {
234         Uint8 data = src[i];
235         for (j = 0; j < 8; j++)
236         {
237             if (data & 0x80)
238             {
239                 row[0] = textColor.r;
240                 row[1] = textColor.g;
241                 row[2] = textColor.b;
242                 row[3] = textColor.a;
243             }
244             else
245             {
246                 row[0] = 0;
247                 row[1] = 0;
248                 row[2] = 0;
249                 row[3] = 0;
250             }
251             data <<= 1;
252             row += 4;
253         }
254 
255         if (width == 8 || (width == 16 && i % 2 == 1))
256         {
257             dst += UNIFONT_TEXTURE_PITCH;
258             row = dst;
259         }
260     }
261 }
262 
unifont_load_texture(Uint32 textureID)263 static int unifont_load_texture(Uint32 textureID)
264 {
265     int i;
266     Uint8 * textureRGBA;
267 
268     if (textureID >= UNIFONT_NUM_TEXTURES)
269     {
270         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Tried to load out of range texture %u.\n", textureID);
271         return -1;
272     }
273 
274     textureRGBA = (Uint8 *)SDL_malloc(UNIFONT_TEXTURE_SIZE);
275     if (textureRGBA == NULL)
276     {
277         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to allocate %d MiB for a texture.\n", UNIFONT_TEXTURE_SIZE / 1024 / 1024);
278         return -1;
279     }
280     SDL_memset(textureRGBA, 0, UNIFONT_TEXTURE_SIZE);
281 
282     /* Copy the glyphs into memory in RGBA format. */
283     for (i = 0; i < UNIFONT_GLYPHS_IN_TEXTURE; i++)
284     {
285         Uint32 codepoint = UNIFONT_GLYPHS_IN_TEXTURE * textureID + i;
286         if (unifontGlyph[codepoint].width > 0)
287         {
288             const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
289             const size_t offset = (cInTex / UNIFONT_GLYPHS_IN_ROW) * UNIFONT_TEXTURE_PITCH * 16 + (cInTex % UNIFONT_GLYPHS_IN_ROW) * 16 * 4;
290             unifont_make_rgba(unifontGlyph[codepoint].data, textureRGBA + offset, unifontGlyph[codepoint].width);
291         }
292     }
293 
294     /* Create textures and upload the RGBA data from above. */
295     for (i = 0; i < state->num_windows; ++i)
296     {
297         SDL_Renderer *renderer = state->renderers[i];
298         SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID];
299         if (state->windows[i] == NULL || renderer == NULL || tex != NULL)
300             continue;
301         tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, UNIFONT_TEXTURE_WIDTH, UNIFONT_TEXTURE_WIDTH);
302         if (tex == NULL)
303         {
304             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "unifont: Failed to create texture %u for renderer %d.\n", textureID, i);
305             return -1;
306         }
307         unifontTexture[UNIFONT_NUM_TEXTURES * i + textureID] = tex;
308         SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
309         if (SDL_UpdateTexture(tex, NULL, textureRGBA, UNIFONT_TEXTURE_PITCH) != 0)
310         {
311             SDL_Log("unifont error: Failed to update texture %u data for renderer %d.\n", textureID, i);
312         }
313     }
314 
315     SDL_free(textureRGBA);
316     unifontTextureLoaded[textureID] = 1;
317     return 0;
318 }
319 
unifont_draw_glyph(Uint32 codepoint,int rendererID,SDL_Rect * dstrect)320 static Sint32 unifont_draw_glyph(Uint32 codepoint, int rendererID, SDL_Rect *dstrect)
321 {
322     SDL_Texture *texture;
323     const Uint32 textureID = codepoint / UNIFONT_GLYPHS_IN_TEXTURE;
324     SDL_Rect srcrect;
325     srcrect.w = srcrect.h = 16;
326     if (codepoint > UNIFONT_MAX_CODEPOINT) {
327         return 0;
328     }
329     if (!unifontTextureLoaded[textureID]) {
330         if (unifont_load_texture(textureID) < 0) {
331             return 0;
332         }
333     }
334     texture = unifontTexture[UNIFONT_NUM_TEXTURES * rendererID + textureID];
335     if (texture != NULL)
336     {
337         const Uint32 cInTex = codepoint % UNIFONT_GLYPHS_IN_TEXTURE;
338         srcrect.x = cInTex % UNIFONT_GLYPHS_IN_ROW * 16;
339         srcrect.y = cInTex / UNIFONT_GLYPHS_IN_ROW * 16;
340         SDL_RenderCopy(state->renderers[rendererID], texture, &srcrect, dstrect);
341     }
342     return unifontGlyph[codepoint].width;
343 }
344 
unifont_cleanup()345 static void unifont_cleanup()
346 {
347     int i, j;
348     for (i = 0; i < state->num_windows; ++i)
349     {
350         SDL_Renderer *renderer = state->renderers[i];
351         if (state->windows[i] == NULL || renderer == NULL)
352             continue;
353         for (j = 0; j < UNIFONT_NUM_TEXTURES; j++)
354         {
355             SDL_Texture *tex = unifontTexture[UNIFONT_NUM_TEXTURES * i + j];
356             if (tex != NULL)
357                 SDL_DestroyTexture(tex);
358         }
359     }
360 
361     for (j = 0; j < UNIFONT_NUM_TEXTURES; j++)
362           unifontTextureLoaded[j] = 0;
363 
364     SDL_free(unifontTexture);
365     SDL_free(unifontGlyph);
366 }
367 
368 /* Unifont code end */
369 #endif
370 
utf8_length(unsigned char c)371 size_t utf8_length(unsigned char c)
372 {
373     c = (unsigned char)(0xff & c);
374     if (c < 0x80)
375         return 1;
376     else if ((c >> 5) ==0x6)
377         return 2;
378     else if ((c >> 4) == 0xe)
379         return 3;
380     else if ((c >> 3) == 0x1e)
381         return 4;
382     else
383         return 0;
384 }
385 
utf8_next(char * p)386 char *utf8_next(char *p)
387 {
388     size_t len = utf8_length(*p);
389     size_t i = 0;
390     if (!len)
391         return 0;
392 
393     for (; i < len; ++i)
394     {
395         ++p;
396         if (!*p)
397             return 0;
398     }
399     return p;
400 }
401 
utf8_advance(char * p,size_t distance)402 char *utf8_advance(char *p, size_t distance)
403 {
404     size_t i = 0;
405     for (; i < distance && p; ++i)
406     {
407         p = utf8_next(p);
408     }
409     return p;
410 }
411 
utf8_decode(char * p,size_t len)412 Uint32 utf8_decode(char *p, size_t len)
413 {
414     Uint32 codepoint = 0;
415     size_t i = 0;
416     if (!len)
417         return 0;
418 
419     for (; i < len; ++i)
420     {
421         if (i == 0)
422             codepoint = (0xff >> len) & *p;
423         else
424         {
425             codepoint <<= 6;
426             codepoint |= 0x3f & *p;
427         }
428         if (!*p)
429             return 0;
430         p++;
431     }
432 
433     return codepoint;
434 }
435 
usage()436 void usage()
437 {
438     SDL_Log("usage: testime [--font fontfile]\n");
439 }
440 
InitInput()441 void InitInput()
442 {
443     /* Prepare a rect for text input */
444     textRect.x = textRect.y = 100;
445     textRect.w = DEFAULT_WINDOW_WIDTH - 2 * textRect.x;
446     textRect.h = 50;
447 
448     text[0] = 0;
449     markedRect = textRect;
450     markedText[0] = 0;
451 
452     SDL_StartTextInput();
453 }
454 
CleanupVideo()455 void CleanupVideo()
456 {
457     SDL_StopTextInput();
458 #ifdef HAVE_SDL_TTF
459     TTF_CloseFont(font);
460     TTF_Quit();
461 #else
462     unifont_cleanup();
463 #endif
464 }
465 
_Redraw(int rendererID)466 void _Redraw(int rendererID)
467 {
468     SDL_Renderer * renderer = state->renderers[rendererID];
469     SDL_Rect drawnTextRect, cursorRect, underlineRect;
470     drawnTextRect = textRect;
471     drawnTextRect.w = 0;
472 
473     SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
474     SDL_RenderFillRect(renderer,&textRect);
475 
476     if (*text)
477     {
478 #ifdef HAVE_SDL_TTF
479         SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, text, textColor);
480         SDL_Texture *texture;
481 
482         /* Vertically center text */
483         drawnTextRect.y = textRect.y + (textRect.h - textSur->h) / 2;
484         drawnTextRect.w = textSur->w;
485         drawnTextRect.h = textSur->h;
486 
487         texture = SDL_CreateTextureFromSurface(renderer,textSur);
488         SDL_FreeSurface(textSur);
489 
490         SDL_RenderCopy(renderer,texture,NULL,&drawnTextRect);
491         SDL_DestroyTexture(texture);
492 #else
493         char *utext = text;
494         Uint32 codepoint;
495         size_t len;
496         SDL_Rect dstrect;
497 
498         dstrect.x = textRect.x;
499         dstrect.y = textRect.y + (textRect.h - 16 * UNIFONT_DRAW_SCALE) / 2;
500         dstrect.w = 16 * UNIFONT_DRAW_SCALE;
501         dstrect.h = 16 * UNIFONT_DRAW_SCALE;
502         drawnTextRect.y = dstrect.y;
503         drawnTextRect.h = dstrect.h;
504 
505         while ((codepoint = utf8_decode(utext, len = utf8_length(*utext))))
506         {
507             Sint32 advance = unifont_draw_glyph(codepoint, rendererID, &dstrect) * UNIFONT_DRAW_SCALE;
508             dstrect.x += advance;
509             drawnTextRect.w += advance;
510             utext += len;
511         }
512 #endif
513     }
514 
515     markedRect.x = textRect.x + drawnTextRect.w;
516     markedRect.w = textRect.w - drawnTextRect.w;
517     if (markedRect.w < 0)
518     {
519         /* Stop text input because we cannot hold any more characters */
520         SDL_StopTextInput();
521         return;
522     }
523     else
524     {
525         SDL_StartTextInput();
526     }
527 
528     cursorRect = drawnTextRect;
529     cursorRect.x += cursorRect.w;
530     cursorRect.w = 2;
531     cursorRect.h = drawnTextRect.h;
532 
533     drawnTextRect.x += drawnTextRect.w;
534     drawnTextRect.w = 0;
535 
536     SDL_SetRenderDrawColor(renderer, backColor.r, backColor.g, backColor.b, backColor.a);
537     SDL_RenderFillRect(renderer,&markedRect);
538 
539     if (markedText[0])
540     {
541 #ifdef HAVE_SDL_TTF
542         SDL_Surface *textSur;
543         SDL_Texture *texture;
544         if (cursor)
545         {
546             char *p = utf8_advance(markedText, cursor);
547             char c = 0;
548             if (!p)
549                 p = &markedText[SDL_strlen(markedText)];
550 
551             c = *p;
552             *p = 0;
553             TTF_SizeUTF8(font, markedText, &drawnTextRect.w, NULL);
554             cursorRect.x += drawnTextRect.w;
555             *p = c;
556         }
557         textSur = TTF_RenderUTF8_Blended(font, markedText, textColor);
558         /* Vertically center text */
559         drawnTextRect.y = textRect.y + (textRect.h - textSur->h) / 2;
560         drawnTextRect.w = textSur->w;
561         drawnTextRect.h = textSur->h;
562 
563         texture = SDL_CreateTextureFromSurface(renderer,textSur);
564         SDL_FreeSurface(textSur);
565 
566         SDL_RenderCopy(renderer,texture,NULL,&drawnTextRect);
567         SDL_DestroyTexture(texture);
568 #else
569         int i = 0;
570         char *utext = markedText;
571         Uint32 codepoint;
572         size_t len;
573         SDL_Rect dstrect;
574 
575         dstrect.x = drawnTextRect.x;
576         dstrect.y = textRect.y + (textRect.h - 16 * UNIFONT_DRAW_SCALE) / 2;
577         dstrect.w = 16 * UNIFONT_DRAW_SCALE;
578         dstrect.h = 16 * UNIFONT_DRAW_SCALE;
579         drawnTextRect.y = dstrect.y;
580         drawnTextRect.h = dstrect.h;
581 
582         while ((codepoint = utf8_decode(utext, len = utf8_length(*utext))))
583         {
584             Sint32 advance = unifont_draw_glyph(codepoint, rendererID, &dstrect) * UNIFONT_DRAW_SCALE;
585             dstrect.x += advance;
586             drawnTextRect.w += advance;
587             if (i < cursor)
588                 cursorRect.x += advance;
589             i++;
590             utext += len;
591         }
592 #endif
593 
594         if (cursor > 0)
595         {
596             cursorRect.y = drawnTextRect.y;
597             cursorRect.h = drawnTextRect.h;
598         }
599 
600         underlineRect = markedRect;
601         underlineRect.y = drawnTextRect.y + drawnTextRect.h - 2;
602         underlineRect.h = 2;
603         underlineRect.w = drawnTextRect.w;
604 
605         SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
606         SDL_RenderFillRect(renderer, &underlineRect);
607     }
608 
609     SDL_SetRenderDrawColor(renderer, lineColor.r, lineColor.g, lineColor.b, lineColor.a);
610     SDL_RenderFillRect(renderer,&cursorRect);
611 
612     SDL_SetTextInputRect(&markedRect);
613 }
614 
Redraw()615 void Redraw()
616 {
617     int i;
618     for (i = 0; i < state->num_windows; ++i) {
619         SDL_Renderer *renderer = state->renderers[i];
620         if (state->windows[i] == NULL)
621             continue;
622         SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
623         SDL_RenderClear(renderer);
624 
625         /* Sending in the window id to let the font renderers know which one we're working with. */
626         _Redraw(i);
627 
628         SDL_RenderPresent(renderer);
629     }
630 }
631 
main(int argc,char * argv[])632 int main(int argc, char *argv[])
633 {
634     int i, done;
635     SDL_Event event;
636     const char *fontname = DEFAULT_FONT;
637 
638     /* Enable standard application logging */
639     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
640 
641     /* Initialize test framework */
642     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
643     if (!state) {
644         return 1;
645     }
646     for (i = 1; i < argc;i++) {
647         SDLTest_CommonArg(state, i);
648     }
649     for (argc--, argv++; argc > 0; argc--, argv++)
650     {
651         if (strcmp(argv[0], "--help") == 0) {
652             usage();
653             return 0;
654         }
655 
656         else if (strcmp(argv[0], "--font") == 0)
657         {
658             argc--;
659             argv++;
660 
661             if (argc > 0)
662                 fontname = argv[0];
663             else {
664                 usage();
665                 return 0;
666             }
667         }
668     }
669 
670     if (!SDLTest_CommonInit(state)) {
671         return 2;
672     }
673 
674 
675 #ifdef HAVE_SDL_TTF
676     /* Initialize fonts */
677     TTF_Init();
678 
679     font = TTF_OpenFont(fontname, DEFAULT_PTSIZE);
680     if (! font)
681     {
682         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to find font: %s\n", TTF_GetError());
683         return -1;
684     }
685 #else
686     if (unifont_init(fontname) < 0) {
687         return -1;
688     }
689 #endif
690 
691     SDL_Log("Using font: %s\n", fontname);
692 
693     InitInput();
694     /* Create the windows and initialize the renderers */
695     for (i = 0; i < state->num_windows; ++i) {
696         SDL_Renderer *renderer = state->renderers[i];
697         SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
698         SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
699         SDL_RenderClear(renderer);
700     }
701     Redraw();
702     /* Main render loop */
703     done = 0;
704     while (!done) {
705         /* Check for events */
706         while (SDL_PollEvent(&event)) {
707             SDLTest_CommonEvent(state, &event, &done);
708             switch(event.type) {
709                 case SDL_KEYDOWN: {
710                     switch (event.key.keysym.sym)
711                     {
712                         case SDLK_RETURN:
713                              text[0]=0x00;
714                              Redraw();
715                              break;
716                         case SDLK_BACKSPACE:
717                             /* Only delete text if not in editing mode. */
718                              if (!markedText[0])
719                              {
720                                  size_t textlen = SDL_strlen(text);
721 
722                                  do {
723                                      if (textlen==0)
724                                      {
725                                          break;
726                                      }
727                                      if ((text[textlen-1] & 0x80) == 0x00)
728                                      {
729                                          /* One byte */
730                                          text[textlen-1]=0x00;
731                                          break;
732                                      }
733                                      if ((text[textlen-1] & 0xC0) == 0x80)
734                                      {
735                                          /* Byte from the multibyte sequence */
736                                          text[textlen-1]=0x00;
737                                          textlen--;
738                                      }
739                                      if ((text[textlen-1] & 0xC0) == 0xC0)
740                                      {
741                                          /* First byte of multibyte sequence */
742                                          text[textlen-1]=0x00;
743                                          break;
744                                      }
745                                  } while(1);
746 
747                                  Redraw();
748                              }
749                              break;
750                     }
751 
752                     if (done)
753                     {
754                         break;
755                     }
756 
757                     SDL_Log("Keyboard: scancode 0x%08X = %s, keycode 0x%08X = %s\n",
758                             event.key.keysym.scancode,
759                             SDL_GetScancodeName(event.key.keysym.scancode),
760                             event.key.keysym.sym, SDL_GetKeyName(event.key.keysym.sym));
761                     break;
762 
763                 case SDL_TEXTINPUT:
764                     if (event.text.text[0] == '\0' || event.text.text[0] == '\n' ||
765                         markedRect.w < 0)
766                         break;
767 
768                     SDL_Log("Keyboard: text input \"%s\"\n", event.text.text);
769 
770                     if (SDL_strlen(text) + SDL_strlen(event.text.text) < sizeof(text))
771                         SDL_strlcat(text, event.text.text, sizeof(text));
772 
773                     SDL_Log("text inputed: %s\n", text);
774 
775                     /* After text inputed, we can clear up markedText because it */
776                     /* is committed */
777                     markedText[0] = 0;
778                     Redraw();
779                     break;
780 
781                 case SDL_TEXTEDITING:
782                     SDL_Log("text editing \"%s\", selected range (%d, %d)\n",
783                             event.edit.text, event.edit.start, event.edit.length);
784 
785                     SDL_strlcpy(markedText, event.edit.text, SDL_TEXTEDITINGEVENT_TEXT_SIZE);
786                     cursor = event.edit.start;
787                     Redraw();
788                     break;
789                 }
790                 break;
791 
792             }
793         }
794     }
795     CleanupVideo();
796     SDLTest_CommonQuit(state);
797     return 0;
798 }
799 
800 
801 /* vi: set ts=4 sw=4 expandtab: */
802