Skip to content
This repository was archived by the owner on May 5, 2023. It is now read-only.

Commit b16958e

Browse files
authored
More info about pressed keys on events (#55)
* added pressedKeys * check for mouse events * updated changelog and readme
1 parent 40fbc90 commit b16958e

5 files changed

Lines changed: 60 additions & 17 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [2.9.3]
8+
### Added
9+
- Added `KeyDetails` param on callback functions `onEnterPress` and `onArrowPress`
10+
711
## [2.9.2]
812
### Fixed
913
- Fixed issue #46 Focus jumps on wrong component: Removed `setTimeout` in `measureLayout` to avoid coordinates mismatches with DOM nodes.

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,11 @@ String that is used as a component focus key. Should be **unique**, otherwise it
260260
Callback function that is called when the item is currently focused and Enter (OK) key is pressed.
261261

262262
Payload:
263-
All the props passed to HOC is passed back to this callback. Useful to avoid creating callback functions during render.
263+
1. All the props passed to HOC is passed back to this callback. Useful to avoid creating callback functions during render.
264+
2. [Details](#keydetails-object) - info about pressed keys
264265

265266
```jsx
266-
const onPress = ({prop1, prop2}) => {...};
267+
const onPress = ({prop1, prop2}, details) => {...};
267268

268269
...
269270
<FocusableItem
@@ -280,6 +281,7 @@ Callback function that is called when the item is currently focused and an arrow
280281
Payload:
281282
1. The directional arrow (left, right, up, down): string
282283
2. All the props passed to HOC is passed back to this callback. Useful to avoid creating callback functions during render.
284+
3. [Details](#keydetails-object) - info about pressed keys
283285

284286
Prevent default navigation:
285287
By returning `false` the default navigation behavior is prevented.
@@ -373,6 +375,19 @@ This function pauses key listeners. Useful when you need to temporary disable na
373375
### `resumeSpatialNavigation`: function
374376
This function resumes key listeners if it was paused with [pauseSpatialNavigation](#pauseSpatialNavigation-function)
375377

378+
### Data Types
379+
380+
### `KeyDetails`: object
381+
This object contains informations about keys.
382+
```
383+
{
384+
pressedKeys: {
385+
[KEY]: number
386+
}
387+
}
388+
```
389+
`pressedKeys` contains a property for each pressed key in a given moment, the value is the number of keydown events fired before the keyup event.
390+
376391
# Development
377392
## Dev environment
378393
This library is using Parcel to serve the web build.

src/App.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ SpatialNavigation.init({
1414

1515
// SpatialNavigation.setKeyMap(keyMap); -> Custom key map
1616

17+
const KEY_ENTER = 'enter';
18+
1719
const styles = StyleSheet.create({
1820
wrapper: {
1921
flex: 1,
@@ -194,9 +196,12 @@ class Content extends React.PureComponent {
194196
this.onProgramPress = this.onProgramPress.bind(this);
195197
}
196198

197-
onProgramPress(program) {
199+
onProgramPress(programProps, {pressedKeys} = {}) {
200+
if (pressedKeys && pressedKeys[KEY_ENTER] > 1) {
201+
return;
202+
}
198203
this.setState({
199-
currentProgram: program
204+
currentProgram: programProps
200205
});
201206
}
202207

@@ -324,7 +329,7 @@ class Category extends React.PureComponent {
324329
{programs.map((program, index) => ((<ProgramFocusable
325330
{...program}
326331
focusKey={`PROGRAM-${this.props.realFocusKey}-${index}`}
327-
onPress={this.props.onProgramPress}
332+
onPress={() => this.props.onProgramPress(program)}
328333
onEnterPress={this.props.onProgramPress}
329334
key={program.title}
330335
onBecameFocused={this.onProgramFocused}

src/spatialNavigation.js

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@ class SpatialNavigation {
292292
this.nativeMode = false;
293293
this.throttle = 0;
294294

295+
this.pressedKeys = {};
296+
295297
/**
296298
* Flag used to block key events from this service
297299
* @type {boolean}
@@ -374,6 +376,10 @@ class SpatialNavigation {
374376
}
375377
}
376378

379+
getEventType(keyCode) {
380+
return findKey(this.getKeyMap(), (code) => keyCode === code);
381+
}
382+
377383
bindEventHandlers() {
378384
if (window) {
379385
this.keyDownEventListener = (event) => {
@@ -385,22 +391,28 @@ class SpatialNavigation {
385391
this.logIndex += 1;
386392
}
387393

388-
const eventType = findKey(this.getKeyMap(), (code) => event.keyCode === code);
394+
const eventType = this.getEventType(event.keyCode);
389395

390396
if (!eventType) {
391397
return;
392398
}
393399

400+
this.pressedKeys[eventType] = this.pressedKeys[eventType] ? this.pressedKeys[eventType] + 1 : 1;
401+
394402
event.preventDefault();
395403
event.stopPropagation();
396404

405+
const details = {
406+
pressedKeys: this.pressedKeys
407+
};
408+
397409
if (eventType === KEY_ENTER && this.focusKey) {
398-
this.onEnterPress();
410+
this.onEnterPress(details);
399411

400412
return;
401413
}
402414

403-
const preventDefaultNavigation = this.onArrowPress(eventType) === false;
415+
const preventDefaultNavigation = this.onArrowPress(eventType, details) === false;
404416

405417
if (preventDefaultNavigation) {
406418
this.log('keyDownEventListener', 'default navigation prevented');
@@ -414,13 +426,20 @@ class SpatialNavigation {
414426
if (this.throttle) {
415427
this.keyDownEventListener =
416428
lodashThrottle(this.keyDownEventListener.bind(this), this.throttle, THROTTLE_OPTIONS);
429+
}
417430

418-
// When throttling then make sure to only throttle key down and cancel any queued functions in case of key up
419-
this.keyUpEventListener = () => this.keyDownEventListener.cancel();
431+
// When throttling then make sure to only throttle key down and cancel any queued functions in case of key up
432+
this.keyUpEventListener = (event) => {
433+
const eventType = this.getEventType(event.keyCode);
420434

421-
window.addEventListener('keyup', this.keyUpEventListener);
422-
}
435+
Reflect.deleteProperty(this.pressedKeys, eventType);
436+
437+
if (this.throttle) {
438+
this.keyDownEventListener.cancel();
439+
}
440+
};
423441

442+
window.addEventListener('keyup', this.keyUpEventListener);
424443
window.addEventListener('keydown', this.keyDownEventListener);
425444
}
426445
}
@@ -437,7 +456,7 @@ class SpatialNavigation {
437456
}
438457
}
439458

440-
onEnterPress() {
459+
onEnterPress(details) {
441460
const component = this.focusableComponents[this.focusKey];
442461

443462
/* Guard against last-focused component being unmounted at time of onEnterPress (e.g due to UI fading out) */
@@ -454,7 +473,7 @@ class SpatialNavigation {
454473
return;
455474
}
456475

457-
component.onEnterPressHandler && component.onEnterPressHandler();
476+
component.onEnterPressHandler && component.onEnterPressHandler(details);
458477
}
459478

460479
onArrowPress(...args) {

src/withFocusable.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,13 @@ const withFocusable = ({
7272
onEnterPressHandler: ({
7373
onEnterPress = noop,
7474
...rest
75-
}) => () => {
76-
onEnterPress(rest);
75+
}) => (details) => {
76+
onEnterPress(rest, details);
7777
},
7878
onArrowPressHandler: ({
7979
onArrowPress = noop,
8080
...rest
81-
}) => (...args) => onArrowPress(...args, rest),
81+
}) => (direction, details) => onArrowPress(direction, rest, details),
8282
onBecameFocusedHandler: ({
8383
onBecameFocused = noop,
8484
...rest

0 commit comments

Comments
 (0)