1 /* 2 Copyright (C) 1997-2014 Sam Lantinga <slouken (at) 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 14 #include <stdlib.h> 15 #include <stdio.h> 16 #include <string.h> 17 18 #include "SDL.h" 19 #ifdef HAVE_SDL_TTF 20 #include "SDL_ttf.h" 21 #endif 22 23 #include "SDL_test_common.h" 24 25 #define DEFAULT_PTSIZE 30 26 #define DEFAULT_FONT "/System/Library/Fonts/.ttf" 27 #define MAX_TEXT_LENGTH 256 28 29 static SDLTest_CommonState *state; 30 static SDL_Rect textRect, markedRect; 31 static SDL_Color lineColor = {0,0,0,0}; 32 static SDL_Color backColor = {255,255,255,0}; 33 static SDL_Color textColor = {0,0,0,0}; 34 static char text[MAX_TEXT_LENGTH], markedText[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; 35 static int cursor = 0; 36 #ifdef HAVE_SDL_TTF 37 static TTF_Font *font; 38 #endif 39 40 size_t utf8_length(unsigned char c) 41 { 42 c = (unsigned char)(0xff & c); 43 if (c < 0x80) 44 return 1; 45 else if ((c >> 5) ==0x6) 46 return 2; 47 else if ((c >> 4) == 0xe) 48 return 3; 49 else if ((c >> 3) == 0x1e) 50 return 4; 51 else 52 return 0; 53 } 54 55 char *utf8_next(char *p) 56 { 57 size_t len = utf8_length(*p); 58 size_t i = 0; 59 if (!len) 60 return 0; 61 62 for (; i < len; ++i) 63 { 64 ++p; 65 if (!*p) 66 return 0; 67 } 68 return p; 69 } 70 71 char *utf8_advance(char *p, size_t distance) 72 { 73 size_t i = 0; 74 for (; i < distance && p; ++i) 75 { 76 p = utf8_next(p); 77 } 78 return p; 79 } 80 81 void usage() 82 { 83 SDL_Log("usage: testime [--font fontfile]\n"); 84 exit(0); 85 } 86 87 void InitInput() 88 { 89 90 /* Prepare a rect for text input */ 91 textRect.x = textRect.y = 100; 92 textRect.w = DEFAULT_WINDOW_WIDTH - 2 * textRect.x; 93 textRect.h = 50; 94 95 text[0] = 0; 96 markedRect = textRect; 97 markedText[0] = 0; 98 99 SDL_StartTextInput(); 100 } 101 102 void CleanupVideo() 103 { 104 SDL_StopTextInput(); 105 #ifdef HAVE_SDL_TTF 106 TTF_CloseFont(font); 107 TTF_Quit(); 108 #endif 109 } 110 111 112 void _Redraw(SDL_Renderer * renderer) { 113 int w = 0, h = textRect.h; 114 SDL_Rect cursorRect, underlineRect; 115 116 SDL_SetRenderDrawColor(renderer, 255,255,255,255); 117 SDL_RenderFillRect(renderer,&textRect); 118 119 #ifdef HAVE_SDL_TTF 120 if (*text) 121 { 122 SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, text, textColor); 123 SDL_Rect dest = {textRect.x, textRect.y, textSur->w, textSur->h }; 124 125 SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer,textSur); 126 SDL_FreeSurface(textSur); 127 128 SDL_RenderCopy(renderer,texture,NULL,&dest); 129 SDL_DestroyTexture(texture); 130 TTF_SizeUTF8(font, text, &w, &h); 131 } 132 #endif 133 134 markedRect.x = textRect.x + w; 135 markedRect.w = textRect.w - w; 136 if (markedRect.w < 0) 137 { 138 /* Stop text input because we cannot hold any more characters */ 139 SDL_StopTextInput(); 140 return; 141 } 142 else 143 { 144 SDL_StartTextInput(); 145 } 146 147 cursorRect = markedRect; 148 cursorRect.w = 2; 149 cursorRect.h = h; 150 151 SDL_SetRenderDrawColor(renderer, 255,255,255,255); 152 SDL_RenderFillRect(renderer,&markedRect); 153 154 if (markedText[0]) 155 { 156 #ifdef HAVE_SDL_TTF 157 if (cursor) 158 { 159 char *p = utf8_advance(markedText, cursor); 160 char c = 0; 161 if (!p) 162 p = &markedText[strlen(markedText)]; 163 164 c = *p; 165 *p = 0; 166 TTF_SizeUTF8(font, markedText, &w, 0); 167 cursorRect.x += w; 168 *p = c; 169 } 170 SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, markedText, textColor); 171 SDL_Rect dest = {markedRect.x, markedRect.y, textSur->w, textSur->h }; 172 TTF_SizeUTF8(font, markedText, &w, &h); 173 SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer,textSur); 174 SDL_FreeSurface(textSur); 175 176 SDL_RenderCopy(renderer,texture,NULL,&dest); 177 SDL_DestroyTexture(texture); 178 #endif 179 180 underlineRect = markedRect; 181 underlineRect.y += (h - 2); 182 underlineRect.h = 2; 183 underlineRect.w = w; 184 185 SDL_SetRenderDrawColor(renderer, 0,0,0,0); 186 SDL_RenderFillRect(renderer,&markedRect); 187 } 188 189 SDL_SetRenderDrawColor(renderer, 0,0,0,0); 190 SDL_RenderFillRect(renderer,&cursorRect); 191 192 SDL_SetTextInputRect(&markedRect); 193 } 194 195 void Redraw() { 196 int i; 197 for (i = 0; i < state->num_windows; ++i) { 198 SDL_Renderer *renderer = state->renderers[i]; 199 if (state->windows[i] == NULL) 200 continue; 201 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); 202 SDL_RenderClear(renderer); 203 204 _Redraw(renderer); 205 206 SDL_RenderPresent(renderer); 207 } 208 } 209 210 int main(int argc, char *argv[]) { 211 int i, done; 212 SDL_Event event; 213 const char *fontname = DEFAULT_FONT; 214 215 /* Enable standard application logging */ 216 SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); 217 218 /* Initialize test framework */ 219 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); 220 if (!state) { 221 return 1; 222 } 223 for (i = 1; i < argc;i++) { 224 SDLTest_CommonArg(state, i); 225 } 226 for (argc--, argv++; argc > 0; argc--, argv++) 227 { 228 if (strcmp(argv[0], "--help") == 0) { 229 usage(); 230 return 0; 231 } 232 233 else if (strcmp(argv[0], "--font") == 0) 234 { 235 argc--; 236 argv++; 237 238 if (argc > 0) 239 fontname = argv[0]; 240 else { 241 usage(); 242 return 0; 243 } 244 } 245 } 246 247 if (!SDLTest_CommonInit(state)) { 248 return 2; 249 } 250 251 252 #ifdef HAVE_SDL_TTF 253 /* Initialize fonts */ 254 TTF_Init(); 255 256 font = TTF_OpenFont(fontname, DEFAULT_PTSIZE); 257 if (! font) 258 { 259 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to find font: %s\n", TTF_GetError()); 260 exit(-1); 261 } 262 #endif 263 264 SDL_Log("Using font: %s\n", fontname); 265 atexit(SDL_Quit); 266 267 InitInput(); 268 /* Create the windows and initialize the renderers */ 269 for (i = 0; i < state->num_windows; ++i) { 270 SDL_Renderer *renderer = state->renderers[i]; 271 SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); 272 SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); 273 SDL_RenderClear(renderer); 274 } 275 Redraw(); 276 /* Main render loop */ 277 done = 0; 278 while (!done) { 279 /* Check for events */ 280 while (SDL_PollEvent(&event)) { 281 SDLTest_CommonEvent(state, &event, &done); 282 switch(event.type) { 283 case SDL_KEYDOWN: { 284 switch (event.key.keysym.sym) 285 { 286 case SDLK_RETURN: 287 text[0]=0x00; 288 Redraw(); 289 break; 290 case SDLK_BACKSPACE: 291 { 292 int textlen=SDL_strlen(text); 293 294 do { 295 if (textlen==0) 296 { 297 break; 298 } 299 if ((text[textlen-1] & 0x80) == 0x00) 300 { 301 /* One byte */ 302 text[textlen-1]=0x00; 303 break; 304 } 305 if ((text[textlen-1] & 0xC0) == 0x80) 306 { 307 /* Byte from the multibyte sequence */ 308 text[textlen-1]=0x00; 309 textlen--; 310 } 311 if ((text[textlen-1] & 0xC0) == 0xC0) 312 { 313 /* First byte of multibyte sequence */ 314 text[textlen-1]=0x00; 315 break; 316 } 317 } while(1); 318 319 Redraw(); 320 } 321 break; 322 } 323 324 if (done) 325 { 326 break; 327 } 328 329 SDL_Log("Keyboard: scancode 0x%08X = %s, keycode 0x%08X = %s\n", 330 event.key.keysym.scancode, 331 SDL_GetScancodeName(event.key.keysym.scancode), 332 event.key.keysym.sym, SDL_GetKeyName(event.key.keysym.sym)); 333 break; 334 335 case SDL_TEXTINPUT: 336 if (event.text.text[0] == '\0' || event.text.text[0] == '\n' || 337 markedRect.w < 0) 338 break; 339 340 SDL_Log("Keyboard: text input \"%s\"\n", event.text.text); 341 342 if (SDL_strlen(text) + SDL_strlen(event.text.text) < sizeof(text)) 343 SDL_strlcat(text, event.text.text, sizeof(text)); 344 345 SDL_Log("text inputed: %s\n", text); 346 347 /* After text inputed, we can clear up markedText because it */ 348 /* is committed */ 349 markedText[0] = 0; 350 Redraw(); 351 break; 352 353 case SDL_TEXTEDITING: 354 SDL_Log("text editing \"%s\", selected range (%d, %d)\n", 355 event.edit.text, event.edit.start, event.edit.length); 356 357 strcpy(markedText, event.edit.text); 358 cursor = event.edit.start; 359 Redraw(); 360 break; 361 } 362 break; 363 364 } 365 } 366 } 367 CleanupVideo(); 368 SDLTest_CommonQuit(state); 369 return 0; 370 } 371 372 373 /* vi: set ts=4 sw=4 expandtab: */ 374