flash interactivity_keyboard_management
Keyboard management
Thanks to the keyboard we can add another dimension to our applications, this functionality is nevertheless not used enough in today’s sites, we’re going to capture certain keyboard strokes which add new functionality in our previously created drawing application.
It would be useful to create a keyboard shortcut to erase the current drawing. By default the Stage object manage keyboard events.
Two events are linked to the keyboard detection:
- KeyboardEvent.KEY_DOWN: broadcast when a key is pressed
- KeyboardEvent.KEY_UP: broadcast when a key is released
We’re going to listen out for even that is broadcast when a key is released.
The KeyboardEvent.KEY_DOWN from the Stage object, will cause the keyboardListen function to be executed:
// register the stage object for the KEY_DOWN events stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyboardListen ); function keyboardListen ( pEvt:KeyboardEvent ):void { // output : [KeyboardEvent type="keyDown" bubbles=true cancelable=false eventPhase=2 charCode=114 keyCode=82 keyLocation=0 ctrlKey=false altKey=false shiftKey=false] trace( pEvt ); }
An event type object called KeyboardEvent is triggered, this class possesses many properties, here are the details:
- KeyboardEvent.altKey: indicates if the ALT key was pressed; this isn’t taken into consideration for the moment.
- KeyboardEvent.charCode: contains the Unicode character code of the key that was pressed
- KeyboardEvent.ctrlKey: indicates if the CTRL key was pressed
- KeyboardEvent.keyCode: the code corresponding to the key that was pressed or released.
- KeyboardEvent.keyLocation: indicates the location of the key on the keyboard
- KeyboardEvent.shiftKey: indicates if the SHIFT key was pressed.
Working out the key that was pressed
The charCode property of the broadcast event object allows us to determine which key was pressed.
Thanks to the String.fromCharCode method we calculate the Unicode code and get the corresponding character:
// register for the KEY_DOWN event of the stage object stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyboardListener ); function keyboardListener ( pEvt:KeyboardEvent ):void { // output : d,f,g, etc... trace( String.fromCharCode( pEvt.charCode ) ); }
To test the pressed key, we use the static properties of the Keyboard class. The most-used key codes are stored in the Keyboard classes static properties.
To find out of the spacebar was pressed, we would write:
// register for the KEY_DOWN event of the stage object stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyboardListener ); function keyboardListener ( pEvt:KeyboardEvent ):void { if ( pEvt.keyCode == Keyboard.SPACE ) { trace("SPACEBAR pressed"); } }
We’re going to delete the drawing whenever the SPACEBAR is pressed, in order to start a new drawing:
// register for the KEY_DOWN event of the stage object stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyboardListener ); function keyboardListener ( pEvt:KeyboardEvent ):void { if ( pEvt.keyCode == Keyboard.SPACE ) { // we delete all previous lines myDrawing.graphics.clear(); // note – we have to redefine a style myDrawing.graphics.lineStyle ( 1, 0x990000, 1 ); } }
We could change the colour of the lines for each new drawing:
// register for the KEY_DOWN event of the stage object stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyboardListener ); function keyboardListener ( pEvt:KeyboardEvent ):void { if ( pEvt.keyCode == Keyboard.SPACE ) { // we delete all previous lines myDrawing.graphics.clear(); // note – we have to redefine a style myDrawing.graphics.lineStyle ( 1, Math.random()*0xFFFFFF, 1 ); } }
We’ll come back to the advanced manipulation of colours in chapter 12, called Bitmap programming
Managing simultaneous key presses
In ActionScript 1 and 2 the management of simultaneous key presses from the keyboard wasn’t easy. In ActionScript 3 thanks to the properties of the MouseEvent class we can easily detect multiple key presses. This is made possible thanks to the altKey, ctrlKey and shiftKey properties.
We’re going to add a notion of history in our drawing application. Whenever the user clicks on CTRL+Z we’ll take one step backwards, to move forwards again the user can click on CTRL+Y.
To create this functionality we need to separate each stroke performed by the user. To do this, we’re going to add each stroke to a different Shape object and add these to a main container object. In order to contain these Shape objects, our main container must be a DisplayObjectContainer, we therefore modify the first few lines of our application to add a Sprite container:
// creation of container for strokes var myDrawing:Sprite = new Sprite(); // add to the display list addChild ( myDrawing );
We must store two arrays, one for deleted strokes the other for displayed strokes:
// arrays for deleted and displayed strokes var displayedStrokes:Array = new Array(); var oldStrokes:Array = new Array();
Each time the mouse is clicked we create a Shape object specific to the stroke, which is stored in the displayedStrokes array. We’ll modify the body of the mouseClick function:
function mouseClick ( pEvt:MouseEvent ):void { // mouse position var positionX:Number = pEvt.stageX; var positionY:Number = pEvt.stageY; // a new shape object is created for each stroke var myNewStroke:Shape = new Shape(); // add the strokes container to the main container myDrawing.addChild ( myNewStroke ); // then we put this on the array for displayed strokes tableauTraces.push ( myNewStroke ); // we define a style for the stroke myNewStroke.graphics.lineStyle ( 1, 0x990000, 1 ); // the cursor is moved to this position // to start drawing again from this position myNewStroke.graphics.moveTo ( positionX, positionY ); // if a new trace intervenes when we are // going backwards we restart from this state if ( oldStrokes.length ) oldStrokes = new Array(); // when the mouse is moving we listen to the event pEvt.currentTarget.addEventListener ( MouseEvent.MOUSE_MOVE, mouseMove ); }
When the mouse is moving we must draw within our Shape object, thanks to our displayedStrokes array we can get the last Shape object and start draw on it:
function mouseMove ( pEvt:MouseEvent ):void { var positionX:Number = pEvt.stageX; var positionY:Number = pEvt.stageY; // get the last shape object created // ready to receive the drawing var myNewStroke:Shape = displayedStrokes[displayedStrokes.length-1]; // the cursor is move to this position // to start drawing again from this position myNewStroke.graphics.lineTo ( positionX, positionY ); // force a refresh pEvt.updateAfterEvent(); }
The last function we need to modify is the keyboardListen function, it’s in this that we’re going to test the keyboard combinations pressed and decide if we need to remove or re-add strokes:
function keyboardListen ( pEvt:KeyboardEvent ):void { // if the spacebar was pressed if ( pEvt.keyCode == Keyboard.SPACE ) { // number of shape objects containing strokes var lng:int = displayedStrokes.length; // remove the strokes from the display list while ( lng-- ) myDrawing.removeChild ( displayedStrokes[lng] ); // the historical arrays are re-initialised // and the references deleted displayedStrokes = new Array(); oldStrokes = new Array(); } // codes of Z and Y keys var ZkeyCode:int = 90; var YkeyCode:int = 89; if ( pEvt.ctrlKey ) { // if undo (CTRL+Z) if( pEvt.keyCode == ZkeyCode && displayedStrokes.length ) { // remove the last stroke var toDelete:Shape = displayedStrokes.pop() // we store each stroke remove in an array oldStrokes.push (toDelete ); // remove the stroke from the display list myDrawing.removeChild( toDelete ); // if redo (CTRL+Y) } else if ( pEvt.keyCode == YkeyCode && oldStrokes.length ) { // get the last stroke deleted var toPrint:Shape = oldStrokes.pop(); // move it to the displayed strokes list displayedStrokes.push ( toPrint ); // then add it to the drawing myDrawing.addChild ( toPrint ); } } }
Here’s the complete code of our drawing application, with its history manager:
// create container for storing strokes var myDrawing:Sprite = new Sprite(); // add to the display list addChild ( myDrawing ); // register for the MouseEvent.MOUSE_DOWN event of the stage stage.addEventListener ( MouseEvent.MOUSE_DOWN, clicSouris ); // register for the MouseEvent.MOUSE_UP event of the stage stage.addEventListener ( MouseEvent.MOUSE_UP, mouseRelease ); // arrays of displayed and remove strokes var displayedStrokes:Array = new Array(); var oldStrokes:Array = new Array(); function mouseClick ( pEvt:MouseEvent ):void { // mouse position var positionX:Number = pEvt.stageX; var positionY:Number = pEvt.stageY; // create a new Shape object for each stroke var myNewStroke:Shape = new Shape(); // add the stroke’s container to the main container myDrawing.addChild ( myNewStroke ); // add it to the display list displayedStrokes.push ( myNewStroke ); // specify a style for the stroke myNewStroke.graphics.lineStyle ( 1, 0x990000, 1 ); // the cursor is move so we start drawing again from this position myNewStroke.graphics.moveTo ( positionX, positionY ); // if a new trace intervenes when we are // going backwards we restart from this state if ( oldStrokes.length ) oldStrokes = new Array; // as soon as the mouse is pressed, starting listening pEvt.currentTarget.addEventListener ( MouseEvent.MOUSE_MOVE, mouseMove ); } function mouseMove ( pEvt:MouseEvent ):void { var positionX:Number = pEvt.stageX; var positionY:Number = pEvt.stageY; // get the last added shape object // ready to start being drawn to var myNewStroke:Shape = displayedStrokes[displayedStrokes.length-1]; // the cursor is move so we start drawing again from this position myNewStroke.graphics.lineTo ( positionX, positionY ); // force a refresh pEvt.updateAfterEvent(); } function mouseRelease ( pEvt:MouseEvent ):void { // unsubscribe from the MOUSE_MOVE event pEvt.currentTarget.removeEventListener ( MouseEvent.MOUSE_MOVE, mouseMove ); } // register the stage for the KEY_DOWN event stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyboardListen ); function keyboardListen ( pEvt:KeyboardEvent ):void { // if the spacebar was pressed if ( pEvt.keyCode == Keyboard.SPACE ) { // number of shape objects containing strokes var lng:int = displayedStrokes.length; // remove the strokes from the display list while ( lng-- ) myDrawing.removeChild ( displayedStrokes[lng] ); // the history arrays and reinitialised // the references are deleted displayedStrokes = new Array(); oldStrokes = new Array(); } // code des keys Z et Y var ZkeyCode:int = 90; var YkeyCode:int = 89; if ( pEvt.ctrlKey ) { // if undo (CTRL+Z) if( pEvt.keyCode == ZkeyCode && displayedStrokes.length ) { // delete last stroke var toDelete:Shape = displayedStrokes.pop() // store each stroke deleted in an array oldStrokes.push ( toDelete ); // remove from the display list myDrawing.removeChild( toDelete ); // if redo (CTRL+Y) } else if ( pEvt.keyCode == YkeyCode && oldStrokes.length ) { // get the last stroke deleted var toDisplay:Shape = oldStrokes.pop(); // move it to the displayed strokes displayedStrokes.push ( toDisplay ); // and display it myDrawing.addChild ( toDisplay ); } } }
We will see in chapter 10 called Bitmap programming how to capture vectorial data before compressing and exporting them to an image of type PNG or JPEG.
We could envisage an application allowing users to draw then save their drawing to their computer in their preferred format. ActionScript keeps surprising us!
Worth remembering
- The MouseEvent class allows access to the shiftKey and ctrlKey properties and manages simultaneous key presses
Simulating the Key.isDown method
ActionScript 3 does not include an equivalent to the isDown method of the Key class present in ActionScript 1 and 2.
For games development it can be important to simulate this old feature. Let’s look into this now.
While developing this functionality, we’ll use a clip symbol which we can place on the screen with the help of the keyboard.
Thanks to a ‘memory object’, we can reproduce the same feature as the isDown method with the help of the following code:
// listen to keyboard events stage.addEventListener ( KeyboardEvent.KEY_DOWN, keyPressed ); stage.addEventListener ( KeyboardEvent.KEY_UP, keyReleased ); // state object for remembering the state of the keys var keys:Object = new Object(); function keyPressed ( pEvt:KeyboardEvent ):void { // mark the key as being pressed keys [ pEvt.keyCode ] = true; } function keyReleased ( pEvt:KeyboardEvent ):void { // make the key as being released keys [ pEvt.keyCode ] = false; } person_mc.addEventListener ( Event.ENTER_FRAME, move ); var state:Number = person_mc.scaleX; var speed:Number = 15; function move ( pEvt:Event ):void { // if the Keyboard.RIGHT was pressed if ( keys [ Keyboard.RIGHT ] ) { pEvt.target.x += speed; pEvt.target.scaleX = state; // if the Keyboard.LEFT was pressed } else if ( keys [ Keyboard.LEFT ] ) { pEvt.target.x -= speed; pEvt.target.scaleX = -state; } }
In testing the previous code, the symbol is manipulated by the keyboard. We’ve managed to simulate the Key.isDown method which doesn’t exists in ActionScript 3.
Worth remembering
- The keyCode property of the KeyboardEvent returns the code the key.
- There is no equivalent of the isDown method of the Key class in ActionScript 3. It is however easy to simulate an equivalent feature.
Mediabox Training Centre © 2000 - 2008 All rights reserved.
Adobe Authorized Training Centre. State convention under number 25 14 02167 14.
Mediabox : SARL au capital de 62.000€ - Activity number: 25 14 02167 14 - SIRET : 493 716 468 00027
MEDIABOX, 102 Avenue des Champs Elysées, 75008 PARIS - Tel. +33(0)2.31.91.96.89 - Fax. +33(0)2.72.68.56.42



