Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
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%">
681
WIDTH="100%"
682
BORDER="0"
683
CELLPADDING="0"
684
CELLSPACING="0"
685
>
686
>
687
WIDTH="33%"
688
ALIGN="left"
689
VALIGN="top"
690
>
691
HREF="guideinput.html"
692
>Prev
693
>
694
>
695
WIDTH="34%"
696
ALIGN="center"
697
VALIGN="top"
698
>
699
HREF="index.html"
700
>Home
701
>
702
>
703
WIDTH="33%"
704
ALIGN="right"
705
VALIGN="top"
706
>
707
HREF="guideexamples.html"
708
>Next
709
>
710
>
711
>
712
>
713
WIDTH="33%"
714
ALIGN="left"
715
VALIGN="top"
716
>Input handling
717
>
718
WIDTH="34%"
719
ALIGN="center"
720
VALIGN="top"
721
>
722
HREF="guideinput.html"
723
>Up
724
>
725
>
726
WIDTH="33%"
727
ALIGN="right"
728
VALIGN="top"
729
>Examples
730
>
731
>
732
>
733
>
734
>
735
>