• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<HTML
2><HEAD
3><TITLE
4>Handling the Keyboard</TITLE
5><META
6NAME="GENERATOR"
7CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
8"><LINK
9REL="HOME"
10TITLE="SDL Library Documentation"
11HREF="index.html"><LINK
12REL="UP"
13TITLE="Input handling"
14HREF="guideinput.html"><LINK
15REL="PREVIOUS"
16TITLE="Input handling"
17HREF="guideinput.html"><LINK
18REL="NEXT"
19TITLE="Examples"
20HREF="guideexamples.html"></HEAD
21><BODY
22CLASS="SECT1"
23BGCOLOR="#FFF8DC"
24TEXT="#000000"
25LINK="#0000ee"
26VLINK="#551a8b"
27ALINK="#ff0000"
28><DIV
29CLASS="NAVHEADER"
30><TABLE
31SUMMARY="Header navigation table"
32WIDTH="100%"
33BORDER="0"
34CELLPADDING="0"
35CELLSPACING="0"
36><TR
37><TH
38COLSPAN="3"
39ALIGN="center"
40>SDL Library Documentation</TH
41></TR
42><TR
43><TD
44WIDTH="10%"
45ALIGN="left"
46VALIGN="bottom"
47><A
48HREF="guideinput.html"
49ACCESSKEY="P"
50>Prev</A
51></TD
52><TD
53WIDTH="80%"
54ALIGN="center"
55VALIGN="bottom"
56>Chapter 3. Input handling</TD
57><TD
58WIDTH="10%"
59ALIGN="right"
60VALIGN="bottom"
61><A
62HREF="guideexamples.html"
63ACCESSKEY="N"
64>Next</A
65></TD
66></TR
67></TABLE
68><HR
69ALIGN="LEFT"
70WIDTH="100%"></DIV
71><DIV
72CLASS="SECT1"
73><H1
74CLASS="SECT1"
75><A
76NAME="GUIDEINPUTKEYBOARD"
77></A
78>Handling the Keyboard</H1
79><DIV
80CLASS="SECT2"
81><H2
82CLASS="SECT2"
83><A
84NAME="AEN271"
85></A
86>Keyboard Related Structures</H2
87><P
88>It should make it a lot easier to understand this tutorial is you are familiar with the data types involved in keyboard access, so I'll explain them first.</P
89><DIV
90CLASS="SECT3"
91><H3
92CLASS="SECT3"
93><A
94NAME="AEN274"
95></A
96>SDLKey</H3
97><P
98><SPAN
99CLASS="STRUCTNAME"
100>SDLKey</SPAN
101> is an enumerated type defined in SDL/include/SDL_keysym.h and detailed <A
102HREF="sdlkey.html"
103>here</A
104>. Each <SPAN
105CLASS="STRUCTNAME"
106>SDLKey</SPAN
107> symbol represents a key, <TT
108CLASS="LITERAL"
109>SDLK_a</TT
110> corresponds to the 'a' key on a keyboard, <TT
111CLASS="LITERAL"
112>SDLK_SPACE</TT
113> corresponds to the space bar, and so on.</P
114></DIV
115><DIV
116CLASS="SECT3"
117><H3
118CLASS="SECT3"
119><A
120NAME="AEN282"
121></A
122>SDLMod</H3
123><P
124>SDLMod is an enumerated type, similar to <SPAN
125CLASS="STRUCTNAME"
126>SDLKey</SPAN
127>, however it enumerates keyboard modifiers (Control, Alt, Shift). The full list of modifier symbols is <A
128HREF="sdlkey.html#SDLMOD"
129>here</A
130>. <SPAN
131CLASS="STRUCTNAME"
132>SDLMod</SPAN
133> values can be AND'd together to represent several modifiers.</P
134></DIV
135><DIV
136CLASS="SECT3"
137><H3
138CLASS="SECT3"
139><A
140NAME="AEN288"
141></A
142>SDL_keysym</H3
143><PRE
144CLASS="PROGRAMLISTING"
145>typedef struct{
146  Uint8 scancode;
147  SDLKey sym;
148  SDLMod mod;
149  Uint16 unicode;
150} SDL_keysym;</PRE
151><P
152>The <SPAN
153CLASS="STRUCTNAME"
154>SDL_keysym</SPAN
155> structure describes a key press or a key release. The <TT
156CLASS="STRUCTFIELD"
157><I
158>scancode</I
159></TT
160> field is hardware specific and should be ignored unless you know what your doing. The <TT
161CLASS="STRUCTFIELD"
162><I
163>sym</I
164></TT
165> field is the <SPAN
166CLASS="STRUCTNAME"
167>SDLKey</SPAN
168> value of the key being pressed or released. The <TT
169CLASS="STRUCTFIELD"
170><I
171>mod</I
172></TT
173> field describes the state of the keyboard modifiers at the time the key press or release occurred. So a value of <TT
174CLASS="LITERAL"
175>KMOD_NUM | KMOD_CAPS | KMOD_LSHIFT</TT
176> would mean that Numlock, Capslock and the left shift key were all press (or enabled in the case of the lock keys). Finally, the <TT
177CLASS="STRUCTFIELD"
178><I
179>unicode</I
180></TT
181> field stores the 16-bit unicode value of the key.</P
182><DIV
183CLASS="NOTE"
184><BLOCKQUOTE
185CLASS="NOTE"
186><P
187><B
188>Note: </B
189>It should be noted and understood that this field is only valid when the <SPAN
190CLASS="STRUCTNAME"
191>SDL_keysym</SPAN
192> is describing a key press, not a key release. Unicode values only make sense on a key press because the unicode value describes an international character and only key presses produce characters. More information on Unicode can be found at <A
193HREF="http://www.unicode.org"
194TARGET="_top"
195>www.unicode.org</A
196></P
197></BLOCKQUOTE
198></DIV
199><DIV
200CLASS="NOTE"
201><BLOCKQUOTE
202CLASS="NOTE"
203><P
204><B
205>Note: </B
206>Unicode translation must be enabled using the <A
207HREF="sdlenableunicode.html"
208><TT
209CLASS="FUNCTION"
210>SDL_EnableUNICODE</TT
211></A
212> function.</P
213></BLOCKQUOTE
214></DIV
215></DIV
216><DIV
217CLASS="SECT3"
218><H3
219CLASS="SECT3"
220><A
221NAME="AEN307"
222></A
223>SDL_KeyboardEvent</H3
224><PRE
225CLASS="PROGRAMLISTING"
226>typedef struct{
227  Uint8 type;
228  Uint8 state;
229  SDL_keysym keysym;
230} SDL_KeyboardEvent;</PRE
231><P
232>The <SPAN
233CLASS="STRUCTNAME"
234>SDL_KeyboardEvent</SPAN
235> describes a keyboard event (obviously). The <TT
236CLASS="STRUCTFIELD"
237><I
238>key</I
239></TT
240> member of the <A
241HREF="sdlevent.html"
242><SPAN
243CLASS="STRUCTNAME"
244>SDL_Event</SPAN
245></A
246> union is a <SPAN
247CLASS="STRUCTNAME"
248>SDL_KeyboardEvent</SPAN
249> structure. The <TT
250CLASS="STRUCTFIELD"
251><I
252>type</I
253></TT
254> field specifies whether the event is a key release (<TT
255CLASS="LITERAL"
256>SDL_KEYUP</TT
257>) or a key press (<TT
258CLASS="LITERAL"
259>SDL_KEYDOWN</TT
260>) event. The <TT
261CLASS="STRUCTFIELD"
262><I
263>state</I
264></TT
265> is largely redundant, it reports the same information as the <TT
266CLASS="STRUCTFIELD"
267><I
268>type</I
269></TT
270> field but uses different values (<TT
271CLASS="LITERAL"
272>SDL_RELEASED</TT
273> and <TT
274CLASS="LITERAL"
275>SDL_PRESSED</TT
276>). The <TT
277CLASS="STRUCTFIELD"
278><I
279>keysym</I
280></TT
281> contains information of the key press or release that this event represents (see above).</P
282></DIV
283></DIV
284><DIV
285CLASS="SECT2"
286><H2
287CLASS="SECT2"
288><A
289NAME="AEN324"
290></A
291>Reading Keyboard Events</H2
292><P
293>Reading keybaord events from the event queue is quite simple (the event queue and using it is described <A
294HREF="sdlevent.html"
295>here</A
296>). We read events using <A
297HREF="sdlpollevent.html"
298><TT
299CLASS="FUNCTION"
300>SDL_PollEvent</TT
301></A
302> in a <TT
303CLASS="LITERAL"
304>while()</TT
305> loop and check for <TT
306CLASS="LITERAL"
307>SDL_KEYUP</TT
308> and <TT
309CLASS="LITERAL"
310>SDL_KEYDOWN</TT
311> events using a <TT
312CLASS="LITERAL"
313>switch</TT
314> statement, like so:</P
315><DIV
316CLASS="EXAMPLE"
317><A
318NAME="AEN334"
319></A
320><P
321><B
322>Example 3-10. Reading Keyboard Events</B
323></P
324><PRE
325CLASS="PROGRAMLISTING"
326>  SDL_Event event;
327  .
328  .
329  /* Poll for events. SDL_PollEvent() returns 0 when there are no  */
330  /* more events on the event queue, our while loop will exit when */
331  /* that occurs.                                                  */
332  while( SDL_PollEvent( &#38;event ) ){
333    /* We are only worried about SDL_KEYDOWN and SDL_KEYUP events */
334    switch( event.type ){
335      case SDL_KEYDOWN:
336        printf( "Key press detected\n" );
337        break;
338
339      case SDL_KEYUP:
340        printf( "Key release detected\n" );
341        break;
342
343      default:
344        break;
345    }
346  }
347  .
348  .</PRE
349></DIV
350><P
351>This is a very basic example. No information about the key press or release is interpreted. We will explore the other extreme out our first full example below - reporting all available information about a keyboard event.</P
352></DIV
353><DIV
354CLASS="SECT2"
355><H2
356CLASS="SECT2"
357><A
358NAME="AEN338"
359></A
360>A More Detailed Look</H2
361><P
362>Before we can read events SDL must be initialised with <A
363HREF="sdlinit.html"
364><TT
365CLASS="FUNCTION"
366>SDL_Init</TT
367></A
368> and a video mode must be set using <A
369HREF="sdlsetvideomode.html"
370><TT
371CLASS="FUNCTION"
372>SDL_SetVideoMode</TT
373></A
374>. There are, however, two other functions we must use to obtain all the information required. We must enable unicode translation by calling <TT
375CLASS="FUNCTION"
376>SDL_EnableUNICODE(1)</TT
377> and we must convert <SPAN
378CLASS="STRUCTNAME"
379>SDLKey</SPAN
380> values into something printable, using <A
381HREF="sdlgetkeyname.html"
382><TT
383CLASS="FUNCTION"
384>SDL_GetKeyName</TT
385></A
386></P
387><DIV
388CLASS="NOTE"
389><BLOCKQUOTE
390CLASS="NOTE"
391><P
392><B
393>Note: </B
394>It is useful to note that unicode values &#60; 0x80 translate directly a characters ASCII value. THis is used in the example below</P
395></BLOCKQUOTE
396></DIV
397><DIV
398CLASS="EXAMPLE"
399><A
400NAME="AEN351"
401></A
402><P
403><B
404>Example 3-11. Interpreting Key Event Information</B
405></P
406><PRE
407CLASS="PROGRAMLISTING"
408>&#13;    #include "SDL.h"
409
410    /* Function Prototypes */
411    void PrintKeyInfo( SDL_KeyboardEvent *key );
412    void PrintModifiers( SDLMod mod );
413
414    /* main */
415    int main( int argc, char *argv[] ){
416
417        SDL_Event event;
418        int quit = 0;
419
420        /* Initialise SDL */
421        if( SDL_Init( SDL_INIT_VIDEO ) &#60; 0){
422            fprintf( stderr, "Could not initialise SDL: %s\n", SDL_GetError() );
423            exit( -1 );
424        }
425
426        /* Set a video mode */
427        if( !SDL_SetVideoMode( 320, 200, 0, 0 ) ){
428            fprintf( stderr, "Could not set video mode: %s\n", SDL_GetError() );
429            SDL_Quit();
430            exit( -1 );
431        }
432
433        /* Enable Unicode translation */
434        SDL_EnableUNICODE( 1 );
435
436        /* Loop until an SDL_QUIT event is found */
437        while( !quit ){
438
439            /* Poll for events */
440            while( SDL_PollEvent( &#38;event ) ){
441
442                switch( event.type ){
443                    /* Keyboard event */
444                    /* Pass the event data onto PrintKeyInfo() */
445                    case SDL_KEYDOWN:
446                    case SDL_KEYUP:
447                        PrintKeyInfo( &#38;event.key );
448                        break;
449
450                    /* SDL_QUIT event (window close) */
451                    case SDL_QUIT:
452                        quit = 1;
453                        break;
454
455                    default:
456                        break;
457                }
458
459            }
460
461        }
462
463        /* Clean up */
464        SDL_Quit();
465        exit( 0 );
466    }
467
468    /* Print all information about a key event */
469    void PrintKeyInfo( SDL_KeyboardEvent *key ){
470        /* Is it a release or a press? */
471        if( key-&#62;type == SDL_KEYUP )
472            printf( "Release:- " );
473        else
474            printf( "Press:- " );
475
476        /* Print the hardware scancode first */
477        printf( "Scancode: 0x%02X", key-&#62;keysym.scancode );
478        /* Print the name of the key */
479        printf( ", Name: %s", SDL_GetKeyName( key-&#62;keysym.sym ) );
480        /* We want to print the unicode info, but we need to make */
481        /* sure its a press event first (remember, release events */
482        /* don't have unicode info                                */
483        if( key-&#62;type == SDL_KEYDOWN ){
484            /* If the Unicode value is less than 0x80 then the    */
485            /* unicode value can be used to get a printable       */
486            /* representation of the key, using (char)unicode.    */
487            printf(", Unicode: " );
488            if( key-&#62;keysym.unicode &#60; 0x80 &#38;&#38; key-&#62;keysym.unicode &#62; 0 ){
489                printf( "%c (0x%04X)", (char)key-&#62;keysym.unicode,
490                        key-&#62;keysym.unicode );
491            }
492            else{
493                printf( "? (0x%04X)", key-&#62;keysym.unicode );
494            }
495        }
496        printf( "\n" );
497        /* Print modifier info */
498        PrintModifiers( key-&#62;keysym.mod );
499    }
500
501    /* Print modifier info */
502    void PrintModifiers( SDLMod mod ){
503        printf( "Modifers: " );
504
505        /* If there are none then say so and return */
506        if( mod == KMOD_NONE ){
507            printf( "None\n" );
508            return;
509        }
510
511        /* Check for the presence of each SDLMod value */
512        /* This looks messy, but there really isn't    */
513        /* a clearer way.                              */
514        if( mod &#38; KMOD_NUM ) printf( "NUMLOCK " );
515        if( mod &#38; KMOD_CAPS ) printf( "CAPSLOCK " );
516        if( mod &#38; KMOD_LCTRL ) printf( "LCTRL " );
517        if( mod &#38; KMOD_RCTRL ) printf( "RCTRL " );
518        if( mod &#38; KMOD_RSHIFT ) printf( "RSHIFT " );
519        if( mod &#38; KMOD_LSHIFT ) printf( "LSHIFT " );
520        if( mod &#38; KMOD_RALT ) printf( "RALT " );
521        if( mod &#38; KMOD_LALT ) printf( "LALT " );
522        if( mod &#38; KMOD_CTRL ) printf( "CTRL " );
523        if( mod &#38; KMOD_SHIFT ) printf( "SHIFT " );
524        if( mod &#38; KMOD_ALT ) printf( "ALT " );
525        printf( "\n" );
526    }</PRE
527></DIV
528></DIV
529><DIV
530CLASS="SECT2"
531><H2
532CLASS="SECT2"
533><A
534NAME="AEN354"
535></A
536>Game-type Input</H2
537><P
538>I have found that people using keyboard events for games and other interactive applications don't always understand one fundemental point.</P
539><A
540NAME="AEN357"
541></A
542><BLOCKQUOTE
543CLASS="BLOCKQUOTE"
544><P
545>Keyboard events <SPAN
546CLASS="emphasis"
547><I
548CLASS="EMPHASIS"
549>only</I
550></SPAN
551> take place when a keys state changes from being unpressed to pressed, and vice versa.</P
552></BLOCKQUOTE
553><P
554>Imagine you have an image of an alien that you wish to move around using the cursor keys: when you pressed the left arrow key you want him to slide over to the left, and when you press the down key you want him to slide down the screen. Examine the following code; it highlights an error that many people have made.
555<PRE
556CLASS="PROGRAMLISTING"
557>    /* Alien screen coordinates */
558    int alien_x=0, alien_y=0;
559    .
560    .
561    /* Initialise SDL and video modes and all that */
562    .
563    /* Main game loop */
564    /* Check for events */
565    while( SDL_PollEvent( &#38;event ) ){
566        switch( event.type ){
567            /* Look for a keypress */
568            case SDL_KEYDOWN:
569                /* Check the SDLKey values and move change the coords */
570                switch( event.key.keysym.sym ){
571                    case SDLK_LEFT:
572                        alien_x -= 1;
573                        break;
574                    case SDLK_RIGHT:
575                        alien_x += 1;
576                        break;
577                    case SDLK_UP:
578                        alien_y -= 1;
579                        break;
580                    case SDLK_DOWN:
581                        alien_y += 1;
582                        break;
583                    default:
584                        break;
585                }
586            }
587        }
588    }
589    .
590    .</PRE
591>
592At first glance you may think this is a perfectly reasonable piece of code for the task, but it isn't. Like I said keyboard events only occur when a key changes state, so the user would have to press and release the left cursor key 100 times to move the alien 100 pixels to the left.</P
593><P
594>To get around this problem we must not use the events to change the position of the alien, we use the events to set flags which are then used in a seperate section of code to move the alien. Something like this:</P
595><DIV
596CLASS="EXAMPLE"
597><A
598NAME="AEN363"
599></A
600><P
601><B
602>Example 3-12. Proper Game Movement</B
603></P
604><PRE
605CLASS="PROGRAMLISTING"
606>    /* Alien screen coordinates */
607    int alien_x=0, alien_y=0;
608    int alien_xvel=0, alien_yvel=0;
609    .
610    .
611    /* Initialise SDL and video modes and all that */
612    .
613    /* Main game loop */
614    /* Check for events */
615    while( SDL_PollEvent( &#38;event ) ){
616        switch( event.type ){
617            /* Look for a keypress */
618            case SDL_KEYDOWN:
619                /* Check the SDLKey values and move change the coords */
620                switch( event.key.keysym.sym ){
621                    case SDLK_LEFT:
622                        alien_xvel = -1;
623                        break;
624                    case SDLK_RIGHT:
625                        alien_xvel =  1;
626                        break;
627                    case SDLK_UP:
628                        alien_yvel = -1;
629                        break;
630                    case SDLK_DOWN:
631                        alien_yvel =  1;
632                        break;
633                    default:
634                        break;
635                }
636                break;
637            /* We must also use the SDL_KEYUP events to zero the x */
638            /* and y velocity variables. But we must also be       */
639            /* careful not to zero the velocities when we shouldn't*/
640            case SDL_KEYUP:
641                switch( event.key.keysym.sym ){
642                    case SDLK_LEFT:
643                        /* We check to make sure the alien is moving */
644                        /* to the left. If it is then we zero the    */
645                        /* velocity. If the alien is moving to the   */
646                        /* right then the right key is still press   */
647                        /* so we don't tocuh the velocity            */
648                        if( alien_xvel &#60; 0 )
649                            alien_xvel = 0;
650                        break;
651                    case SDLK_RIGHT:
652                        if( alien_xvel &#62; 0 )
653                            alien_xvel = 0;
654                        break;
655                    case SDLK_UP:
656                        if( alien_yvel &#60; 0 )
657                            alien_yvel = 0;
658                        break;
659                    case SDLK_DOWN:
660                        if( alien_yvel &#62; 0 )
661                            alien_yvel = 0;
662                        break;
663                    default:
664                        break;
665                }
666                break;
667
668            default:
669                break;
670        }
671    }
672    .
673    .
674    /* Update the alien position */
675    alien_x += alien_xvel;
676    alien_y += alien_yvel;</PRE
677></DIV
678><P
679>As can be seen, we use two extra variables, alien_xvel and alien_yvel, which represent the motion of the ship, it is these variables that we update when we detect keypresses and releases.</P
680></DIV
681></DIV
682><DIV
683CLASS="NAVFOOTER"
684><HR
685ALIGN="LEFT"
686WIDTH="100%"><TABLE
687SUMMARY="Footer navigation table"
688WIDTH="100%"
689BORDER="0"
690CELLPADDING="0"
691CELLSPACING="0"
692><TR
693><TD
694WIDTH="33%"
695ALIGN="left"
696VALIGN="top"
697><A
698HREF="guideinput.html"
699ACCESSKEY="P"
700>Prev</A
701></TD
702><TD
703WIDTH="34%"
704ALIGN="center"
705VALIGN="top"
706><A
707HREF="index.html"
708ACCESSKEY="H"
709>Home</A
710></TD
711><TD
712WIDTH="33%"
713ALIGN="right"
714VALIGN="top"
715><A
716HREF="guideexamples.html"
717ACCESSKEY="N"
718>Next</A
719></TD
720></TR
721><TR
722><TD
723WIDTH="33%"
724ALIGN="left"
725VALIGN="top"
726>Input handling</TD
727><TD
728WIDTH="34%"
729ALIGN="center"
730VALIGN="top"
731><A
732HREF="guideinput.html"
733ACCESSKEY="U"
734>Up</A
735></TD
736><TD
737WIDTH="33%"
738ALIGN="right"
739VALIGN="top"
740>Examples</TD
741></TR
742></TABLE
743></DIV
744></BODY
745></HTML
746>