comparison docs/html/guideinputkeyboard.html @ 0:74212992fb08

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