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