1 /**************************************************************************
2 practice.c
3 -  description: practice module
4 -------------------
5 begin                : Friday Jan 25, 2003
6 copyright            : (C) 2003 by Jesse Andrews
7 email                : jdandr2@uky.edu
8 
9 Revised extensively: 2007 and 2008
10 David Bruce <davidstuartbruce@gmail.com>
11 Revised extensively: 2008
12 Sreyas Kurumanghat <k.sreyas@gmail.com>
13 ***************************************************************************/
14 
15 /***************************************************************************
16 *                                                                         *
17 *   This program is free software; you can redistribute it and/or modify  *
18 *   it under the terms of the GNU General Public License as published by  *
19 *   the Free Software Foundation; either version 2 of the License, or     *
20 *   (at your option) any later version.                                   *
21 *                                                                         *
22 ***************************************************************************/
23 
24 #include "globals.h"
25 #include "funcs.h"
26 #include "SDL_extras.h"
27 #include "convert_utf.h"
28 
29 #define MAX_PHRASES 256
30 #define MAX_PHRASE_LENGTH 256
31 #define MAX_WRAP_LINES 10
32 #define TEXT_HEIGHT 28
33 #define SPRITE_FRAME_TIME 200
34 /* "Local globals" for practice.c */
35 static int fontsize = 0;
36 static int medfontsize = 0;
37 static int bigfontsize = 0;
38 
39 /* Surfaces for things we want to pre-render: */
40 static SDL_Surface* hands = NULL;
41 static SDL_Surface* hand_shift[3] = {NULL};
42 static SDL_Surface* keyboard = NULL;
43 static SDL_Surface* keypress1 = NULL;
44 static SDL_Surface* keypress2 = NULL;
45 static SDL_Surface* hand[11] = {NULL};
46 static sprite* tux_stand = NULL;
47 static sprite* tux_win = NULL;
48 static SDL_Surface* time_label_srfc = NULL;
49 static SDL_Surface* chars_label_srfc = NULL;
50 static SDL_Surface* cpm_label_srfc = NULL;
51 static SDL_Surface* wpm_label_srfc = NULL;
52 static SDL_Surface* errors_label_srfc = NULL;
53 static SDL_Surface* accuracy_label_srfc = NULL;
54 
55 
56 static wchar_t phrases[MAX_PHRASES][MAX_PHRASE_LENGTH];
57 static Mix_Chunk* wrong = NULL;
58 static Mix_Chunk* cheer = NULL;
59 
60 
61 static int phrase_draw_width = 0; /* How wide before text needs wrapping */
62 static int num_phrases = 0;
63 
64 
65 /* Locations for blitting  */
66 
67 /* Three main areas within window: */
68 static SDL_Rect left_pane;
69 static SDL_Rect top_pane;
70 static SDL_Rect bottom_pane;
71 
72 /* Locations within left pane: */
73 static SDL_Rect tux_loc;
74 static SDL_Rect time_label;
75 static SDL_Rect time_rect;
76 static SDL_Rect chars_typed_label;
77 static SDL_Rect chars_typed_rect;
78 static SDL_Rect cpm_label;
79 static SDL_Rect cpm_rect;
80 static SDL_Rect wpm_label;
81 static SDL_Rect wpm_rect;
82 static SDL_Rect errors_label;
83 static SDL_Rect errors_rect;
84 static SDL_Rect accuracy_label;
85 static SDL_Rect accuracy_rect;
86 
87 /* Locations within top pane: */
88 static SDL_Rect phr_text_rect;
89 static SDL_Rect user_text_rect;
90 
91 /* Locations within bottom pane: */
92 static SDL_Rect hand_loc;
93 static SDL_Rect nextletter_rect;
94 //static SDL_Rect letter_loc;
95 static SDL_Rect keyboard_loc;
96 
97 
98 /*local function prototypes: */
99 static int load_phrases(const char* phrase_file);
100 static int find_next_wrap(const wchar_t* wstr, int font_size, int width);
101 static void recalc_positions(void);
102 static void calc_font_sizes(void);
103 static int create_labels(void);
104 static void display_next_letter(const wchar_t* str, Uint16 index);
105 static int practice_load_media(void);
106 static void practice_unload_media(void);
107 //static void show(char t);
108 SDL_Surface* GetKeypress1(int index);
109 SDL_Surface* GetKeypress2(int index);
110 SDL_Surface* GetWrongKeypress(int index);
111 static void print_load_results(void);
112 
113 /************************************************************************/
114 /*                                                                      */
115 /*         "Public" functions (callable throughout program)             */
116 /*                                                                      */
117 /************************************************************************/
118 
119 /*  --------  This is the main function for the 'Practice' activity. ------ */
Phrases(wchar_t * pphrase)120 int Phrases(wchar_t* pphrase )
121 {
122   /* FIXME make variable names more descriptive */
123   Uint32 start = 0, a = 0, tuxtime = 0;
124   int quit = 0,
125       i = 0,
126       cursor = 0,
127       wrap_pt = 0,
128       prev_wrap = 0,
129       total = 0,
130       state = 0;
131   int once_only = 0;
132   int correct_chars = 0;
133   int wrong_chars = 0;
134   float accuracy = 0;
135   int cur_phrase = 0;
136   int keytimes[MAX_PHRASE_LENGTH] = {0};
137   char time_str[20];
138   char chars_typed_str[20];
139   char cpm_str[20];
140   char wpm_str[20];
141   char errors_str[20];
142   char accuracy_str[20];
143   SDL_Surface* tmpsurf = NULL;
144 
145   /* Load all needed graphics, strings, sounds.... */
146   if (!practice_load_media())
147   {
148     fprintf(stderr, "Phrases() - practice_load_media() failed, returning.\n\n");
149     return 0;
150   }
151 
152   /* If we got a phrase string arg, use it, otherwise we */
153   /* load practice phrases from  the default file:       */
154   if (pphrase != NULL
155     && wcslen(pphrase) > 0)
156   {
157     wcsncpy(phrases[0], pphrase, MAX_PHRASE_LENGTH);
158     num_phrases = 1;
159     once_only = 1;
160   }
161   else
162   {
163     num_phrases = load_phrases("phrases.txt");
164   }
165   /* Set up positions for blitting: */
166   recalc_positions();
167 
168   start = tuxtime = SDL_GetTicks();
169 
170 
171   /* Begin main event loop for "Practice" activity:  -------- */
172   do
173   {
174     switch (state)
175     {
176       /* state = 0 means the phrase has changed and we need to reset      */
177       /* all the variables related to progress of this phrase; we also    */
178       /* need a complete redraw (state = 1)                               */
179       case 0:
180        /* reset other variables related to progress within phrase: */
181         for (i = 0; i < MAX_PHRASE_LENGTH; i++)
182           keytimes[i] = 0;
183         time_str[0] = '\0';
184         chars_typed_str[0] = '\0';
185         cpm_str[0] = '\0';
186         wpm_str[0] = '\0';
187         errors_str[0] = '\0';
188         accuracy_str[0] = '\0';
189         total = 0;
190         cursor = 0;
191         wrap_pt = 0;
192         prev_wrap = 0;
193         correct_chars = 0;
194         wrong_chars = 0;
195         /* No 'break;' so we drop through to do case 1 as well : */
196 
197       /* state == 1 means complete redraw needed                          */
198       /* If we do this without the case 0 resets, it means the wrap point */
199       /* has changed and the text needs redrawing, or that the screen     */
200       /* size has changed:                                                */
201       case 1:
202         /* Draw bkgd before we start */
203         /* NOTE the keyboard and hands will get drawn when we drop through to case 2: */
204         SDL_BlitSurface(CurrentBkgd(), NULL, screen, NULL);
205         /* Note - the validity of all these surfaces is tested */
206         /* in Practice_Load_Media(), so we should be safe.     */
207 
208         /* Draw Tux:   */
209         SDL_BlitSurface(tux_stand->frame[tux_stand->cur], NULL, screen, &tux_loc);
210         /* Draw all the labels for the typing stats: */
211         SDL_BlitSurface(time_label_srfc, NULL, screen, &time_label);
212         SDL_BlitSurface(chars_label_srfc, NULL, screen, &chars_typed_label);
213         SDL_BlitSurface(cpm_label_srfc, NULL, screen, &cpm_label);
214         SDL_BlitSurface(wpm_label_srfc, NULL, screen, &wpm_label);
215         SDL_BlitSurface(errors_label_srfc, NULL, screen, &errors_label);
216         SDL_BlitSurface(accuracy_label_srfc, NULL, screen, &accuracy_label);
217 
218 
219         /* Find wrapping point: */
220         wrap_pt = find_next_wrap(&phrases[cur_phrase][prev_wrap],
221                                   medfontsize, phrase_draw_width);
222 
223         /* Draw the phrase to be typed up to the next wrapping point: */
224         DEBUGCODE
225         {
226           wchar_t buf[200];
227           wcsncpy(buf, &phrases[cur_phrase][prev_wrap], wrap_pt + 1);
228           buf[wrap_pt + 1]= '\0';
229           fprintf(stderr, "wrap_pt = %d\t cursor = %d\t prev_wrap = %d\n",
230                           wrap_pt, cursor, prev_wrap);
231           fprintf(stderr, "Phrase to be typed is: %S\n", buf);
232         }
233 
234         tmpsurf = BlackOutline_w(&phrases[cur_phrase][prev_wrap],
235                                   medfontsize, &white, wrap_pt + 1);
236 
237         if (tmpsurf)
238         {
239           SDL_BlitSurface(tmpsurf, NULL, screen, &phr_text_rect);
240           SDL_FreeSurface(tmpsurf);
241           tmpsurf = NULL;
242         }
243 
244         /* Draw the text the player has typed so far: */
245 
246         tmpsurf = BlackOutline_w(&phrases[cur_phrase][prev_wrap],
247                                   medfontsize, &white,
248                                   cursor - prev_wrap);
249 
250         DEBUGCODE
251         {
252           wchar_t buf[200];
253           wcsncpy(buf, &phrases[cur_phrase][prev_wrap], cursor - prev_wrap);
254           buf[cursor - prev_wrap]= '\0';
255           fprintf(stderr, "wrap_pt = %d\t cursor = %d\t prev_wrap = %d\n",
256                           wrap_pt, cursor, prev_wrap);
257           fprintf(stderr, "Text typed so far is: %S\n", buf);
258         }
259 
260         if (tmpsurf)
261         {
262           SDL_BlitSurface(tmpsurf, NULL, screen, &user_text_rect);
263           SDL_FreeSurface(tmpsurf);
264           tmpsurf = NULL;
265         }
266 
267         /* Update timer: */
268         tmpsurf = BlackOutline(time_str, fontsize, &white);
269         if (tmpsurf)
270         {
271           SDL_BlitSurface(tmpsurf, NULL, screen, &time_rect);
272           SDL_FreeSurface(tmpsurf);
273           tmpsurf = NULL;
274         }
275 
276       /* state == 2 means user has pressed key, either correct or incorrect */
277       case 2:
278         start = SDL_GetTicks();
279         SDL_BlitSurface(CurrentBkgd(), &hand_loc, screen, &hand_loc);
280         SDL_BlitSurface(hands, NULL, screen, &hand_loc);
281         SDL_BlitSurface(keyboard, NULL, screen, &keyboard_loc);
282         /* Update entire screen */
283         SDL_UpdateRect(screen, 0, 0, 0, 0);
284 
285         state = 3;
286         break;
287 
288 
289       case 3: /* Wind up here the next time through the loop: */
290               /* If no typing for 0.5 sec, display hint:      */
291         if (SDL_GetTicks() - start > 500)
292         {
293 
294           /* Show finger hint, if available. Note that GetFinger() */
295           /* returns negative values on error and never returns a  */
296           /* value greater than 9.                                 */
297           int key = GetIndex(phrases[cur_phrase][cursor]);
298           int fing = GetFinger(key);
299           int shift = GetShift(key);
300           keypress1 = GetKeypress1(key);
301           keypress2 = GetKeypress2(key);
302 
303           SDL_BlitSurface(CurrentBkgd(), &hand_loc, screen, &hand_loc);
304           SDL_BlitSurface(hands, NULL, screen, &hand_loc);
305 
306           if (fing >= 0)
307             SDL_BlitSurface(hand[fing], NULL, screen, &hand_loc);
308           SDL_BlitSurface(hand_shift[shift], NULL, screen, &hand_loc);
309 
310           if (keypress1)
311           {
312             SDL_BlitSurface(keypress1, NULL, screen, &keyboard_loc);
313             SDL_FreeSurface(keypress1);
314             keypress1 = NULL;
315           }
316 
317           if (keypress2)
318           {
319             SDL_BlitSurface(keypress2, NULL, screen, &keyboard_loc);
320             SDL_FreeSurface(keypress2);
321             keypress2 = NULL;
322           }
323 
324           state = 4;
325         }
326         break;
327 
328       case 4:
329         /* After 0.75 sec, hint starts flashing (alternating states 5 and 6 with delays) */
330         if (SDL_GetTicks() - start > 750)
331         {
332           state = 5;
333         }
334         break;
335 
336       case 5:
337         SDL_BlitSurface(CurrentBkgd(), &hand_loc, screen, &hand_loc);
338         SDL_BlitSurface(hands, NULL, screen, &hand_loc);
339         SDL_BlitSurface(keyboard, NULL, screen, &keyboard_loc);
340         state = 14;
341         break;
342 
343       case 6:
344       {
345         int key = GetIndex(phrases[cur_phrase][cursor]);
346         int fing = GetFinger(key);
347         int shift = GetShift(key);
348         keypress1 = GetKeypress1(key);
349         keypress2 = GetKeypress2(key);
350 
351         SDL_BlitSurface(CurrentBkgd(), &hand_loc, screen, &hand_loc);
352         SDL_BlitSurface(hands, NULL, screen, &hand_loc);
353 
354         if (fing >= 0)
355           SDL_BlitSurface(hand[fing], NULL, screen, &hand_loc);
356 
357         SDL_BlitSurface(hand_shift[shift], NULL, screen, &hand_loc);
358 
359         if (keypress1)
360         {
361           SDL_BlitSurface(keypress1, NULL, screen, &keyboard_loc);
362           SDL_FreeSurface(keypress1);
363           keypress1 = NULL;
364         }
365 
366         if (keypress2)
367         {
368           SDL_BlitSurface(keypress2, NULL, screen, &keyboard_loc);
369           SDL_FreeSurface(keypress2);
370           keypress2 = NULL;
371         }
372 
373         state = 13;
374         break;
375       }
376 
377       default:
378         state -= 2; // this is to make the flashing slower
379 
380     }  /*  ----------- End of switch(state) statement-------------- */
381 
382     /* This blits the next character onto the screen in a large font: */
383     display_next_letter(phrases[cur_phrase], cursor);
384 
385     while  (SDL_PollEvent(&event))
386     {
387       if (event.type == SDL_KEYDOWN)
388       {
389         int key = GetIndex((wchar_t)event.key.keysym.unicode);
390         int shift_pressed = event.key.keysym.mod&KMOD_SHIFT;
391         char tmp = -1;
392 
393         /* TODO I must be missing something - why aren't we just looking at */
394         /* the event.key.keysym.unicode value instead of going through this */
395         /* giant switch statement?                                          */
396 
397         switch(event.key.keysym.sym)
398         {
399           case  SDLK_ESCAPE:
400             if (Pause() == 1)
401                quit = 1;
402             // continue loop and/or redraw screen
403             state = 1;
404             break;
405 
406           case  SDLK_F10:
407             SwitchScreenMode();
408             recalc_positions();
409             create_labels();
410             state = 1;
411             break;
412 
413           case  SDLK_DOWN: //practice next phase in list
414             if (cur_phrase < num_phrases - 1)
415             {
416               cur_phrase++;
417               state = 0;
418             }
419             break;
420 
421           case  SDLK_UP: //practice previous phase in list
422             if (cur_phrase > 0)
423             {
424               cur_phrase--;
425               state = 0;
426             }
427             break;
428 
429           case  SDLK_BACKQUOTE:
430             if(shift_pressed)
431               tmp='~';
432             else
433               tmp='`';
434             break;
435 
436           case SDLK_COMMA:
437             if(shift_pressed)
438               tmp='<';
439             else
440               tmp=',';
441             break;
442 
443           case SDLK_MINUS:
444             if(shift_pressed)
445               tmp='_';
446             else
447               tmp='-';
448             break;
449 
450           case SDLK_PERIOD:
451             if(shift_pressed)
452               tmp='>';
453             else
454               tmp='.';
455             break;
456 
457           case SDLK_SLASH:
458             if(shift_pressed)
459               tmp='?';
460             else
461               tmp='/';
462             break;
463 
464           case SDLK_0:
465             if(shift_pressed)
466               tmp=')';
467             else
468               tmp='0';
469             break;
470 
471           case SDLK_1:
472             if(shift_pressed)
473               tmp='!';
474             else
475               tmp='1';
476             break;
477 
478           case SDLK_2:
479             if(shift_pressed)
480               tmp='@';
481             else
482               tmp='2';
483             break;
484 
485           case SDLK_3:
486             if(shift_pressed)
487               tmp='#';
488             else
489               tmp='3';
490             break;
491 
492           case SDLK_4:
493             if(shift_pressed)
494               tmp='$';
495             else
496               tmp='4';
497             break;
498 
499           case SDLK_5:
500             if(shift_pressed)
501               tmp='%';
502             else
503               tmp='5';
504             break;
505 
506           case SDLK_6:
507             if(shift_pressed)
508               tmp='^';
509             else
510               tmp='6';
511             break;
512 
513           case SDLK_7:
514             if(shift_pressed)
515               tmp='&';
516             else
517               tmp='7';
518             break;
519 
520           case SDLK_8:
521             if(shift_pressed)
522               tmp='*';
523             else
524               tmp='8';
525             break;
526 
527           case SDLK_9:
528             if(shift_pressed)
529               tmp='(';
530             else
531               tmp='9';
532             break;
533 
534           case SDLK_SEMICOLON:
535             if(shift_pressed)
536               tmp=':';
537             else
538               tmp=';';
539             break;
540 
541           case SDLK_EQUALS:
542             if(shift_pressed)
543               tmp='+';
544             else
545               tmp='=';
546             break;
547 
548           case SDLK_LEFTBRACKET:
549             if(shift_pressed)
550               tmp='{';
551             else
552               tmp='[';
553             break;
554 
555           case SDLK_BACKSLASH:
556             if(shift_pressed)
557               tmp='|';
558             else
559               tmp='\\';
560             break;
561 
562           case SDLK_RIGHTBRACKET:
563             if(shift_pressed)
564               tmp='}';
565             else
566               tmp=']';
567             break;
568 
569           case SDLK_QUOTE:
570             if(shift_pressed)
571               tmp='"';
572             else
573               tmp='\'';
574             break;
575 
576           case SDLK_SPACE:  tmp=' ';  break;
577           case SDLK_a:      tmp='a';  break;
578           case SDLK_b:      tmp='b';  break;
579           case SDLK_c:      tmp='c';  break;
580           case SDLK_d:      tmp='d';  break;
581           case SDLK_e:      tmp='e';  break;
582           case SDLK_f:      tmp='f';  break;
583           case SDLK_g:      tmp='g';  break;
584           case SDLK_h:      tmp='h';  break;
585           case SDLK_i:      tmp='i';  break;
586           case SDLK_j:      tmp='j';  break;
587           case SDLK_k:      tmp='k';  break;
588           case SDLK_l:      tmp='l';  break;
589           case SDLK_m:      tmp='m';  break;
590           case SDLK_n:      tmp='n';  break;
591           case SDLK_o:      tmp='o';  break;
592           case SDLK_p:      tmp='p';  break;
593           case SDLK_q:      tmp='q';  break;
594           case SDLK_r:      tmp='r';  break;
595           case SDLK_s:      tmp='s';  break;
596           case SDLK_t:      tmp='t';  break;
597           case SDLK_u:      tmp='u';  break;
598           case SDLK_v:      tmp='v';  break;
599           case SDLK_w:      tmp='w';  break;
600           case SDLK_x:      tmp='x';  break;
601           case SDLK_y:      tmp='y';  break;
602           case SDLK_z:      tmp='z';  break;
603           /* ignore other keys: */
604           default: break;
605         }
606 
607         /* If state has changed as direct result of keypress (e.g. F10), leave */
608         /* poll event loop so we don't treat it as a simple 'wrong' key: */
609         if (state == 0
610          || state == 1)
611           continue;
612 
613         /* Change to uppercase if shift used */
614         if(shift_pressed)
615           tmp=toupper(tmp);
616 
617         if ( key != -1 )
618           updatekeylist(key,tmp);
619 
620         /* Record elapsed time for this keypress and update running total: */
621         a = SDL_GetTicks();
622         keytimes[cursor] = a - start;
623         start = a;
624 
625         total += keytimes[cursor];
626         sprintf(time_str, "%.2f %s", (float) total / 1000, N_("sec"));
627         sprintf(chars_typed_str, "%d", correct_chars);
628         sprintf(cpm_str, "%.1f", (float) correct_chars /((float)total/60000));
629         sprintf(wpm_str, "%.1f", (float) ((float) correct_chars/5) /((float) total/60000));
630         sprintf(errors_str, "%d", wrong_chars);
631 
632         /* Calculate accuracy, avoiding divide-by-zero error: */
633         if (correct_chars + wrong_chars == 0)
634           accuracy = 1;
635         else
636           accuracy = (float)correct_chars/((float) (correct_chars + wrong_chars));
637         sprintf(accuracy_str, "%.1f%%", accuracy * 100);
638 
639 
640         /****************************************************/
641         /*  ---------- If user typed correct character, handle it: --------------- */
642         if (phrases[cur_phrase][cursor] == event.key.keysym.unicode)
643         {
644           cursor++;
645           correct_chars++;
646 
647           /* Handle wrapping if we are at the end of the current display. */
648           /* NOTE now also checking for space at end of line so we wrap   */
649           /* automatically without waiting for user to type invisible     */
650           /* space                                                        */
651           if (cursor >= prev_wrap + wrap_pt + 2) /* wrap onto next line */
652           {
653             /* This will cause the next line of the phrase to be drawn: */
654             prev_wrap = prev_wrap + wrap_pt + 2;
655             state = 1;
656           }
657           else if ((cursor == prev_wrap + wrap_pt + 1) /* skip terminal space */
658                && (phrases[cur_phrase][cursor] == ' '))
659           {
660             /* Need to increment cursor another time in this case: */
661             cursor ++;
662             prev_wrap = prev_wrap + wrap_pt + 2;
663             state = 1;
664           }
665           else
666             state = 2;
667 
668           /* Redraw everything below any "completed" lines of input text, */
669           /* except we don't want to redraw keyboard to avoid flicker:    */
670           tmpsurf = BlackOutline_w(&phrases[cur_phrase][prev_wrap],
671                                    medfontsize, &white,
672                                    cursor - prev_wrap);
673 
674           if (tmpsurf)
675           {
676             SDL_BlitSurface(CurrentBkgd(), &user_text_rect, screen, &user_text_rect);
677             SDL_BlitSurface(tmpsurf, NULL, screen, &user_text_rect);
678             SDL_FreeSurface(tmpsurf);
679             tmpsurf = NULL;
680           }
681 
682 
683           tmpsurf = BlackOutline(time_str, fontsize, &white);
684           if (tmpsurf)
685           {
686             SDL_BlitSurface(CurrentBkgd(), &time_rect, screen, &time_rect);
687             SDL_BlitSurface(tmpsurf, NULL, screen, &time_rect);
688             SDL_FreeSurface(tmpsurf);
689             tmpsurf = NULL;
690           }
691 
692           tmpsurf = BlackOutline(chars_typed_str, fontsize, &white);
693           if (tmpsurf)
694           {
695             SDL_BlitSurface(CurrentBkgd(), &chars_typed_rect, screen, &chars_typed_rect);
696             SDL_BlitSurface(tmpsurf, NULL, screen, &chars_typed_rect);
697             SDL_FreeSurface(tmpsurf);
698             tmpsurf = NULL;
699           }
700 
701           tmpsurf = BlackOutline(cpm_str, fontsize, &white);
702           if (tmpsurf)
703           {
704             SDL_BlitSurface(CurrentBkgd(), &cpm_rect, screen, &cpm_rect);
705             SDL_BlitSurface(tmpsurf, NULL, screen, &cpm_rect);
706             SDL_FreeSurface(tmpsurf);
707             tmpsurf = NULL;
708           }
709 
710           tmpsurf = BlackOutline(wpm_str, fontsize, &white);
711           if (tmpsurf)
712           {
713             SDL_BlitSurface(CurrentBkgd(), &wpm_rect, screen, &wpm_rect);
714             SDL_BlitSurface(tmpsurf, NULL, screen, &wpm_rect);
715             SDL_FreeSurface(tmpsurf);
716             tmpsurf = NULL;
717           }
718 
719           tmpsurf = BlackOutline(errors_str, fontsize, &white);
720           if (tmpsurf)
721           {
722             SDL_BlitSurface(CurrentBkgd(), &errors_rect, screen, &errors_rect);
723             SDL_BlitSurface(tmpsurf, NULL, screen, &errors_rect);
724             SDL_FreeSurface(tmpsurf);
725             tmpsurf = NULL;
726           }
727 
728           tmpsurf = BlackOutline(accuracy_str, fontsize, &white);
729           if (tmpsurf)
730           {
731             SDL_BlitSurface(CurrentBkgd(), &accuracy_rect, screen, &accuracy_rect);
732             SDL_BlitSurface(tmpsurf, NULL, screen, &accuracy_rect);
733             SDL_FreeSurface(tmpsurf);
734             tmpsurf = NULL;
735           }
736 
737           SDL_Flip(screen);
738 
739           /* If player has completed phrase, celebrate! */
740           if (cursor == wcslen(phrases[cur_phrase]))
741           {
742             /* Draw Tux celebrating: */
743             {
744               int done = 0;
745 
746               PlaySound(cheer);
747 
748               while (!done)
749               {
750                 while (SDL_PollEvent(&event))
751                 {
752                   if ((event.type == SDL_KEYDOWN)
753                     ||(event.type == SDL_MOUSEBUTTONDOWN))
754                     done = 1;
755                 }
756 
757                 /* Draw Tux: */
758                 SDL_BlitSurface(CurrentBkgd(), &tux_loc, screen, &tux_loc);
759                 if (tux_win && tux_win->frame[tux_win->cur])
760                   SDL_BlitSurface(tux_win->frame[tux_win->cur], NULL, screen, &tux_loc);
761                 SDL_UpdateRect(screen, tux_loc.x, tux_loc.y, tux_loc.w, tux_loc.h);
762                 NEXT_FRAME(tux_win);
763                 SDL_Delay(200);
764               }
765             }
766 
767             /* if we are just doing a single phrase passed as arg to function, */
768             /* we stop here:                                                   */
769             if (once_only)
770               quit = 1;
771             else  /* means we are using the phrases from the file */
772             {
773               /* Go on to next phrase, or back to first one if all done */
774               if (cur_phrase < num_phrases)
775                 cur_phrase++;
776               else
777                 cur_phrase = 0;
778             }
779             state = 0;
780           }
781         }
782         else  /* -------- handle incorrect key press: -------------*/
783         {
784           // int key = GetIndex((wchar_t)event.key.keysym.unicode);
785           if ( key != -1 )
786           {
787             keypress1= GetWrongKeypress(key);
788 
789             if (keypress1) // avoid segfault if NULL
790             {
791               SDL_BlitSurface(keypress1, NULL, screen, &keyboard_loc);
792               SDL_FreeSurface(keypress1);
793             }
794           }
795           state = 2;
796 
797           /* Don't count shift keys as wrong: */
798           if (event.key.keysym.sym != SDLK_RSHIFT
799            && event.key.keysym.sym != SDLK_LSHIFT)
800           {
801             /* Also, don't count spacebar as wrong on first char */
802             /* after wrap because we automatically skip it above */
803             if((cursor != prev_wrap)
804              ||(event.key.keysym.sym != SDLK_SPACE))
805             {
806               wrong_chars++;
807               PlaySound(wrong);
808             }
809           }
810         }
811 
812       } /* End of "if(event.type == SDL_KEYDOWN)" block  --*/
813 
814     }  /* ----- End of SDL_PollEvent() loop -------------- */
815 
816     /* Draw next tux frame if appropriate: */
817     if ((SDL_GetTicks() - tuxtime) > SPRITE_FRAME_TIME)
818     {
819       tuxtime = SDL_GetTicks();
820 
821       SDL_BlitSurface(CurrentBkgd(), &tux_loc, screen, &tux_loc);
822 
823       if (tux_stand && tux_stand->frame[tux_stand->cur])
824         SDL_BlitSurface(tux_stand->frame[tux_stand->cur], NULL, screen, &tux_loc);
825       NEXT_FRAME(tux_stand);
826     }
827 
828     SDL_UpdateRect(screen, 0, 0, 0, 0);
829 //    SDL_Flip(screen);
830     SDL_Delay(30); /* FIXME should keep frame rate constant */
831 
832   }while (!quit);  /* ------- End of main event loop ------------- */
833 
834   savekeyboard();
835 
836   practice_unload_media();
837 
838   return quit;
839 }
840 
841 
842 
843 /************************************************************************/
844 /*                                                                      */
845 /*       "Private" functions (local to practice.c)                      */
846 /*                                                                      */
847 /************************************************************************/
848 
849 /* Select appropriate font sizes based on the screen we're working with: */
calc_font_sizes(void)850 static void calc_font_sizes(void)
851 {
852   fontsize = (screen->h)/28;
853   medfontsize = fontsize * 1.5;
854   bigfontsize = fontsize * 4;
855 }
856 
practice_load_media(void)857 static int practice_load_media(void)
858 {
859   int i;
860   char fn[FNLEN];
861   int load_failed = 0;
862   int labels_ok = 0;
863 
864   DEBUGCODE { printf("Entering practice_load_media\n"); }
865 
866 
867   /* load needed SDL_Surfaces: */
868   LoadBothBkgds("main_bkg.png");
869   hands = LoadImage("hands/hands.png", IMG_ALPHA);
870   hand_shift[0] = LoadImage("hands/none.png", IMG_ALPHA);
871   hand_shift[1] = LoadImage("hands/lshift.png", IMG_ALPHA);
872   hand_shift[2] = LoadImage("hands/rshift.png", IMG_ALPHA);
873   keyboard = LoadImage("keyboard/keyboard.png", IMG_ALPHA);
874 
875   for (i = 0; i < 10; i++)
876   {
877     sprintf(fn, "hands/%d.png", i);
878     hand[i] = LoadImage(fn, IMG_ALPHA);
879     if (!hand[i])
880       load_failed = 1;
881   }
882 
883   /* load tux sprites: */
884   tux_win = LoadSprite("tux/win", IMG_ALPHA);
885   tux_stand = LoadSprite("tux/stand", IMG_ALPHA);
886   /* load needed sounds: */
887   wrong = LoadSound("buzz.wav");
888   cheer = LoadSound("cheer.wav");
889 
890   /* load needed fonts: */
891   calc_font_sizes();
892 
893   /* create labels: */
894   labels_ok = create_labels();
895 
896   /* Get out if anything failed to load (except sounds): */
897   if (load_failed
898     ||!hands
899     ||!CurrentBkgd()
900     ||!tux_win
901     ||!tux_stand
902     ||!keyboard
903     ||!hand_shift[0]
904     ||!hand_shift[1]
905     ||!hand_shift[2]
906     ||!labels_ok)
907   {
908     fprintf(stderr, "practice_load_media() - failed to load needed media \n");
909     print_load_results();
910     return 0;
911   }
912 
913   /* Now render letters for glyphs in alphabet: */
914   /* This is used for keyboard graphic */
915   RenderLetters(fontsize);
916   GenerateKeyboard(keyboard);
917 
918   LOG("DONE - Loading practice media\n");
919   DEBUGCODE { printf("Leaving practice_load_media\n"); }
920   return 1;
921 }
922 
923 
924 
print_load_results(void)925 static void print_load_results(void)
926 {
927   LOG("\npractice - print_load_results:\n");
928  /* Get out if anything failed to load: */
929   if (!CurrentBkgd())
930     { LOG("CurrentBkgd() did not load\n");}
931   if (!hands)
932     { LOG("hands did not load\n");}
933   if (!tux_win)
934     { LOG("tux_win did not load\n");}
935   if (!tux_stand)
936     { LOG("tux_stand did not load\n");}
937   if (!keyboard)
938     { LOG("keyboard did not load\n");}
939   if (!hand_shift[0])
940     { LOG("hand_shift[0] did not load\n");}
941   if (!hand_shift[1])
942     { LOG("hand_shift[1] did not load\n");}
943   if (!hand_shift[2])
944     { LOG("hand_shift[2] did not load\n");}
945   if (!time_label_srfc)
946     { LOG("time_label_srfc did not load\n");}
947   if (!chars_label_srfc)
948     { LOG("chars_label_srfc did not load\n");}
949   if (!cpm_label_srfc)
950     { LOG("cpm_label_srfc did not load\n");}
951   if (!wpm_label_srfc)
952     { LOG("wpm_label_srfc did not load\n");}
953   if (!time_label_srfc)
954     { LOG("time_label_srfc did not load\n");}
955   if (!errors_label_srfc)
956     { LOG("errors_label_srfc did not load\n");}
957   if (!accuracy_label_srfc)
958     { LOG("accuracy_label_srfc did not load\n");}
959 
960   LOG("End print_load_results()\n\n");
961 }
962 
recalc_positions(void)963 static void recalc_positions(void)
964 {
965   int text_height;
966   calc_font_sizes();
967   text_height = fontsize * 1.5;
968 
969   DEBUGCODE
970   {
971     fprintf(stderr, "Entering recalc_positions(), screen is %d x %d\n", screen->w, screen->h);
972   }
973 
974   if (!keyboard
975     ||!tux_win
976     ||!tux_win->frame[0]
977     ||!hand[0])
978   {
979     fprintf(stderr, "recalc_positions() - needed ptr invalid - returning\n");
980   }
981 
982   /* Screen is divided into three areas or 'panes' : */
983   /*
984         *************************************
985         *        *                          *
986         * left   *           top            *
987         *        *                          *
988         *        ****************************
989         *        *                          *
990         *        *                          *
991         *        *          bottom          *
992         *        *                          *
993         *        *                          *
994         *************************************
995   */
996 
997   left_pane.x = 0;
998   left_pane.y = 0;
999   left_pane.w = screen->w * 0.25;
1000   left_pane.h = screen->h;
1001 
1002   top_pane.x = screen->w * 0.25;
1003   top_pane.y = 0;
1004   top_pane.w = screen->w * 0.75;
1005   top_pane.h = screen->h * 0.4;
1006 
1007   bottom_pane.x = screen->w * 0.25;
1008   bottom_pane.y = screen->h * 0.4;
1009   bottom_pane.w = screen->w * 0.75;
1010   bottom_pane.h = screen->h * 0.6;
1011 
1012   /* Set up all the locations within the left pane: */
1013   tux_loc.x = left_pane.x + 5;
1014   tux_loc.y = left_pane.y + 5;
1015   tux_loc.w = tux_stand->frame[0]->w;
1016   tux_loc.h = tux_stand->frame[0]->h;
1017 
1018   time_label.x = left_pane.x + 5;
1019   time_label.y = tux_loc.y + tux_loc.h;
1020   time_label.w = left_pane.w - 5;
1021   time_label.h = text_height;
1022 
1023   time_rect.x = left_pane.x + 5;
1024   time_rect.y = time_label.y + time_label.h;
1025   time_rect.w = left_pane.w - 5;
1026   time_rect.h = text_height;
1027 
1028   chars_typed_label.x = left_pane.x + 5;
1029   chars_typed_label.y = time_rect.y + time_rect.h;
1030   chars_typed_label.w = left_pane.w - 5;
1031   chars_typed_label.h = text_height;
1032 
1033   chars_typed_rect.x = left_pane.x + 5;
1034   chars_typed_rect.y = chars_typed_label.y + chars_typed_label.h;
1035   chars_typed_rect.w = left_pane.w - 5;
1036   chars_typed_rect.h = text_height;
1037 
1038   cpm_label.x = left_pane.x + 5;
1039   cpm_label.y = chars_typed_rect.y + chars_typed_rect.h;
1040   cpm_label.w = left_pane.w - 5;
1041   cpm_label.h = text_height;
1042 
1043   cpm_rect.x = left_pane.x + 5;
1044   cpm_rect.y = cpm_label.y + cpm_label.h;
1045   cpm_rect.w = left_pane.w - 5;
1046   cpm_rect.h = text_height;
1047 
1048   wpm_label.x = left_pane.x + 5;
1049   wpm_label.y = cpm_rect.y + cpm_rect.h;
1050   wpm_label.w = left_pane.w - 5;
1051   wpm_label.h = text_height;
1052 
1053   wpm_rect.x = left_pane.x + 5;
1054   wpm_rect.y = wpm_label.y + wpm_label.h;
1055   wpm_rect.w = left_pane.w - 5;
1056   wpm_rect.h = text_height;
1057 
1058   errors_label.x = left_pane.x + 5;
1059   errors_label.y = wpm_rect.y + wpm_rect.h;
1060   errors_label.w = left_pane.w - 5;
1061   errors_label.h = text_height;
1062 
1063   errors_rect.x = left_pane.x + 5;
1064   errors_rect.y = errors_label.y + errors_label.h;
1065   errors_rect.w = left_pane.w - 5;
1066   errors_rect.h = text_height;
1067 
1068   accuracy_label.x = left_pane.x + 5;
1069   accuracy_label.y = errors_rect.y + errors_rect.h;
1070   accuracy_label.w = left_pane.w - 5;
1071   accuracy_label.h = text_height;
1072 
1073   accuracy_rect.x = left_pane.x + 5;
1074   accuracy_rect.y = accuracy_label.y + accuracy_label.h;
1075   accuracy_rect.w = left_pane.w - 5;
1076   accuracy_rect.h = text_height;
1077 
1078   /* Set up all the locations within the top pane: */
1079   phr_text_rect.x = top_pane.x + 5;
1080   phr_text_rect.y = top_pane.y + top_pane.h * 0.3;
1081   phr_text_rect.w = top_pane.w - 5;
1082   phr_text_rect.h = medfontsize;
1083 
1084   /* we can't just use phr_text_rect.w to calc wrap */
1085   /* because SDL_BlitSurface() clobbers it: */
1086   phrase_draw_width = phr_text_rect.w;
1087 
1088   user_text_rect.x = top_pane.x + 5;
1089   user_text_rect.y = top_pane.y + top_pane.h * 0.6;
1090   user_text_rect.w = top_pane.w - 5;
1091   user_text_rect.h = medfontsize * 1.5;
1092 
1093   /* Set up all the locations within the bottom pane: */
1094   keyboard_loc.x = bottom_pane.x + bottom_pane.w/4 - keyboard->w/4;
1095   keyboard_loc.y = bottom_pane.y + 5;
1096   keyboard_loc.w = keyboard->w;
1097   keyboard_loc.h = keyboard->h;
1098 
1099   hand_loc.x = keyboard_loc.x;
1100   hand_loc.y = keyboard_loc.y + keyboard_loc.h + 20;
1101   hand_loc.w = (hand[0]->w);
1102   hand_loc.h = (hand[0]->h);
1103 
1104 
1105   nextletter_rect.x = keyboard_loc.x + keyboard_loc.w - 80;
1106   nextletter_rect.y = keyboard_loc.y + keyboard_loc.h;
1107   nextletter_rect.w = bigfontsize * 1.5;
1108   nextletter_rect.h = bigfontsize * 1.5;
1109 
1110 }
1111 
1112 
practice_unload_media(void)1113 static void practice_unload_media(void)
1114 {
1115   int i;
1116 
1117   FreeBothBkgds();
1118   FreeLetters();
1119 
1120   if (time_label_srfc)
1121     SDL_FreeSurface(time_label_srfc);
1122   time_label_srfc = NULL;
1123 
1124   if (chars_label_srfc)
1125     SDL_FreeSurface(chars_label_srfc);
1126   chars_label_srfc = NULL;
1127 
1128   if (cpm_label_srfc)
1129     SDL_FreeSurface(cpm_label_srfc);
1130   cpm_label_srfc = NULL;
1131 
1132   if (wpm_label_srfc)
1133     SDL_FreeSurface(wpm_label_srfc);
1134   wpm_label_srfc = NULL;
1135 
1136   if (errors_label_srfc)
1137     SDL_FreeSurface(errors_label_srfc);
1138   errors_label_srfc = NULL;
1139 
1140   if (accuracy_label_srfc)
1141     SDL_FreeSurface(accuracy_label_srfc);
1142   accuracy_label_srfc = NULL;
1143 
1144   if (hands)
1145     SDL_FreeSurface(hands);
1146   hands = NULL;
1147 
1148   for(i = 0; i < 3; i++)
1149   {
1150     if (hand_shift[i])
1151       SDL_FreeSurface(hand_shift[i]);
1152     hand_shift[i] = NULL;
1153   }
1154 
1155   if (keyboard)
1156     SDL_FreeSurface(keyboard);
1157   keyboard = NULL;
1158 
1159   for (i = 0; i < 10; i++)
1160   {
1161     if (hand[i])
1162       SDL_FreeSurface(hand[i]);
1163     hand[i] = NULL;
1164   }
1165 
1166   if (tux_stand)
1167   {
1168     FreeSprite(tux_stand);
1169     tux_stand = NULL;
1170   }
1171 
1172   if (tux_win)
1173   {
1174     FreeSprite(tux_win);
1175     tux_win = NULL;
1176   }
1177 
1178   if (cheer)
1179     Mix_FreeChunk(cheer);
1180   cheer = NULL;
1181 
1182   if (wrong)
1183     Mix_FreeChunk(wrong);
1184   wrong = NULL;
1185 }
1186 
1187 
1188 // /* looks like dead code: */
1189 // static void show(char t)
1190 // {
1191 //   SDL_Rect dst;
1192 //   SDL_Surface* s = NULL;
1193 //
1194 //   s = GetWhiteGlyph((int)t);
1195 //   if (!s)
1196 //     return;
1197 //
1198 //   dst.x = 320 - (s->w/2);
1199 //   dst.y = 100;
1200 //   dst.w = s->w;
1201 //   dst.h = s->h;
1202 //   SDL_BlitSurface(s, NULL, screen, &dst);
1203 // }
1204 
1205 
1206 /* Looks for phrases.txt in theme, then in default if not found, */
1207 /* loads it into phrases[][] array.  Returns number of phrases   */
1208 /* successfully loaded.                                          */
load_phrases(const char * phrase_file)1209 static int load_phrases(const char* phrase_file)
1210 {
1211   int found = 0;
1212   int num_phrases = 0;
1213   char buf[MAX_PHRASE_LENGTH];
1214   FILE* fp;
1215   char fn[FNLEN];
1216 
1217   /* If using theme, look there first: */
1218   if (!settings.use_english)
1219   {
1220     sprintf(fn , "%s/%s", settings.theme_data_path, phrase_file);
1221     if (CheckFile(fn))
1222       found = 1;
1223   }
1224 
1225   /* Now checking English: */
1226   if (!found)
1227   {
1228     sprintf(fn , "%s/%s", settings.default_data_path, phrase_file);
1229     if (CheckFile(fn))
1230       found = 1;
1231   }
1232 
1233   if (!found)
1234   {
1235     fprintf(stderr, "Could not find phrases file '%s' - cannot do Practice\n",
1236                    phrase_file);
1237     return 0;
1238   }
1239 
1240   DEBUGCODE { printf("load_phrases(): phrases file is '%s'\n", fn ); }
1241 
1242   /* We know it will open OK because we already ran CheckFile() on it */
1243   fp = fopen(fn, "r");
1244 
1245   /* So now copy each line into phrases array: */
1246   /* NOTE we need to convert to wchar_t so just fscanf won't work! */
1247   while (!feof(fp) && num_phrases <= MAX_PHRASES)
1248   {
1249     /* Similar check to above but compiler complains unless we */
1250     /* inspect return value of fscanf():                       */
1251     if (EOF != fscanf(fp, "%[^\n]\n", buf))
1252     {
1253       ConvertFromUTF8(phrases[num_phrases], buf, MAX_PHRASE_LENGTH);
1254       DEBUGCODE {printf("phrase %d:\t%S\n", num_phrases, phrases[num_phrases]);}
1255       num_phrases++;
1256     }
1257   }
1258 
1259   if (num_phrases > MAX_PHRASES)
1260   {
1261     fprintf(stderr, "File contains more than MAX_PHRASES - stopping\n");
1262     num_phrases = MAX_PHRASES;
1263   }
1264 
1265   fclose(fp);
1266 
1267   DOUT(num_phrases);
1268 
1269   return num_phrases;
1270 }
1271 
1272 
1273 
1274 /* Returns index relative to wstr of last char to be printed before break.  */
1275 /* (i.e. end of last full word that fits within 'width'                     */
find_next_wrap(const wchar_t * wstr,int font_size,int width)1276 static int find_next_wrap(const wchar_t* wstr, int font_size, int width)
1277 {
1278   wchar_t buf[MAX_PHRASE_LENGTH];
1279   char UTF8buf[MAX_PHRASE_LENGTH];
1280   SDL_Surface* s = NULL;
1281   int word_end = -1;
1282   int prev_word_end = -1;
1283 
1284   int i = 0;
1285   int phr_length = 0;
1286   int test_w = 0;      /* The width in pixels of the SDL-rendered string */
1287   /* FIXME get rid of this once overhaul done: */
1288 
1289   LOG("Entering find__next_wrap\n");
1290 
1291   /* Make sure args OK: */
1292   if (!wstr)
1293   {
1294     fprintf(stderr, "find_next_wrap() - error - invalid string argument\n");
1295     return -1;
1296   }
1297 
1298   DOUT(width);
1299   DEBUGCODE{ fprintf(stderr, "wstr = %S\n", wstr);}
1300 
1301   phr_length = wcslen(wstr);
1302 
1303   DOUT(phr_length);
1304   /* Using 'MAX_PHRASE_LENGTH - 1' will make sure our copied string is   */
1305   /* null-terminated, even if it didn't fit.                             */
1306 
1307   if (phr_length > (MAX_PHRASE_LENGTH - 1))
1308   {
1309     fprintf(stderr, "find_next_wrap() - error - phrase exceeds MAX_PHRASE_LENGTH\n");
1310     return -1;
1311   }
1312 
1313   /* The function will eventually return from within the loop */
1314   while(1)
1315   {
1316     /* Find next either next space or end of string to check width */
1317     for( ;
1318         i < phr_length  &&  wstr[i] != ' ';
1319         i++);
1320 
1321     DOUT(i);
1322 
1323     /* If exited because space found, back up one so we are at last char in word: */
1324     if (wstr[i] == ' ')
1325       word_end = i - 1;
1326     else
1327       word_end = i;
1328 
1329     /* See if we have exceeded the width */
1330     /* Copy string into buf and null terminate after point to be checked: */
1331     wcsncpy(buf, wstr, MAX_PHRASE_LENGTH);
1332     buf[word_end + 1] = '\0';
1333     DEBUGCODE{ fprintf(stderr, "buf = %S\n", buf);}
1334 
1335     /* Need to convert to UTF8 because couldn't get UNICODE version to work: */
1336     ConvertToUTF8(buf, UTF8buf, MAX_PHRASE_LENGTH);
1337     /*  Now check width of string: */
1338     s = SimpleText(UTF8buf, font_size, &white);
1339     if (!s)
1340     {
1341       /* An error occurred: */
1342       return -1;
1343     }
1344 
1345     test_w = s->w;
1346     SDL_FreeSurface(s);
1347     s = NULL;
1348 
1349     DOUT(test_w);
1350     DOUT(width);
1351     /* If we've gone past the width, the previous space was the wrap point, */
1352     /* whether or not we are at the end of the string:                      */
1353     if (test_w > width)
1354     {
1355       DEBUGCODE
1356       {
1357         fprintf(stderr, "width exceeded, returning end of previous word as wrap point\n");
1358         fprintf(stderr, "prev_word_end is %d\n", prev_word_end);
1359         fprintf(stderr, "leaving find_next_wrap()\n");
1360       }
1361       return prev_word_end;
1362     }
1363     else
1364     {
1365       if (i >= phr_length)
1366       {
1367         DEBUGCODE
1368         {
1369           fprintf(stderr, "width not exceeded, returning because end of string reached\n");
1370           fprintf(stderr, "word_end is %d\n", word_end);
1371         }
1372         /* We reached the end of the phrase without exceeding the width, */
1373         /* so just return our current position: */
1374         return word_end;
1375       }
1376       else
1377       {
1378         prev_word_end = word_end;
1379         i++;
1380       }
1381     }
1382   }
1383 }
1384 
1385 
1386 /* FIXME this isn't very safe because index could be out of allocated string, */
1387 /* and there a very good way to test for this within this function.           */
1388 /* Displays the next letter to be typed in a large font */
display_next_letter(const wchar_t * str,Uint16 index)1389 static void display_next_letter(const wchar_t *str, Uint16 index)
1390 {
1391   wchar_t ltr[2];
1392   SDL_Surface* s = NULL;
1393 
1394   if (!str || (index >= MAX_PHRASE_LENGTH))
1395     return;
1396 
1397   ltr[0] = str[index];
1398   ltr[1] = '\0';
1399 
1400   s = BlackOutline_w(ltr, bigfontsize, &white, 1);
1401 
1402   if (s)
1403   {
1404     SDL_BlitSurface(CurrentBkgd(), &nextletter_rect, screen, &nextletter_rect);
1405     SDL_BlitSurface(s, NULL, screen, &nextletter_rect);
1406     SDL_FreeSurface(s);
1407     s = NULL;
1408   }
1409 }
1410 
1411 
GetKeypress1(int index)1412 SDL_Surface* GetKeypress1(int index)
1413 {
1414 	char buf[50];
1415 	GetKeyPos(index,buf);
1416 	return (LoadImage(buf, IMG_ALPHA));
1417 }
1418 
1419 
GetWrongKeypress(int index)1420 SDL_Surface* GetWrongKeypress(int index)
1421 {
1422 	char buf[50];
1423 	GetWrongKeyPos(index,buf);
1424 	return (LoadImage(buf, IMG_ALPHA));
1425 }
1426 
1427 
GetKeypress2(int index)1428 SDL_Surface* GetKeypress2(int index)
1429 {
1430 
1431 	char buf[50];
1432 	GetKeyShift(index, buf);
1433 	return (LoadImage(buf, IMG_ALPHA));
1434 }
1435 
create_labels(void)1436 static int create_labels(void)
1437 {
1438   if (time_label_srfc)
1439     SDL_FreeSurface(time_label_srfc);
1440   time_label_srfc = BlackOutline(_("Time"), fontsize, &yellow);
1441 
1442   if (chars_label_srfc)
1443     SDL_FreeSurface(chars_label_srfc);
1444   chars_label_srfc = BlackOutline(_("Chars"), fontsize, &yellow);
1445 
1446   if (cpm_label_srfc)
1447     SDL_FreeSurface(cpm_label_srfc);
1448   cpm_label_srfc = BlackOutline(_("CPM"), fontsize, &yellow);
1449 
1450   if (wpm_label_srfc)
1451     SDL_FreeSurface(wpm_label_srfc);
1452   wpm_label_srfc = BlackOutline(_("WPM"), fontsize, &yellow);
1453 
1454   if (errors_label_srfc)
1455     SDL_FreeSurface(errors_label_srfc);
1456   errors_label_srfc = BlackOutline(_("Errors"), fontsize, &yellow);
1457 
1458   if (accuracy_label_srfc)
1459     SDL_FreeSurface(accuracy_label_srfc);
1460   accuracy_label_srfc = BlackOutline(_("Accuracy"), fontsize, &yellow);
1461 
1462   if (time_label_srfc
1463    && chars_label_srfc
1464    && cpm_label_srfc
1465    && wpm_label_srfc
1466    && errors_label_srfc
1467    && accuracy_label_srfc)
1468     return 1;
1469   else
1470     return 0;
1471 }
1472