You can use jwerty, which can be found here. We use jwerty in our Durandal project (as does Ayende Rahien in RavenDB's new HTML5 Raven Studio, which is also written with Durandal).
To see the rich keyboard support with jwerty in action, take a look at this video on my DropBox account of a Dropdown Datepicker that I wrote entirely with Durandal (and jwerty).
If you're interested, I can show you how to integrate jwerty into Durandal (pretty trivial).
[EDIT]
There are two strategies for using jwerty with Durandal: inline and custom Knockout binding.
INLINE
Below is a snippet directly from our CalendarNavigationEngine:
//Bind the directional keys
CalendarNavigationEngine.prototype.bindDirectionalKeys = function () {
var that = this;
var kContainerClass = this.kContainerClass;
//Bind directional keys
jwerty.key('left', function () { that.prevItem(); }, kContainerClass);
jwerty.key('up', function () { that.prevWeek(); }, kContainerClass);
jwerty.key('pgup / ctrl+left', function () { that.prevPage(); }, kContainerClass);
jwerty.key('right', function () { that.nextItem(); }, kContainerClass);
jwerty.key('down', function () { that.nextWeek(); }, kContainerClass);
jwerty.key('pgdown / ctrl+right', function () { that.nextPage(); }, kContainerClass);
jwerty.key('home', function () { that.firstItem(); }, kContainerClass);
jwerty.key('end', function () { that.lastItem(); }, kContainerClass);
jwerty.key('enter / tab', that.select.bind(that), kContainerClass);
};
We usually call bindDirectionalKeys
Durandal's compositionComplete
handler on the viewModel. In this case, the call chain is much deeper as CalendarNavigationEngine is not a viewModel.
By inline I mean to say that you are making the call directly from your viewModel (or module), as shown above. kContainerClass
is the DOM class on the element, or elements, that has focus and should receive and process keyboard events.
With this approach, you need a corresponding unbind method:
//Unbind key bindings
CalendarNavigationEngine.prototype.clearKeyBindings = function () {
$(this.kContainerClass).unbind('keydown.jwerty');
};
This would [eventually] be called from Durandal's detached
handler, and cleans up all key bindings in the context of kContainerClass
to avoid memory leaks. THIS IS NOT OPTIONAL.
CUSTOM KNOCKOUT BINDING
There are plenty of resources on StackOverflow on how to write custom Knockout bindings. But basically, the strategy involves binding the DOM element to a jwerty key binding. This is pretty trivial, although we did not take this approach (we are considering it).
There is one caveat: Knockout does not permit multiple identical bindings. So you cannot call a jwerty binding multiple times, which is what you would need to do in order to associate multiple key bindings with a single element (as in the example I gave above). However, what you can do is bind an array of key bindings to a single element, and then just have your custom Knockout binding, in its init
handler, iterate over that array, binding with jwerty for each item. Again, still trivial.