[ Team LiB ] Previous Section Next Section

9.9 Reading Which Noncharacter Key Was Pressed

NN 6, IE 4

9.9.1 Problem

You want to initiate a script action based on whether the user pressed one of the noncharacter keyboard keys.

9.9.2 Solution

Use the onkeydown or onkeyup event handler to read the code number associated with the noncharacter key. You can read this value from the event object's keyCode property in IE 4 or later and Netscape 6 or later.

The following function (which also invokes the getElementStyle( ) function from Recipe 11.12) moves an absolute-positioned element in five-pixel increments in the direction of the keyboard arrow key that the user presses:

function handleArrowKeys(evt) {
    evt = (evt) ? evt : ((window.event) ? event : null);
    if (evt) {
        var top = getElementStyle("moveableElem", "top", "top");
        var left = getElementStyle("moveableElem", "left", "left");
        var elem = document.getElementById("moveableElem");
        switch (evt.keyCode) {
            case 37:
                elem.style.left = (parseInt(left) - 5) + "px";
                break;    
            case 38:
                elem.style.top = (parseInt(top) - 5) + "px";
                break;    
            case 39:
                elem.style.left = (parseInt(left) + 5) + "px";
                break;    
            case 40:
                elem.style.top = (parseInt(top) + 5) + "px";
                break;    
         }
    }
}
   
document.onkeyup = handleArrowKeys;

This example uses the onkeyup event handler because the onkeydown event is broken in Netscape 7 (and neither onkeyup nor onkeydown works in Netscape 6.x). This is too bad: when you use onkeydown in IE, holding the key down until it goes into auto-repeat causes the onkeydown event to fire repeatedly, moving the positioned element in the same direction over and over (a desirable user interface behavior).

9.9.3 Discussion

Key codes are different from character codes. Each physical key on the keyboard has a code associated with it. For example, while the "2" key in the top row of character keys and the "2" key on the numeric keypad generate the same character codes, each key creates a distinct key code during onkeydown and onkeyup events. Key codes for regular alphanumeric keys are the same regardless of whether the Shift key is down at the time. Appendix B lists the key codes for a typical English-language PC keyboard.

Designing an application around the noncharacter keys is tricky because each browser and operating system has its own default behavior for things like function and navigation keys. To prevent scripts from hijacking the application entirely, browsers do not let you block events that are native to the application or operating system. Thus, in the function shown in the Solution, where the four arrow navigation keys are used to move an element, if the page is scrollable at all, the default scrolling action also occurs in addition to the repositioning of the element. No amount of returning false or canceling event bubbling prevents the normal action from taking place. (Although in this case, if you assign focus to an empty text input field, the default of moving the cursor has no apparent action, and the page doesn't scroll.)

If you wish to program a function key to initiate some action, you should plan to do so only on one browser platform on one operating system whose key behaviors you can predict. Even in just the Windows environment, you need to make sure that a function key you wish to program truly has no default action�something that isn't always apparent just by trolling through the browser's menus. Some function key assignments are implemented to perform actions not listed in any menu. Test, test, test!

These same kinds of cautions apply to attempts at scripting keyboard combinations to act as scripted shortcuts. You cannot override browser-defined keyboard shortcuts and finding unused two-key combinations across browsers will be a challenge. It is easier to find accelerator combinations utilizing two or more modifier keys. For example, the following onkeyup event handler function invokes the runSpecial( ) function when the user holds down Ctrl-Alt and then presses and releases the "P" key in IE 4 or later and Netscape 7 or later:

function handleAccelerator(evt) {
    evt = (evt) ? evt : ((window.event) ? event : null);
    if (evt) {
        if (evt.keyCode =  = 80 && evt.ctrlKey && evt.altKey) {
            runSpecial( );
        }
    }
}
document.onkeyup = handleAccelerator;

When coding accelerator key behavior, it is best to bind the keyboard event to the document node because that node has the greatest scope. Keyboard events that occur inside nested nodes (such as text input fields or text areas) will bubble up to the document node unless cancelled along the way. If such an event occurs inside an editable text field, the target of the event is the text field element. Thus, you could create a context-sensitive help feature with Ctrl-Alt-F2 providing details about the field while the user is editing it:

function showHelp(elem) {
    var elemID = elem.id;
    switch (elemID) {
        case "name":
            alert("Enter your full name.");
            break;
        case "email":
            alert("We will be contacting you with your access code. \n" +
                   "Make sure the address is accurate and up to date.");
            break;
        ...
    }
}
   
function handleAccelerator(evt) {
    evt = (evt) ? evt : ((window.event) ? event : null);
    var elem = (evt.target) ? evt.target : 
        ((evt.srcElement) ? evt.srcElement : null);
    if (evt) {
        // for Ctrl+Alt+F2
        if (evt.keyCode =  = 113 && evt.ctrlKey && evt.altKey) {
            showHelp(elem);
        }
    }
}
document.onkeyup = handleAccelerator;

You can't use F1 in this case, because IE for Windows triggers the application help system with any keyboard combination involving the F1 function key.

9.9.4 See Also

Recipe 9.1 for equalizing disparate event model objects; Recipe 9.6 for equalizing event target references; Recipe 9.8 for reading character key values; Recipe 9.10 for reading modifier key status during keyboard-event processing.

    [ Team LiB ] Previous Section Next Section