Merge "[ion/device] Fix events generation"

This commit is contained in:
Romain Goyet
2017-03-31 10:51:00 +02:00
committed by Gerrit

View File

@@ -50,53 +50,54 @@ static bool sleepWithTimeout(int duration, int * timeout) {
}
}
// Debouncing, and change to get_key event.
Event sLastEvent = Events::None;
Keyboard::State sLastKeyboardState = 0;
bool sEventIsRepeating = 0;
constexpr int delayBeforeRepeat = 200;
constexpr int delayBetweenRepeat = 50;
bool canRepeatEvent(Event e) {
return (e == Events::Left || e == Events::Up || e == Events::Down || e == Events::Right || e == Events::Backspace);
}
// FIXME: Timeout is ignored!
Event getEvent(int * timeout) {
// Let's start by saving which keys we've seen up
Keyboard::State keysSeenUp = ~Keyboard::scan();
/* We'll need to sleep to prevent keys from repeating too fast.
* As a rule of thumb, we'll assume that the user cannot input more than 20
* keys per second. That gives a 50ms minimum delay between events. */
int sleepDelay = 50;
// The following two operations could be looped
// 1 - Wait a little to deal with establishing contacts (debouncing)
if (sleepWithTimeout(sleepDelay, timeout)) {
return Ion::Events::None;
}
/* 2 - Let's discard the keys we previously saw up but which aren't anymore:
* those were probably bouncing indeed. In terms of logic, that gives :
* Initial keysSeenUp : 0001001
* Current scan : 1111110
* Updated keysSeenUp : 0000001
* In other works, updated = initial "or not" scan.*/
keysSeenUp |= ~Keyboard::scan();
int time = 0;
Keyboard::State keysSeenUp = 0;
Keyboard::State keysSeenTransitionningFromUpToDown = 0;
while (true) {
Keyboard::State state = Keyboard::scan();
/* We want to detect keys that are now down (1 in scan) and that were
* previously up (1 in keysSeenUp). */
Keyboard::State match = state & keysSeenUp;
// Let's take this opportunity to update the keys we've seen up
keysSeenUp |= ~state;
if (match != 0) {
keysSeenTransitionningFromUpToDown = keysSeenUp & state;
if (keysSeenTransitionningFromUpToDown != 0) {
sEventIsRepeating = false;
/* The key that triggered the event corresponds to the first non-zero bit
* in "match". This is a rather simple logic operation for the which many
* processors have an instruction (ARM thumb uses CLZ).
* Unfortunately there's no way to express this in standard C, so we have
* to resort to using a builtin function. */
Keyboard::Key key = (Keyboard::Key)(63-__builtin_clzll(match));
Event result(key, sIsShiftActive, sIsAlphaActive || sIsAlphaLocked);
updateModifiersFromEvent(result);
return result;
Keyboard::Key key = (Keyboard::Key)(63-__builtin_clzll(keysSeenTransitionningFromUpToDown));
Event event(key, sIsShiftActive, sIsAlphaActive || sIsAlphaLocked);
updateModifiersFromEvent(event);
sLastEvent = event;
sLastKeyboardState = state;
return event;
}
// Last but not least, sleep for a bit if we didn't find anything
if (sleepWithTimeout(sleepDelay, timeout)) {
return Ion::Events::None;
msleep(10);
time += 10;
// At this point, we know that keysSeenTransitionningFromUpToDown has *always* been zero
// In other words, no new key has been pressed
if (canRepeatEvent(sLastEvent) && (state == sLastKeyboardState)) {
int delay = (sEventIsRepeating ? delayBetweenRepeat : delayBeforeRepeat);
if (time >= delay) {
sEventIsRepeating = true;
sLastKeyboardState = state;
return sLastEvent;
}
}
}
}