/*global
    process_goto_hotkey:    false,
    process_compose_hotkey: false,
    process_key_in_input:   false */

// We don't generally treat these as global.
// Tell JSLint they are, to break the mutual recursion.


var pressed_keys = {};

function num_pressed_keys() {
    var size = 0, key;
    for (key in pressed_keys) {
        if (pressed_keys.hasOwnProperty(key))
            size++;
    }
    return size;
}

var directional_hotkeys = {
    40: get_next_visible,  // down arrow
    74: get_next_visible,  // 'j'
    38: get_prev_visible,  // up arrow
    75: get_prev_visible,  // 'k'
    36: get_first_visible, // Home
    35: get_last_visible   // End
};

function simulate_keydown(keycode) {
    $(document).trigger($.Event('keydown', {keyCode: keycode}));
}

function process_hotkey(code) {
    var next_zephyr;
    if (directional_hotkeys.hasOwnProperty(code)) {
        next_zephyr = directional_hotkeys[code](selected_zephyr);
        if (next_zephyr.length !== 0) {
            select_zephyr(next_zephyr, true);
        }
        return process_hotkey;
    }

    if (num_pressed_keys() > 1) {
        // If you are already holding down another key, none of these
        // actions apply.
        return false;
    }

    switch (code) {
    case 33: // Page Up
        keep_pointer_in_view();
        return false; // We want the browser to actually page up and down
    case 34: // Page Down
        keep_pointer_in_view();
        return false;
    case 27: // Esc: hide compose pane
        hide_compose();
        return process_hotkey;
    case 67: // 'c': compose
        compose_button();
        return process_compose_hotkey;
    case 82: // 'r': respond to zephyr
        respond_to_zephyr();
        return process_key_in_input;

    case 71: // 'g': start of "go to" command
        return process_goto_hotkey;
    }

    return false;
}

var goto_hotkeys = {
    67: narrow_by_recipient,  // 'c'
    73: narrow_instance,      // 'i'
    80: narrow_all_personals, // 'p'
    65: show_all_messages,    // 'a'
    27: hide_compose          // Esc
};

function process_goto_hotkey(code) {
    if (goto_hotkeys.hasOwnProperty(code))
        goto_hotkeys[code]();

    /* Always return to the initial hotkey mode, even
       with an unrecognized "go to" command. */
    return process_hotkey;
}

function process_key_in_input(code) {
    if (code === 27) {
        // User hit Escape key
        hide_compose();
        return process_hotkey;
    }
    return false;
}

function process_compose_hotkey(code) {
    if (code === 9) { // Tab: toggle between class and huddle compose tabs.
        toggle_compose();
        return process_compose_hotkey;
    } else {
        set_keydown_in_input(true);
        simulate_keydown(code);
    }
}

$(document).keydown(function (e) {
    pressed_keys[e.which] = true;
});

$(document).keyup(function (e) {
    pressed_keys = {};
});

/* The current handler function for keydown events.
   It should return a new handler, or 'false' to
   decline to handle the event. */
var keydown_handler = process_hotkey;

function set_keydown_in_input(flag) {
    // No argument should behave like 'true'.
    if (flag === undefined)
        flag = true;

    if (flag) {
        keydown_handler = process_key_in_input;
    } else {
        keydown_handler = process_hotkey;
    }
}

$(document).keydown(function (event) {
    var result = keydown_handler(event.keyCode);
    if (typeof result === 'function') {
        keydown_handler = result;
        event.preventDefault();
    }
});

@@ -491,10 +491,11 @@
     
-74
+106
 : ge
@@ -565,10 +565,11 @@
     
+10
 7
-5
 : ge
@@ -1567,18 +1567,18 @@
    case 
-67
+99
 : // 'c'
@@ -1665,10 +1665,11 @@
 ase 
-82
+114
 : //
@@ -1772,10 +1772,11 @@
 ase 
-7
 1
+03
 : //
@@ -1899,10 +1899,10 @@
     
-67
+99
 : na
@@ -1936,10 +1936,11 @@
     
-73
+105
 : na
@@ -1974,10 +1974,11 @@
     
-80
+112
 : na
@@ -2012,10 +2012,10 @@
     
-65
+97
 : sh
@@ -3346,93 +3346,950 @@
 %0A%7D%0A%0A
-$(document).keydown(function (event) %7B%0A    var result = keydown_handler(event.keyCode
+/* We register both a keydown and a keypress function because%0A   we want to intercept pgup/pgdn, escape, etc, and process them%0A   as they happen on the keyboard. However, if we processed%0A   letters/numbers in keydown, we wouldn't know what the case of%0A   the letters were.%0A%0A   We want case-sensitive hotkeys (such as in the case of r vs R)%0A   so we bail in .keydown if the event is a letter or number and%0A   instead just let keypress go for it. */%0A%0A$(document).keydown(function (event) %7B%0A    if (48 %3E event.which %7C%7C90 %3C event.which) %7B // outside the alphanumeric range%0A        var result = keydown_handler(event.which);%0A        if (typeof result === 'function') %7B%0A            keydown_handler = result;%0A            event.preventDefault();%0A        %7D%0A    %7D%0A%7D);%0A%0A$(document).keypress(function (event) %7B%0A    // What exactly triggers .keypress may vary by browser.%0A    // Welcome to compatability hell.%0A%0A    var result = keydown_handler(event.which
 );%0A 

Make hotkeys case sensitive.