Skip to content

Commit

Permalink
Merge pull request jeresig#37 from rpocklin/master
Browse files Browse the repository at this point in the history
Reviewed 'meta' key functionality for Mac and added 'hyper' keyboard shortcut and other missing keys
  • Loading branch information
rpocklin committed Mar 25, 2014
2 parents d078652 + 3b37b7c commit 4dbba5c
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 57 deletions.
43 changes: 31 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,13 @@ Syntax when wanting to use jQuery's `on()`/`off` methods:
this.value = this.value.replace('$', 'EUR');
});

## Types

Supported types are `'keydown'`, `'keyup'` and `'keypress'`

## Example

[Example](http://htmlpreview.github.com/?https://github.com/jeresig/jquery.hotkeys/master/test-static-05.html)

## Notes

Modifiers are not case sensitive (Ctrl == ctrl == cTRL)

If you want to use more than one modifiers (e.g. alt+ctrl+z) you should define them by an alphabetical order e.g. alt+ctrl+shift
## Event Types

Hotkeys aren't tracked if you're inside of an input element (unless you explicitly bind the hotkey directly to the input). This helps to avoid conflict with normal user typing.

You can use namespacing by adding a suffix to the event type (e.g. 'keyup.toggle')
Supported types are `'keydown'`, `'keyup'` and `'keypress'`

## jQuery Compatibility

Expand All @@ -59,6 +49,35 @@ It is known to be working with all the major browsers on all available platforms
* Safari-3+
* Chrome-0.2+

## Notes

Modifiers are not case sensitive (`Ctrl` == `ctrl` == `cTRL`)

If you want to use more than one modifier (e.g. `alt+ctrl+z`) you should define them by an alphabetical order e.g. alt+ctrl+shift

Hotkeys aren't tracked if you're inside of an input element (unless you explicitly bind the hotkey directly to the input). This helps to avoid conflict with normal user typing.

You can use namespacing by adding a suffix to the event type (e.g. `keyup.toggle`)


### Meta and Hyper Keys
Meta and hyper keys don't register on `keyup` in any browser tested.

#### Chrome 33.0.1750.117
Meta key registers on `keydown` event.
Hyper key registers on `keydown` event.

#### Firefox 27.0.1 and Safari 7.0.1
Meta key registers on `keydown` and `keypress` events.
Hyper key registers on `keydown` and `keypress` events.

#### Opera 19.0
Meta key doesn't register at all :(
Hyper key registers on `keydown` and `keypress` events.

#### TL;DR
Bind to `keydown` event for meta and hyper keys, but meta key does not work in Opera ;)

### Addendum

Firefox is the most liberal one in the manner of letting you capture all short-cuts even those that are built-in in the browser such as `Ctrl-t` for new tab, or `Ctrl-a` for selecting all text. You can always bubble them up to the browser by returning `true` in your handler.
Expand Down
44 changes: 18 additions & 26 deletions jquery.hotkeys.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@
*/

(function(jQuery){

jQuery.hotkeys = {
version: "0.8",

specialKeys: {
8: "backspace", 9: "tab", 10: "return", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", 59: ";", 61: "=",
96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 186: ";", 191: "/",
220: "\\", 222: "'", 224: "meta"
104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 173: "-", 186: ";", 187: "=",
188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'"
},

shiftNums: {
"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
".": ">", "/": "?", "\\": "|"
}
};
Expand All @@ -50,8 +50,9 @@

var origHandler = handleObj.handler,
keys = handleObj.data.keys.toLowerCase().split(" "),
textAcceptingInputTypes = ["text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime", "datetime-local", "search", "color", "tel"];

textAcceptingInputTypes = ["text", "password", "number", "email", "url", "range", "date", "month", "week",
"time", "datetime", "datetime-local", "search", "color", "tel"];

handleObj.handler = function( event ) {
// Don't fire in text-accepting inputs that we didn't directly bind to
if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
Expand All @@ -63,23 +64,14 @@
character = String.fromCharCode( event.which ).toLowerCase(),
modif = "", possible = {};

// check combinations (alt|ctrl|shift+anything)
if ( event.altKey && special !== "alt" ) {
modif += "alt+";
}
jQuery.each([ "alt", "ctrl", "meta", "shift" ], function(index, specialKey) {
if (event[specialKey + 'Key'] && special !== specialKey) {
modif += specialKey + '+';
}
});

if ( event.ctrlKey && special !== "ctrl" ) {
modif += "ctrl+";
}

// TODO: Need to make sure this works consistently across platforms
if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
modif += "meta+";
}

if ( event.shiftKey && special !== "shift" ) {
modif += "shift+";
}
modif = modif.replace('alt+ctrl+meta+shift', 'hyper');

if ( special ) {
possible[ modif + special ] = true;
Expand Down
59 changes: 41 additions & 18 deletions test-static-06.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,54 @@ <h1>KeyDown.</h1>
shiftKey: <input id="kd_shiftKey"><br/>
ctrlKey: <input id="kd_ctrlKey"><br/>
altKey: <input id="kd_altKey"><br/>
metaKey: <input id="kd_metaKey"><br/>
<h1>KeyPress.</h1>
currentTarget: <input id="kp_currentTarget"><br/>
which: <input id="kp_which"></br>
shiftKey: <input id="kp_shiftKey"><br/>
ctrlKey: <input id="kp_ctrlKey"><br/>
altKey: <input id="kp_altKey"><br/>
metaKey: <input id="kp_metaKey"><br/>
<h1>KeyUp.</h1>
currentTarget: <input id="ku_currentTarget"><br/>
which: <input id="ku_which"></br>
shiftKey: <input id="ku_shiftKey"><br/>
ctrlKey: <input id="ku_ctrlKey"><br/>
altKey: <input id="ku_altKey"><br/>
metaKey: <input id="ku_metaKey"><br/>
<script>

$(document).bind('keydown', KdDescribeEvent);
$(document).bind('keypress', KpDescribeEvent);

function KdDescribeEvent(event){
$('#kd_currentTarget').val(event.currentTarget);
$('#kd_which').val(event.which);
$('#kd_shiftKey').val(event.shiftKey);
$('#kd_ctrlKey').val(event.ctrlKey);
$('#kd_altKey').val(event.altKey);
}
function KpDescribeEvent(event){
$('#kp_currentTarget').val(event.currentTarget);
$('#kp_which').val(event.which);
$('#kp_shiftKey').val(event.shiftKey);
$('#kp_ctrlKey').val(event.ctrlKey);
$('#kp_altKey').val(event.altKey);
}
$(function() {
function KdDescribeEvent(event){
$('#kd_currentTarget').val(event.currentTarget);
$('#kd_which').val(event.which);
$('#kd_shiftKey').val(event.shiftKey);
$('#kd_ctrlKey').val(event.ctrlKey);
$('#kd_altKey').val(event.altKey);
$('#kd_metaKey').val(event.metaKey);
}
function KpDescribeEvent(event){
$('#kp_currentTarget').val(event.currentTarget);
$('#kp_which').val(event.which);
$('#kp_shiftKey').val(event.shiftKey);
$('#kp_ctrlKey').val(event.ctrlKey);
$('#kp_altKey').val(event.altKey);
$('#kp_metaKey').val(event.metaKey);
}
function KuDescribeEvent(event){
$('#ku_currentTarget').val(event.currentTarget);
$('#ku_which').val(event.which);
$('#ku_shiftKey').val(event.shiftKey);
$('#ku_ctrlKey').val(event.ctrlKey);
$('#ku_altKey').val(event.altKey);
$('#ku_metaKey').val(event.metaKey);
}

setTimeout(function() {
$(document).bind('keydown', KdDescribeEvent);
$(document).bind('keypress', KpDescribeEvent);
$(document).bind('keyup', KuDescribeEvent);
}, 500);
});

</script>
</body>
Expand Down
20 changes: 19 additions & 1 deletion test/spec/bindingSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe("binding functions to key combinations", function() {

return event;
};
});
});

afterEach(function(){
this.fixture.remove();
Expand Down Expand Up @@ -79,6 +79,24 @@ describe("binding functions to key combinations", function() {
sinon.assert.calledOnce(spy);
});

it("should bind the 'meta+a' keys and call the callback handler function", function() {

$(document).bind('keyup', 'meta+a', this.callbackFn);
var event = this.createKeyUpEvent(65);
event.metaKey = true;
$(document).trigger(event);
sinon.assert.calledOnce(this.callbackFn);
});

it("should bind the 'hyper+a' keys and call the callback handler function", function() {

$(document).bind('keyup', 'hyper+a', this.callbackFn);
var event = this.createKeyUpEvent(65);
event.shiftKey = true, event.metaKey = true, event.altKey = true, event.ctrlKey = true;
$(document).trigger(event);
sinon.assert.calledOnce(this.callbackFn);
});

it("should not trigger event handler callbacks bound to any standard input types if not bound directly", function() {

var i = 0;
Expand Down

0 comments on commit 4dbba5c

Please sign in to comment.