Index: admin_menu.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.css,v
retrieving revision 1.25.2.4
diff -u -p -r1.25.2.4 admin_menu.css
--- admin_menu.css	2 Nov 2008 21:36:22 -0000	1.25.2.4
+++ admin_menu.css	9 Nov 2008 04:38:32 -0000
@@ -97,6 +97,9 @@ body.admin-menu { margin-top: 20px !impo
 /* #210615: Mozilla on Mac fix */
 html.js fieldset.collapsible div.fieldset-wrapper { overflow: visible; }
 
+/* Keyboard navigation */
+div#admin-menu li.focused { background-color: #75757a; }
+
 @media print {
   #admin-menu { display: none; }
   body.admin-menu { margin-top: 0 !important; }
Index: admin_menu.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.js,v
retrieving revision 1.7.2.6
diff -u -p -r1.7.2.6 admin_menu.js
--- admin_menu.js	2 Nov 2008 21:36:22 -0000	1.7.2.6
+++ admin_menu.js	9 Nov 2008 04:48:27 -0000
@@ -47,4 +47,143 @@ $(document).ready(function() {
       uls.css({left: '-999em', display: 'none'});
     }, 400);
   });
+
+  // Keyboard navigation.
+  (function() {
+    var tree = $.map($("#admin-menu").find("> ul > li.expandable"), function (element, index) {
+      var _this = $(element);
+      var tree = { li: _this, a: _this.find("> a") };
+      var children;
+      if ((children = _this.find("> ul > li")).length) {
+        tree.children = $.map(children, arguments.callee);
+      }
+      return tree;
+    });
+
+    // Create object parents
+    (function (array, parent, parentIndex, level) {
+      var level = level || 1;
+      for (var i = 0; i < array.length; i++) {
+        var object = array[i];
+        object.level = level;
+
+        if (object.children) {
+          arguments.callee(object.children, object, i, level + 1);
+        }
+        if (parent) {
+          object.parent = parent;
+        }
+        object.parentIndex = parentIndex || i;
+        object.index = i;
+      };
+    })(tree);
+
+    var active = false;
+    var current;
+
+    $(document).bind('keydown', function (event) {
+      var key = event.keyCode;
+      // Left, top, right, down or escape pressed.
+      if (!(key == 37 || key == 38 || key == 39 || key == 40 || key == 27)) {
+        return true;
+      }
+
+      // Un-hover the menu if escape is pressed.
+      if (key == 27) {
+        active = !active;
+        if (!active) {
+          $("#admin-menu").find('li.expandable').trigger('mouseleave');
+          current.li.removeClass('focused');
+          current.a.blur();
+          current = undefined;
+          return false;
+        }
+      }
+      // If the menu is not active, break here.
+      if (!active) {
+        return false;
+      }
+
+      // Reset first element on initialization.
+      if (!current) {
+        // @todo Find 'Content Management', since modules can alter the menu via
+        // hook_admin_menu().
+        current = tree[2];
+      }
+
+      var next;
+      switch (key) {
+        case 37: // Left
+          // Handle first level.
+          if (current.level == 1 && tree[current.parentIndex - 1]) {
+            next = tree[current.parentIndex - 1];
+          }
+          // Handle third and deeper levels.
+          else if (current.level > 2) {
+            next = current.parent;
+          }
+          // Handle second level.
+          else {
+            next = tree[current.parent.parentIndex - 1];
+          }
+          break;
+
+        case 38: // Up
+          if (current.level == 1) {
+            next = current.children[current.children.length - 1];
+          }
+          // Handle first level.
+          else if (!(current.level == 2 && current.index == 0)) {
+            next = current.parent.children[current.index - 1];
+          }
+          else if (current.level == 2 && current.index == 0) {
+            next = current.parent;
+          }
+          break;
+
+        case 39: // Right
+          // Handle first level.
+          if (current.level == 1 && tree[current.parentIndex + 1]) {
+            next = tree[current.parentIndex + 1];
+          }
+          else if (current.children) {
+            next = current.children[0];
+          }
+          else if (current.level == 2) {
+            next = tree[current.parent.parentIndex + 1];
+          }
+          break;
+
+        case 40: // Down
+          // Handle first level.
+          if (current.level == 1 && tree[current.parentIndex].children) {
+            next = tree[current.parentIndex].children[0];
+          }
+          else {
+            next = current.parent.children[current.index + 1];
+          }
+          break;
+      }
+      // Fallback to current if next is not set.
+      if (!next) {
+        next = current;
+      }
+      current.li.removeClass('focused');
+      if ((next.level < current.level) || (!next.children && next.level == current.level)) {
+        current.li.trigger('mouseleave');
+      }
+      next.li.addClass('focused');
+      next.a.focus();
+      next.li.trigger('mouseenter');
+
+      current = next;
+
+      event.preventDefault();
+      event.cancelBubble = true;
+      if (event.stopPropagation) {
+        event.stopPropagation();
+      }
+      return false;
+    });
+  })();
 });
