Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f6598ec

Browse files
committed
Merge pull request medialize#86 from medialize/issue/59-modifier-keys
closes medialize#59
2 parents 5d72939 + 0d026c2 commit f6598ec

File tree

9 files changed

+629
-50
lines changed

9 files changed

+629
-50
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@ The following lists show the changes to the library grouped by domain.
2323

2424
* changing [`ally.is.focusRelevant`][ally/is/focus-relevant] and [`ally.is.focusable`][ally/is/focusable] to regard `<keygen>` and `<embed>` focus-relevant but *not* focusable - [issue #82](https://github.com/medialize/ally.js/issues/82)
2525
* changing [`ally.is.validArea`][ally/is/valid-area] to properly handle `<area href="…">` vs. `<area>` - [issue #72](https://github.com/medialize/ally.js/issues/72)
26-
* changing [`ally.is.focusRelevant`][ally/is/focus-relevant] to properly handle `<object type="application/x-shockwave-flash">` in IE9 - [issue #71](https://github.com/medialize/ally.js/issues/71)
26+
* changing [`ally.is.focusRelevant`][ally/is/focus-relevant] to properly handle `<object type="application/x-shockwave-flash">` in IE9 - [Issue #71](https://github.com/medialize/ally.js/issues/71)
2727
* fixing [`ally.query.tabsequence`][ally/query/tabsequence] to return `<area>` elements at the correct position - [issue #5](https://github.com/medialize/ally.js/issues/5)
2828
* fixing [`ally.query.tabsequence`][ally/query/tabsequence] to properly sort within Shadow DOM - [issue #6](https://github.com/medialize/ally.js/issues/6)
2929
* refactoring [`ally.query.tabsequence`][ally/query/tabsequence] to extract `util/merge-dom-order` and `util/sort-dom-order`
3030

31+
#### Keyboard support
32+
33+
* changing [`ally.when.key`][ally/when/key] to handle modifier keys and respect `context` and `filter` options - [issue #59](https://github.com/medialize/ally.js/issues/59)
34+
* changing [`ally.map.keycode`][ally/map/keycode] to provide alphanumeric keys and aliasing
35+
3136
#### Internals
3237

3338
* changing `ally.is.*` to work with other documents (e.g. iframes) - [issue #78](https://github.com/medialize/ally.js/issues/78)

build/metalsmith/assets/website.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ main .example h1 {
340340
main table {
341341
border: 1px solid #E5E5E5;
342342
border-collapse: collapse;
343+
width: 100%;
344+
word-break: normal;
343345
}
344346
main th,
345347
main td {

docs/api/map/keycode.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ tags: data
55

66
# ally.map.keycode
77

8-
Map of control [`event.keyCode`](https://developer.mozilla.org/en-US/docs/Web/API/event.keyCode)s.
8+
Map human readable names for [`event.keyCode`](https://developer.mozilla.org/en-US/docs/Web/API/event.keyCode)s.
99

1010

1111
## Description
@@ -26,19 +26,62 @@ var map = {
2626
enter: 13,
2727
escape: 27,
2828
space: 32,
29+
30+
// Function keys
31+
f1: 112,
32+
// ...
33+
34+
// Numeric keys
35+
0: 48,
36+
1: 49,
37+
// ...
38+
"num-0": 96,
39+
"num-1": 97,
40+
// ...
41+
42+
// Latin characters
43+
a: 65,
44+
// ...
45+
z: 90,
2946
}
3047
```
3148

49+
The map knows the following keys:
50+
51+
* `a` - `z`
52+
* `0` - `9`
53+
* `num-0` - `num-9` (number block)
54+
* `f1` - `f25` (function keys)
55+
* `down`, `left`, `right`, `up` (arrow keys)
56+
* `end`, `home`, `pageDown`, `page-down`, `pageUp`, `page-up`
57+
* `enter`, `escape`, `space`, `tab`
58+
* `alt`, `capsLock`, `caps-lock`, `ctrl`, `meta`, `shift`
59+
* `pause`, `insert`, `delete`, `backspace`
60+
3261

3362
## Usage
3463

3564
```js
36-
console.log(ally.map.keycode.enter);
65+
console.log("keycode of enter", ally.map.keycode.enter);
3766
```
3867

3968

69+
## Changes
70+
71+
* `v#master` replaced the key `command` by `meta`.
72+
* `v#master` added `a` - `z`, `0` - `9`, `num-0` - `num-9`, `f13` - `f25`, `page-down`, `page-up`, `caps-lock`.
73+
* `v#master` added `_alias` to resolve multiple keyCodes for the same logical key.
74+
75+
76+
## Notes
77+
78+
* **NOTE:** The key `meta` is known by different keyCodes: `91`, `92`, `93`, `224` - which `ally.map.keycodes.alias.91` helps to resolve. The same is true for numeric keys (0-9) and their counterparts on the numblock.
79+
80+
4081
## Related resources
4182

83+
* [`KeyboardEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) may help deal with this mess in the future.
84+
4285

4386
## Contributing
4487

docs/api/when/key.md

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,49 @@ Executes a callback when a given key has been pressed.
1010

1111
## Description
1212

13-
This is a convenience API to avoid adding and removing keyboard event handlers and having to filter for specific keys in application code. Callbacks are executed on `keydown`.
13+
This is a convenience API to avoid adding and removing keyboard event handlers and having to filter for specific keys in application code. Callbacks are executed synchronously while handling [`keydown`](https://developer.mozilla.org/en-US/docs/Web/Events/keydown) events to maintain the ability to [`event.preventDefault()`](https://developer.mozilla.org/en/docs/Web/API/Event/preventDefault).
14+
15+
Keyboard events are dispatched to the currently focused element (`document.activeElement`). This allows us to handle keyboard events only when the user is engaged in a particular widget.
16+
17+
### Key binding syntax
18+
19+
In order to easily register keyboard events including modifier keys, `ally.when.key` understands the following `<key-binding>` syntax:
20+
21+
| `<key-binding>` | primary key | keyCode | alt | ctrl | meta | shift |
22+
|-----------------|-------------|---------|-----|------|-------|------|
23+
| `space` | <kbd>Space</kbd> | 32 | no | no | no | no |
24+
| `*+space` | <kbd>Space</kbd> | 32 | ? | ? | ? | ? |
25+
| `shift+space` | <kbd>Space</kbd> | 32 | no | no | no | yes |
26+
| `shift+*+enter` | <kbd>Enter</kbd> | 13 | ? | ? | ? | yes |
27+
| `!shift+*+enter` | <kbd>Enter</kbd> | 13 | ? | ? | ? | no |
28+
| `?shift+ctrl+enter` | <kbd>Enter</kbd> | 13 | no | yes | no | ? |
29+
| `enter shift+8` | <kbd>Enter</kbd> | 13 | no | no | no | no |
30+
| *(continued)* | <kbd>Backspace</kbd> | 8 | no | no | no | yes |
31+
32+
Legend: `no` means the modifier key is not pressed, `yes` means the modifier key is pressed, `?` means the state of the modifier key is ignored.
33+
34+
The `<key-binding>` syntax is defined by the following [EBNF](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form) grammar, with `property of map/keycode` referring to the property names of [`ally.map.keycode`](../map/keycode.md):
35+
36+
```ebnf
37+
token-list = token, { " ", token } ;
38+
token = { modifier, "+" }, key ;
39+
key = named-key | keycode ;
40+
named-key = ? property of ally.map.keycode ? ;
41+
keycode = ? /[0-9]+/ ? ;
42+
modifier = ( [ "!" | "?" ], modifier-name ) | "*" ;
43+
modifier-name = "alt" | "ctrl" | "meta" | "shift" ;
44+
```
45+
46+
### Modifier keys
47+
48+
The modifier keys may have different names/symbols depending on operating system and physical keyboard:
49+
50+
| modifier key name | physical key on keyboard |
51+
|-------------------|--------------------------|
52+
| alt | <kbd>Alt</kbd>, <kbd>Option</kbd> or<kbd> ⌥</kbd> on Mac) |
53+
| ctrl | <kbd>Ctrl</kbd>, <kbd>⌃</kbd> on Mac |
54+
| meta | <kbd>Meta</kbd>, <kbd> ⌘</kbd> or <kbd></kbd> or <kbd>Command</kbd> on Mac, <kbd>⊞</kbd> or <kbd>Windows</kbd> on Windows |
55+
| shift | <kbd>Shift</kbd>, <kbd>⇧</kbd> on Mac |
1456

1557

1658
## Usage
@@ -33,19 +75,23 @@ handle.disengage();
3375

3476
### Arguments
3577

36-
The method accepts an object of `<key>: <callback>` mappings. See [Callback Signature](#Callback-Signature) for details
37-
38-
`<key>`s can be specified as a numeric code ([`keyCode`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode)) e.g. `13` for the <kbd>Enter</kbd> key, or as the string name `enter` which is resolved to the numeric code internally using [`ally.map.keycode`](../map/keycode.md). Multiple `<key>: <callback>` combinations can be passed.
78+
| Name | Type | Default | Description |
79+
| ---- | ---- | ------- | ----------- |
80+
| context | [`<selector>`](../concepts.md#Selector) | [`documentElement`](https://developer.mozilla.org/en-US/docs/Web/API/Document/documentElement) | The scope of the DOM in which keyboard events will be processed. The first element of a collection is used. |
81+
| filter | [`<selector>`](../concepts.md#Selector) | `null` | The elements and descendants to exclude when processing keyboard events. |
82+
| [`<key-binding>`](#Key-binding-syntax) | function | *required* | Mapping of `<key-binding>` to callback function. See [Callback Signature](#Callback-Signature) for details. This argument is expected one or more times. |
3983

4084
### Returns
4185

4286
A [`<service>`](../concepts.md#Service) interface, providing the `handle.disengage()` method to stop the service.
4387

4488
### Throws
4589

46-
* [`TypeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) if `<ke>` is neither numeric, nor found in [`ally.map.keycode`](../map/keycode.md).
90+
* [`TypeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) if no `<key-binding>: <callback>` combinations were passed.
91+
* [`TypeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) if `<key-binding>` does not resolve to a keyCode.
92+
* [`TypeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) if `<key-binding>` contains illegal modifier names.
4793
* [`TypeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) if `<callback>` is not a `function`.
48-
* [`TypeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) when no `<key>: <callback>` combinations were passed.
94+
4995

5096
## Callback signature
5197

@@ -54,27 +100,36 @@ A [`<service>`](../concepts.md#Service) interface, providing the `handle.disenga
54100
| event | [`KeyboardEvent`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent) | *required* | The original `keydown` event. |
55101
| disengage | function | *required* | The service's `handle.disengage()` method. |
56102

57-
The callback is executed in the context of `document.documentElement` (that's where `this` inside the callback points to). The callback is passed the `handle.disengage()` method to allow simplified "execute once" behaviors. The callback's return value is ignored.
103+
The callback is executed in the context of `context` (that's where `this` inside the callback points to). The callback is passed the `handle.disengage()` method to allow simplified "execute once" behaviors. The callback's return value is ignored.
58104

59105

60106
## Examples
61107

62108
* **EXAMPLE:** [`ally.when.key` Example](./key.example.html)
63109

64110

111+
## Changes
112+
113+
* `v#master` introduced the extended `<key-binding>` syntax (thereby changing the default modifier key behavior).
114+
* `v#master` introduced the options `context` and `filter`.
115+
116+
65117
## Notes
66118

67119
* **NOTE:** Firefox has a long standing issue with keyboard events propagating to the document while browser UI like autocomplete is being interacted with [Gecko 286933](https://bugzilla.mozilla.org/show_bug.cgi?id=286933).
120+
* **WARNING:** The callback for the `<key-binding>` `space` only executes if *no* modifier key was pressed. In order to make the callback execute regardless of modifier keys, use the `<key-binding>` `*+space`.
121+
* **NOTE:** The modifiers `alt`, `ctrl`, `meta` usually engage system-level or browser-level functionality. Do not use these modifiers lightly. For example `alt+a` prints the letter `å` on a Mac with German keyboard layout, `meta+q` exits the application and `meta+space` engages Spotlight.
68122

69123

70124
## Related resources
71125

72126
* [`ally.map.keycode`](../map/keycode.md) used for resolving named keys
127+
* The `<key-binding>` syntax is inspired by [PolymerElements/iron-a11y-keys](https://github.com/PolymerElements/iron-a11y-keys#grammar)
73128

74129

75130
## Contributing
76131

77132
* [module source](https://github.com/medialize/ally.js/blob/master/src/when/key.js)
78133
* [document source](https://github.com/medialize/ally.js/blob/master/docs/api/when/key.md)
79134
* [unit test](https://github.com/medialize/ally.js/blob/master/test/unit/when.key.test.js)
80-
135+
* uses [when/key.binding](https://github.com/medialize/ally.js/blob/master/src/when/key.binding.js) to parse `<key-binding>`

src/map/keycode.js

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11

2-
// https://github.com/keithamus/jwerty/blob/master/jwerty.js
2+
// codes mostly cloned from https://github.com/keithamus/jwerty/blob/master/jwerty.js
3+
// deliberately not exposing characters like <,.-#* because they vary *wildly*
4+
// across keyboard layouts and may cause various problems
5+
// (e.g. "*" is "Shift +" on a German Mac keyboard)
6+
// (e.g. "@" is "Alt L" on a German Mac keyboard)
37

4-
export default {
8+
const keycode = {
59
// Element Focus
610
tab: 9,
711

@@ -11,7 +15,9 @@ export default {
1115
right: 39,
1216
down: 40,
1317
pageUp: 33,
18+
'page-up': 33,
1419
pageDown: 34,
20+
'page-down': 34,
1521
end: 35,
1622
home: 36,
1723

@@ -23,27 +29,47 @@ export default {
2329
// Modifier
2430
shift: 16,
2531
capsLock: 20,
32+
'caps-lock': 20,
2633
ctrl: 17,
2734
alt: 18,
28-
command: 224,
35+
meta: 91,
36+
// in firefox: 224
37+
// on mac (chrome): meta-left=91, meta-right=93
38+
// on win (IE11): meta-left=91, meta-right=92
2939
pause: 19,
3040

3141
// Content Manipulation
3242
insert: 45,
3343
'delete': 46,
3444
backspace: 8,
3545

36-
// Special Function
37-
f1: 112,
38-
f2: 113,
39-
f3: 114,
40-
f4: 115,
41-
f5: 116,
42-
f6: 117,
43-
f7: 118,
44-
f8: 119,
45-
f9: 120,
46-
f10: 121,
47-
f11: 122,
48-
f12: 123,
46+
// the same logical key may be identified through different keyCodes
47+
_alias: {
48+
91: [92, 93, 224],
49+
},
4950
};
51+
52+
// Function keys (112 - 137)
53+
// NOTE: not every keyboard knows F13+
54+
for (let n = 1; n < 26; n++) {
55+
keycode['f' + n] = n + 111;
56+
}
57+
58+
// Number keys (48-57, numpad 96-105)
59+
// NOTE: not every keyboard knows num-0+
60+
for (let n = 0; n < 10; n++) {
61+
const code = n + 48;
62+
const numCode = n + 96;
63+
keycode[n] = code;
64+
keycode['num-' + n] = numCode;
65+
keycode._alias[code] = [numCode];
66+
}
67+
68+
// Latin characters (65 - 90)
69+
for (let n = 0; n < 26; n++) {
70+
const code = n + 65;
71+
const name = String.fromCharCode(code).toLowerCase();
72+
keycode[name] = code;
73+
}
74+
75+
export default keycode;

0 commit comments

Comments
 (0)