KeyboardManager: a class to manage the polling of a switch-matrix keyboard
Revision 3:1310c57aca77, committed 2011-02-03
- Comitter:
- osmeest
- Date:
- Thu Feb 03 22:01:57 2011 +0000
- Parent:
- 2:eb4cc53ff33d
- Commit message:
- improve code structure, add key mapping and long key press handling
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/KeyMapper.cpp Thu Feb 03 22:01:57 2011 +0000 @@ -0,0 +1,57 @@ +#include "kbd_mgr/KeyMapper.h" +#include <algorithm> +#include <functional> + +namespace kbd_mgr { + +void KeyMap::addMapping(KeyEvent::EventType event, int key, char ch) +{ + const KeyMapping *mapping = getMapping(event, key); + if (mapping) { + KeyMapping *updatable = const_cast<KeyMapping*>(mapping); + updatable->ch = ch; + } + else { + KeyMapping o(event, key, ch); + this->map_.push_back(o); + } +} + +void KeyMap::addMappings(KeyEvent::EventType event, const std::string &str) +{ + for(int key = 0; key < str.size(); ++key) { + addMapping(event, key, str[key]); + } +} + +char KeyMap::map(KeyEvent::EventType event, int key) const +{ + const KeyMapping *mapping = getMapping(event, key); + if (!mapping) { + mapping = getMapping(KeyEvent::NoEvent, key); + } + return (mapping ? mapping->ch : '\0'); +} + +const KeyMap::KeyMapping * KeyMap::getMapping(KeyEvent::EventType event, int key) const +{ + std::pair<KeyEvent::EventType, int> criteria = std::make_pair(event, key); + Map::const_iterator p = this->map_.begin(); + while (p != this->map_.end() && !p->matches(criteria)) { + ++p; + } + + if (p == this->map_.end()) { + return NULL; + } + return &(*p); +} + +void KeyMapper::handleKeyPress(const KeyEvent &keypress) +{ + char ch = map(keypress.event, keypress.keyCode); + KeyEvent mapped(keypress, ch); + invokeHandler(mapped); +} + +} // kbd_mgr
--- a/KeyboardManager.cpp Sun Jan 23 23:15:36 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -#include "kbd_mgr/KeyboardManager.h" -#include "kbd_mgr/KeyboardMonitor.h" -#include "kbd_mgr/KeyboardStateChangeMonitor.h" -#include "kbd_mgr/SingleKeyPressMonitor.h" - -namespace kbd_mgr { - -struct KeyboardManager::Impl { - SingleKeyPressMonitor keyPressMonitor; - KeyboardStateChangeMonitor stateChangeMonitor; - KeyboardMonitor monitor; - - Impl(PortName inPort, std::size_t numKeysPerRow, int inLowestBit, - const OutPinsSet &outPins, KeyPressEventHandler *handler) : - keyPressMonitor(handler), - stateChangeMonitor(&keyPressMonitor), - monitor(inPort, numKeysPerRow, inLowestBit, outPins, &stateChangeMonitor) - { } -}; - -KeyboardManager::KeyboardManager( - PortName inPort, std::size_t numKeysPerRow, int inLowestBit, - const OutPinsSet &outPins, KeyPressEventHandler *handler) : - pimpl(new Impl(inPort, numKeysPerRow, inLowestBit, outPins, handler)) -{ } - -void KeyboardManager::start(float pollingPeriod) -{ - this->pimpl->monitor.start(pollingPeriod); -} - -void KeyboardManager::stop() -{ - this->pimpl->monitor.stop(); -} - -} // kbd_mgr
--- a/KeyboardMonitor.cpp Sun Jan 23 23:15:36 2011 +0000 +++ b/KeyboardMonitor.cpp Thu Feb 03 22:01:57 2011 +0000 @@ -1,52 +1,55 @@ -#include "kbd_mgr/KeyboardMonitor.h" - -namespace kbd_mgr { - -KeyboardMonitor::KeyboardMonitor(PortName inPort, std::size_t numKeysPerRow, std::size_t inLowestBit, - const KeyboardMonitor::OutPinsSet &outPins, KeyboardStateHandler *handler) : - in(inPort, ((1 << numKeysPerRow)-1) << inLowestBit), inBitShift(inLowestBit), outPins(outPins), handler(handler), - ticker(), scanRow(0), currentState(outPins.size(), numKeysPerRow) -{ } - -void KeyboardMonitor::start(float pollingPeriod) -{ - if (this->outPins.empty()) { - return; - } - - if (pollingPeriod < 20e-6) { - pollingPeriod = 20e-6; - } - - for(OutPinsSet::const_iterator p = this->outPins.begin(); p != this->outPins.end(); ++p) { - DigitalOut out(*p); - out.write( p == this->outPins.begin() ? 1 : 0 ); - } - this->in.mode(PullDown); - this->scanRow = 0; - this->ticker.attach(this, &KeyboardMonitor::timerHandler, pollingPeriod); -} - -void KeyboardMonitor::stop() -{ - this->ticker.detach(); - this->in.mode(OpenDrain); -} - -void KeyboardMonitor::timerHandler() -{ - DigitalOut out(this->outPins[this->scanRow]); - out.write(1); - wait_us(10); - int v = (this->in.read() >> this->inBitShift); - out.write(0); - this->currentState.setRowState(this->scanRow, v); - this->scanRow = (this->scanRow + 1) % this->currentState.getNumRows(); - if (this->scanRow == 0) { - if (this->handler) { - (*this->handler)(this->currentState); - } - } -} - -} // kbd_mgr +#include "kbd_mgr/KeyboardMonitor.h" + +namespace kbd_mgr { + +KeyboardMonitor::KeyboardMonitor(PortName inPort, std::size_t numKeysPerRow, std::size_t inLowestBit, + const KeyboardMonitor::OutPinsSet &outPins) : + in(inPort, ((1 << numKeysPerRow)-1) << inLowestBit), inBitShift(inLowestBit), outPins(outPins), + ticker(), scanRow(0), currentState(outPins.size(), numKeysPerRow) +{ } + +KeyboardMonitor::~KeyboardMonitor() +{ + stop(); +} + +void KeyboardMonitor::start(float pollingPeriod) +{ + if (this->outPins.empty()) { + return; + } + + if (pollingPeriod < 20e-6) { + pollingPeriod = 20e-6; + } + + for(OutPinsSet::const_iterator p = this->outPins.begin(); p != this->outPins.end(); ++p) { + DigitalOut out(*p); + out.write( p == this->outPins.begin() ? 1 : 0 ); + } + this->in.mode(PullDown); + this->scanRow = 0; + this->ticker.attach(this, &KeyboardMonitor::timerHandler, pollingPeriod); +} + +void KeyboardMonitor::stop() +{ + this->ticker.detach(); + this->in.mode(OpenDrain); +} + +void KeyboardMonitor::timerHandler() +{ + DigitalOut out(this->outPins[this->scanRow]); + out.write(1); + wait_us(10); + int v = (this->in.read() >> this->inBitShift); + out.write(0); + this->currentState.setRowState(this->scanRow, v); + this->scanRow = (this->scanRow + 1) % this->currentState.getNumRows(); + if (this->scanRow == 0) { + invokeHandler(this->currentState); + } +} + +} // kbd_mgr
--- a/KeyboardState.cpp Sun Jan 23 23:15:36 2011 +0000 +++ b/KeyboardState.cpp Thu Feb 03 22:01:57 2011 +0000 @@ -1,170 +1,170 @@ -#include "kbd_mgr/KeyboardState.h" - -#include <algorithm> -#include <iomanip> - -namespace kbd_mgr { - -KeyboardState::KeyboardState() : - numRows(0), numKeysPerRow(0), rowMask(0), numRowsPerWord(0), numKeysPerWord(0), numWords(0), data(0) -{ } - -KeyboardState::KeyboardState(std::size_t numRows, std::size_t numKeysPerRow) : - numRows(numRows), numKeysPerRow(numKeysPerRow), rowMask((1 << numKeysPerRow) -1), - numRowsPerWord((sizeof(int) * 8) / numKeysPerRow), numKeysPerWord(numRowsPerWord * numKeysPerRow), - numWords((numRows + (numRowsPerWord-1)) / numRowsPerWord), - data(numWords, 0) -{ } - -void KeyboardState::clear() { - std::fill(this->data.begin(), this->data.end(), 0); -} - -int KeyboardState::getRowInfo(std::size_t row, std::size_t &wordIndex, std::size_t &rowShift, int &rowMask) const -{ - std::size_t rowInWord = row % numRowsPerWord; - wordIndex = row / numRowsPerWord; - rowShift = numKeysPerRow * rowInWord; - rowMask = this->rowMask << rowShift; - - return this->data[wordIndex]; -} - -void KeyboardState::setRowState(std::size_t row, int rowState) { - std::size_t wordIndex; - std::size_t rowShift; - int rowMask; - int v = getRowInfo(row, wordIndex, rowShift, rowMask); - v = (v & ~rowMask) | ((rowState & this->rowMask) << rowShift); - this->data[wordIndex] = v; -} - -int KeyboardState::getRowState(std::size_t row) const { - std::size_t wordIndex; - std::size_t rowShift; - int rowMask; - int v = getRowInfo(row, wordIndex, rowShift, rowMask); - return (v & rowMask) >> rowShift; -} - -bool KeyboardState::getKeyState(std::size_t key) const { - std::size_t row = key / this->numKeysPerRow; - std::size_t keyInRow = key % this->numKeysPerRow; - int keyMask = 1 << keyInRow; - - return (getRowState(row) & keyMask) != 0; -} - -KeyboardState KeyboardState::operator&(const KeyboardState &other) const { - KeyboardState result(this->numRows, this->numKeysPerRow); - - typedef Data::const_iterator SourceIterator; - typedef Data::iterator TargetIterator; - - SourceIterator a = this->data.begin(); - SourceIterator b = other.data.begin(); - TargetIterator t = result.data.begin(); - while (a != this->data.end() && b != other.data.end() && t != result.data.end()) - { - *t = *a & *b; - ++a; ++b; ++t; - } - - return result; -} - -bool KeyboardState::operator==(const KeyboardState &other) const { - if (this == &other) { - return true; - } - - if (this->numRows != other.numRows || this->numKeysPerRow != other.numKeysPerRow) - return false; - - Data::const_iterator p = this->data.begin(); - Data::const_iterator q = other.data.begin(); - while (p != this->data.end() && q != other.data.end()) { - if (*p != *q) { - return false; - } - ++p; ++q; - } - - return true; -} - -bool KeyboardState::empty() const { - for(Data::const_iterator p = this->data.begin(); p != this->data.end(); ++p) { - if (*p != 0) { - return false; - } - } - - return true; -} - -namespace { - int getBitNumber(int v) - { - if (v == 0) { - return -1; - } - - int key = 0; - while (v != 1) { - key++; - v >>= 1; - } - - return key; - } -} - -KeyboardState::KeyPressType KeyboardState::getKeyPressType(int *key) const -{ - if (key) { - *key = -1; - } - - Data::const_iterator p = this->data.begin(); - std::size_t wordIndex = 0; - while (p != this->data.end() && *p == 0) { - ++p; - ++wordIndex; - } - if (p != this->data.end()) { - int v = *p; - if (v != (v & -v)) { - return MultiKeyPress; - } - int k = getBitNumber(v) + wordIndex * this->numKeysPerWord; - ++p; - while (p != this->data.end() && *p == 0) { - ++p; - } - if (p == this->data.end()) { - if (key) { - *key = k; - } - return SingleKeyPress; - } - else { - return MultiKeyPress; - } - } - else { - return Idle; - } -} - -void KeyboardState::streamTo(std::ostream &out) const { - using namespace std; - std::size_t width = (this->numKeysPerWord + 3) / 4; - ios_base::fmtflags f = out.flags(); - for(Data::const_reverse_iterator p = this->data.rbegin(); p != this->data.rend(); ++p) { - out << hex << setw(width) << setfill('0') << *p; - } - out.flags(f); -} - +#include "kbd_mgr/KeyboardState.h" + +#include <algorithm> +#include <iomanip> + +namespace kbd_mgr { + +KeyboardState::KeyboardState() : + numRows(0), numKeysPerRow(0), rowMask(0), numRowsPerWord(0), numKeysPerWord(0), numWords(0), data(0) +{ } + +KeyboardState::KeyboardState(std::size_t numRows, std::size_t numKeysPerRow) : + numRows(numRows), numKeysPerRow(numKeysPerRow), rowMask((1 << numKeysPerRow) -1), + numRowsPerWord((sizeof(int) * 8) / numKeysPerRow), numKeysPerWord(numRowsPerWord * numKeysPerRow), + numWords((numRows + (numRowsPerWord-1)) / numRowsPerWord), + data(numWords, 0) +{ } + +void KeyboardState::clear() { + std::fill(this->data.begin(), this->data.end(), 0); +} + +int KeyboardState::getRowInfo(std::size_t row, std::size_t &wordIndex, std::size_t &rowShift, int &rowMask) const +{ + std::size_t rowInWord = row % numRowsPerWord; + wordIndex = row / numRowsPerWord; + rowShift = numKeysPerRow * rowInWord; + rowMask = this->rowMask << rowShift; + + return this->data[wordIndex]; +} + +void KeyboardState::setRowState(std::size_t row, int rowState) { + std::size_t wordIndex; + std::size_t rowShift; + int rowMask; + int v = getRowInfo(row, wordIndex, rowShift, rowMask); + v = (v & ~rowMask) | ((rowState & this->rowMask) << rowShift); + this->data[wordIndex] = v; +} + +int KeyboardState::getRowState(std::size_t row) const { + std::size_t wordIndex; + std::size_t rowShift; + int rowMask; + int v = getRowInfo(row, wordIndex, rowShift, rowMask); + return (v & rowMask) >> rowShift; +} + +bool KeyboardState::getKeyState(std::size_t key) const { + std::size_t row = key / this->numKeysPerRow; + std::size_t keyInRow = key % this->numKeysPerRow; + int keyMask = 1 << keyInRow; + + return (getRowState(row) & keyMask) != 0; +} + +KeyboardState KeyboardState::operator&(const KeyboardState &other) const { + KeyboardState result(this->numRows, this->numKeysPerRow); + + typedef Data::const_iterator SourceIterator; + typedef Data::iterator TargetIterator; + + SourceIterator a = this->data.begin(); + SourceIterator b = other.data.begin(); + TargetIterator t = result.data.begin(); + while (a != this->data.end() && b != other.data.end() && t != result.data.end()) + { + *t = *a & *b; + ++a; ++b; ++t; + } + + return result; +} + +bool KeyboardState::operator==(const KeyboardState &other) const { + if (this == &other) { + return true; + } + + if (this->numRows != other.numRows || this->numKeysPerRow != other.numKeysPerRow) + return false; + + Data::const_iterator p = this->data.begin(); + Data::const_iterator q = other.data.begin(); + while (p != this->data.end() && q != other.data.end()) { + if (*p != *q) { + return false; + } + ++p; ++q; + } + + return true; +} + +bool KeyboardState::empty() const { + for(Data::const_iterator p = this->data.begin(); p != this->data.end(); ++p) { + if (*p != 0) { + return false; + } + } + + return true; +} + +namespace { + int getBitNumber(int v) + { + if (v == 0) { + return -1; + } + + int key = 0; + while (v != 1) { + key++; + v >>= 1; + } + + return key; + } +} + +KeyboardState::KeyPressType KeyboardState::getKeyPressType(int *key) const +{ + if (key) { + *key = -1; + } + + Data::const_iterator p = this->data.begin(); + std::size_t wordIndex = 0; + while (p != this->data.end() && *p == 0) { + ++p; + ++wordIndex; + } + if (p != this->data.end()) { + int v = *p; + if (v != (v & -v)) { + return MultiKeyPress; + } + int k = getBitNumber(v) + wordIndex * this->numKeysPerWord; + ++p; + while (p != this->data.end() && *p == 0) { + ++p; + } + if (p == this->data.end()) { + if (key) { + *key = k; + } + return SingleKeyPress; + } + else { + return MultiKeyPress; + } + } + else { + return Idle; + } +} + +void KeyboardState::streamTo(std::ostream &out) const { + using namespace std; + std::size_t width = (this->numKeysPerWord + 3) / 4; + ios_base::fmtflags f = out.flags(); + for(Data::const_reverse_iterator p = this->data.rbegin(); p != this->data.rend(); ++p) { + out << hex << setw(width) << setfill('0') << *p; + } + out.flags(f); +} + } // kbd_mgr \ No newline at end of file
--- a/KeyboardStateChangeMonitor.cpp Sun Jan 23 23:15:36 2011 +0000 +++ b/KeyboardStateChangeMonitor.cpp Thu Feb 03 22:01:57 2011 +0000 @@ -1,15 +1,13 @@ -#include "kbd_mgr/KeyboardStateChangeMonitor.h" - -namespace kbd_mgr { - -void KeyboardStateChangeMonitor::operator()(const KeyboardState &newState) -{ - if (newState != this->lastState) { - if (this->handler) { - (*this->handler)(newState); - } - this->lastState = newState; - } -} - -} // kbd_mgr +#include "kbd_mgr/KeyboardStateChangeMonitor.h" + +namespace kbd_mgr { + +void KeyboardStateChangeMonitor::handleState(const KeyboardState &newState) +{ + if (newState != this->lastState) { + invokeHandler(newState); + this->lastState = newState; + } +} + +} // kbd_mgr
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LongKeyPressMonitor.cpp Thu Feb 03 22:01:57 2011 +0000 @@ -0,0 +1,132 @@ +#include <kbd_mgr/LongKeyPressMonitor.h> + +namespace kbd_mgr { + +LongKeyPressMonitor::AutoRepeatSetupProxy LongKeyPressMonitor::autoRepeat(float initTime, float delay) +{ + this->repeatInitTime_ = initTime; + this->repeatDelay_ = delay; + + return AutoRepeatSetupProxy(this); +} + +void LongKeyPressMonitor::addAutoRepeatKey(int firstKey, int lastKey) +{ + for(int key = firstKey; key <= lastKey; ++key) { + this->repeatKeys_.insert(key); + this->longPressKeys_.erase(key); + } +} + +LongKeyPressMonitor::LongPressSetupProxy LongKeyPressMonitor::longKeyPress(float longPressTime) +{ + this->longPressTime_ = longPressTime; + return LongPressSetupProxy(this); +} + +void LongKeyPressMonitor::addLongPressKey(int firstKey, int lastKey) +{ + for(int key = firstKey; key <= lastKey; ++key) { + this->longPressKeys_.insert(key); + this->repeatKeys_.erase(key); + } +} + +void LongKeyPressMonitor::handleKeyPress(const KeyEvent &keypress) +{ + if (keypress.event == KeyEvent::KeyDown) { + invokeHandler(keypress); + handleKeyDown(keypress); + } + else if (keypress.event == KeyEvent::KeyUp) { + handleKeyUp(keypress); + invokeHandler(keypress); + } + else { + invokeHandler(keypress); + } +} + +void LongKeyPressMonitor::handleKeyDown(const KeyEvent &keypress) +{ + this->keyDownCount++; + if (this->keyDownCount == 1) { + handleFirstKeyDown(keypress); + } + else { + handleOtherKeyDown(keypress); + } +} + +void LongKeyPressMonitor::handleFirstKeyDown(const KeyEvent &keypress) +{ + this->keypress = keypress; + + if (isAutoRepeatKey(keypress.keyCode)) { + this->state = RepeatInitWait; + this->timer.attach(this, &LongKeyPressMonitor::handleTimer, this->repeatInitTime_); + } + else if (isLongPressKey(keypress.keyCode)) { + this->state = LongPressWait; + this->timer.attach(this, &LongKeyPressMonitor::handleTimer, this->longPressTime_); + } +} + +void LongKeyPressMonitor::handleOtherKeyDown(const KeyEvent &keypress) +{ + this->state = Invalid; + this->timer.detach(); +} + +void LongKeyPressMonitor::handleKeyUp(const KeyEvent &keypress) +{ + this->keyDownCount--; + + if (this->state == Invalid || this->state == RepeatInitWait || this->state == LongPressWait) { + KeyEvent pressed(keypress, KeyEvent::KeyPress); + invokeHandler(pressed); + } + + if (this->keyDownCount == 0) { + handleLastKeyUp(keypress); + } +} + +void LongKeyPressMonitor::handleLastKeyUp(const KeyEvent &keypress) +{ + this->state = Idle; +} + +void LongKeyPressMonitor::handleTimer() +{ + switch(this->state) { + case RepeatInitWait: + case Repeating: + handleRepeatTimer(); + break; + case LongPressWait: + handleLongPressTimer(); + break; + default: + break; + } +} + +void LongKeyPressMonitor::handleRepeatTimer() +{ + KeyEvent repeated(this->keypress, + (this->state == RepeatInitWait ? KeyEvent::KeyPress : KeyEvent::RepeatedKeyPress)); + invokeHandler(repeated); + + this->state = Repeating; + this->timer.attach(this, &LongKeyPressMonitor::handleTimer, this->repeatDelay_); +} + +void LongKeyPressMonitor::handleLongPressTimer() +{ + KeyEvent longPressed(keypress, KeyEvent::LongKeyPress); + invokeHandler(longPressed); + this->state = LongPressReported; +} + +} // kbd_mgr
--- a/SingleKeyPressMonitor.cpp Sun Jan 23 23:15:36 2011 +0000 +++ b/SingleKeyPressMonitor.cpp Thu Feb 03 22:01:57 2011 +0000 @@ -1,30 +1,28 @@ -#include "kbd_mgr/SingleKeyPressMonitor.h" - -namespace kbd_mgr { - -void SingleKeyPressMonitor::operator()(const KeyboardState &newState) -{ - int key; - if (newState.getKeyPressType(key) == KeyboardState::SingleKeyPress && this->lastReportedState.empty()) - { - if (this->handler) { - (*this->handler)(key, true); - } - - this->lastReportedState = newState; - this->lastReportedKey = key; - } - else if (!this->lastReportedState.empty() && - (newState & this->lastReportedState).empty()) - { - if (this->handler) { - (*this->handler)(this->lastReportedKey, false); - } - - this->lastReportedState.clear(); - this->lastReportedKey = KeyPressEventHandler::NoKey; - } - -} - +#include "kbd_mgr/SingleKeyPressMonitor.h" + +namespace kbd_mgr { + +void SingleKeyPressMonitor::handleState(const KeyboardState &newState) +{ + int key; + if (newState.getKeyPressType(key) == KeyboardState::SingleKeyPress && this->lastReportedState.empty()) + { + KeyEvent keyDown(key, KeyEvent::KeyDown); + invokeHandler(keyDown); + + this->lastReportedState = newState; + this->lastReportedKey = key; + } + else if (!this->lastReportedState.empty() && + (newState & this->lastReportedState).empty()) + { + KeyEvent keyUp(this->lastReportedKey, KeyEvent::KeyUp); + invokeHandler(keyUp); + + this->lastReportedState.clear(); + this->lastReportedKey = KeyEvent::NoKey; + } + +} + } // kbd_mgr \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kbd_mgr/KeyMapper.h Thu Feb 03 22:01:57 2011 +0000 @@ -0,0 +1,123 @@ +#ifndef KEY_MAPPER_H_ +#define KEY_MAPPER_H_ + +#include "kbd_mgr/KeyPressEventServer.h" + +#include <vector> +#include <string> +#include <utility> + +namespace kbd_mgr { + +/** + * @brief A class used to store a set of key mappings. + * It associates a key event and a key code to a mapped character. + * It also allows to specify a mapping for any unmatched key event of a key. + * The KeyMap can be set at construction time with a string and an optional key event. + * Additional mappings can be specified by using the () operator. This way, both individual mappings and string mappings are possible. + * Eg. keymap(KeyEvent::LongKeyPress, 1, '@')(1, '*') + * maps the key 1 to '*' for all key presses but to '@' when a long key press occurs. + */ +class KeyMap { +public: + /** + * @brief Creates an empty keymap. + */ + KeyMap() : map_() { } + + /** + * @brief Creates a keymap based on a string. + * Each character is mapped to the key at that position (key 1 maps to str[1]). + */ + KeyMap(const std::string &str) : map_() { + addMappings(KeyEvent::NoEvent, str); + } + /** + * @brief Creates a keymap based on a string for a certain key event. + * Each character is mapped to the key at that position (key 1 maps to str[1]). + */ + KeyMap(KeyEvent::EventType event, const std::string &str) : map_() { + addMappings(event, str); + } + + /** + * @brief Adds key mappings based on the given string. + */ + KeyMap& operator()(const std::string &str) { + addMappings(KeyEvent::NoEvent, str); + return *this; + } + + /** + * @brief Adds key mappings based on the given string for a given event. + */ + KeyMap& operator()(KeyEvent::EventType event, const std::string &str) { + addMappings(event, str); + return *this; + } + + /** + * @brief Adds a key mapping for a key. + */ + KeyMap& operator()(int key, char ch) { + addMapping(KeyEvent::NoEvent, key, ch); + return *this; + } + + /** + * @brief Adds a key mapping for a key event & code combo. + */ + KeyMap& operator()(KeyEvent::EventType event, int key, char ch) { + addMapping(event, key, ch); + return *this; + } + + /** + * @brief Gets the mapped character for a key press event. + */ + char map(KeyEvent::EventType event, int key) const; + +private: + struct KeyMapping { + KeyEvent::EventType event; + int key; + char ch; + + KeyMapping(KeyEvent::EventType event, int key, char ch) : event(event), key(key), ch(ch) { } + + bool matches(const std::pair<KeyEvent::EventType, int> &arg) const { + return this->event == arg.first && this->key == arg.second; + } + }; + + void addMapping(KeyEvent::EventType event, int key, char ch); + void addMappings(KeyEvent::EventType event, const std::string &str); + const KeyMapping * getMapping(KeyEvent::EventType event, int key) const; + + typedef std::vector<KeyMapping> Map; + Map map_; +}; + +/** + * @brief A key press event handler that adds a mapped key char to key events. + * Mappings can be specified for any key press event or for some specific key press event. + */ +class KeyMapper : public KeyPressEventServer, public KeyPressEventHandler { +public: + + KeyMapper(const KeyMap &keymap = KeyMap()) : + keymap_(keymap) + { } + + const KeyMap & keymap() const { return this->keymap_; } + char map(KeyEvent::EventType event, int key) const { return this->keymap_.map(event, key); } + + virtual void handleKeyPress(const KeyEvent &keypress); + +private: + KeyMap keymap_; +}; + +} // kbd_mgr + +#endif // KEY_MAPPER_H_
--- a/kbd_mgr/KeyPressEventHandler.h Sun Jan 23 23:15:36 2011 +0000 +++ b/kbd_mgr/KeyPressEventHandler.h Thu Feb 03 22:01:57 2011 +0000 @@ -1,21 +1,82 @@ -#ifndef KEY_PRESS_EVENT_HANDLER_H_ -#define KEY_PRESS_EVENT_HANDLER_H_ - -namespace kbd_mgr { - -/** - * @brief Interface used to report key presses and releases. - */ -class KeyPressEventHandler { -public: - enum { - NoKey = -1 - }; - - virtual void operator()(int key, bool keyDown) = 0; - virtual ~KeyPressEventHandler() { } -}; - -} // kbd_mgr - -#endif // KEY_PRESS_EVENT_HANDLER_H_ +#ifndef KEY_PRESS_EVENT_HANDLER_H_ +#define KEY_PRESS_EVENT_HANDLER_H_ + +namespace kbd_mgr { + +struct KeyEvent { + enum KeyId { + NoKey = -1 + }; + + enum EventType { + NoEvent, KeyDown, KeyPress, RepeatedKeyPress, LongKeyPress, KeyUp + }; + + int keyCode; + char keyChar; + EventType event; + + KeyEvent() : keyCode(NoKey), keyChar(0), event(NoEvent) { } + + /** + * @brief Creates a raw key event (no char). + */ + KeyEvent(int key, EventType event) : keyCode(key), keyChar(0), event(event) { } + + /** + * @brief Converts a raw key event into a mapped key. + */ + KeyEvent(const KeyEvent &raw, char ch) : keyCode(raw.keyCode), keyChar(ch), event(raw.event) { } + + /** + * @brief Creates a key event with a different event code. + */ + KeyEvent(const KeyEvent &other, EventType event) : keyCode(other.keyCode), keyChar(other.keyChar), event(event) { } +}; + +/** + * @brief Interface used to report key presses and releases. + */ +class KeyPressEventHandler { +public: + virtual void handleKeyPress(const KeyEvent &keypress) = 0; + virtual ~KeyPressEventHandler() { } +}; + +template <class T> +class MemberKeyPressEventHandler : public KeyPressEventHandler { +public: + typedef void (T::*MemberFunction)(const KeyEvent &keypress); + + MemberKeyPressEventHandler(T *obj, MemberFunction fn) : + object(obj), func(fn) + { } + + virtual void handleKeyPress(const KeyEvent &keypress) { + (object->*func)(keypress); + } + +private: + T *object; + MemberFunction func; +}; + +class FunctionKeyPressEventHandler : public KeyPressEventHandler { +public: + typedef void (*HandlerFunction)(const KeyEvent &keypress); + + FunctionKeyPressEventHandler(HandlerFunction fn) : + func(fn) + { } + + virtual void handleKeyPress(const KeyEvent &keypress) { + func(keypress); + } + +private: + HandlerFunction func; +}; + +} // kbd_mgr + +#endif // KEY_PRESS_EVENT_HANDLER_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kbd_mgr/KeyPressEventServer.h Thu Feb 03 22:01:57 2011 +0000 @@ -0,0 +1,43 @@ +#ifndef KEYPRESS_EVENT_SERVER_H_ +#define KEYPRESS_EVENT_SERVER_H_ + +#include "kbd_mgr/KeyboardEventServer.h" +#include "kbd_mgr/KeyPressEventHandler.h" + +namespace kbd_mgr { + +/** + * @brief A base class for monitors that report keypresses. + */ +class KeyPressEventServer : public KeyboardEventServer<KeyPressEventHandler> { +public: + /** + * @brief Attaches the monitor to a function. + * @param fn Event handler called to report keyboard state change. + */ + void attach(FunctionKeyPressEventHandler::HandlerFunction fn) { + setHandler(new FunctionKeyPressEventHandler(fn)); + } + + /** + * @brief Attaches the monitor to a method of an object. + * @param obj Event handler object + * @param fn Event handler method called to report keyboard state after each complete scan. + */ + template <class T> + void attach(T *obj, typename MemberKeyPressEventHandler<T>::MemberFunction fn) { + setHandler(new MemberKeyPressEventHandler<T>(obj, fn)); + } + + using KeyboardEventServer<KeyPressEventHandler>::attach; + + void invokeHandler(const KeyEvent &keypress) { + if (this->hasHandler()) { + this->handler()->handleKeyPress(keypress); + } + } +}; + +} // kbd_mgr + +#endif // KEYPRESS_EVENT_SERVER_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kbd_mgr/KeyboardEventServer.h Thu Feb 03 22:01:57 2011 +0000 @@ -0,0 +1,54 @@ +#ifndef KEYBOARD_EVENT_SERVER_H_ +#define KEYBOARD_EVENT_SERVER_H_ + +#include <cstdlib> + +namespace kbd_mgr { + +template <class HandlerClass> +class KeyboardEventServer { +protected: + KeyboardEventServer() : handler_(NULL), ownHandler_(false) { } + + ~KeyboardEventServer() + { + clearHandler(); + } + + void setHandler(HandlerClass *h, bool owner = true) { + this->handler_ = h; + this->ownHandler_ = owner; + } + + void clearHandler() { + if (this->ownHandler_) { + delete this->handler_; + } + this->handler_ = NULL; + this->ownHandler_ = false; + } + + HandlerClass *handler() const { return this->handler_; } + + bool hasHandler() const { return this->handler_ != NULL; } + +public: + void attach(HandlerClass *handler) { + setHandler(handler, false); + } + void attach(HandlerClass &handler) { + setHandler(&handler, false); + } + + void detach() { + clearHandler(); + } + +private: + HandlerClass *handler_; + bool ownHandler_; +}; + +} // kbd_mgr + +#endif // KEYBOARD_EVENT_SERVER_H_
--- a/kbd_mgr/KeyboardManager.h Sun Jan 23 23:15:36 2011 +0000 +++ b/kbd_mgr/KeyboardManager.h Thu Feb 03 22:01:57 2011 +0000 @@ -1,52 +1,5 @@ -#ifndef KEYBOARD_MANAGER_HPP_ -#define KEYBOARD_MANAGER_HPP_ - -#include "kbd_mgr/KeyPressEventHandler.h" - -#include "mbed.h" -#include <memory> -#include <vector> - -namespace kbd_mgr { - -/** - * @brief A class that polls the state of a NxM switch-matrix keyboard. - * For efficiency reasons, this class uses contiguous bits in a GPIO ports for reading the state of the keys in a row. - * Key rows are activated one by one using a set of digital outputs. - * Each time a key press or a key release is detected, the specified event handler is invoked. - * As the managed switch matrix is not protected against cross-overs, multiple key presses are - * ignored (only the state changes of the first key pressed are reported). - */ -class KeyboardManager { -public: - typedef std::vector<PinName> OutPinsSet; - - /** - * @param inPort Port to be used for reading the key state. - * @param numKeysPerRow Number of keys in a row (N) - * @param inLowestBit Index of the lowest bit of inPort (using inLowestBit to inLowestBit+N). - * @param outPins Pins to be used for powering each key row. - * @param handler Event handler called to report key presses and releases. - */ - KeyboardManager(PortName inPort, std::size_t numKeysPerRow, int inLowestBit, - const OutPinsSet &outPins, KeyPressEventHandler *handler); - - /** - * @brief Enables the polling of the keyboard state. - * @param pollingPeriod Frequency of the polling ticker (1kHz by default, min 20 microsec). - */ - void start(float pollingPeriod = 1e-3); - - /** - * @brief Disables the polling of the keyboard state. - */ - void stop(); - -private: - struct Impl; // opaque structure hiding implementation details - std::auto_ptr<Impl> pimpl; -}; - -} // kbd_mgr - -#endif // KEYBOARD_MANAGER_HPP_ +#include "kbd_mgr/KeyboardMonitor.h" +#include "kbd_mgr/KeyboardStateChangeMonitor.h" +#include "kbd_mgr/SingleKeyPressMonitor.h" +#include "kbd_mgr/LongKeyPressMonitor.h" +#include "kbd_mgr/KeyMapper.h"
--- a/kbd_mgr/KeyboardMonitor.h Sun Jan 23 23:15:36 2011 +0000 +++ b/kbd_mgr/KeyboardMonitor.h Thu Feb 03 22:01:57 2011 +0000 @@ -1,58 +1,57 @@ -#ifndef KEYBOARD_MONITOR_H_ -#define KEYBOARD_MONITOR_H_ - -#include "kbd_mgr/KeyboardState.h" -#include "kbd_mgr/KeyboardStateHandler.h" - -#include "mbed.h" -#include <vector> - -namespace kbd_mgr { - -/** - * @brief A class that polls the state of a switch-matrix keyboard. - * For efficiency reasons, this class uses contiguous bits in a GPIO ports for reading the state of the keys in a row. - * Key rows are activated one by one using a set of digital outputs. - * When a full keyboard scan has been done, it is provided to the registered handler. - */ -class KeyboardMonitor { -public: - typedef std::vector<PinName> OutPinsSet; - - /** - * @param inPort Port to be used for reading the key state. - * @param numKeysPerRow Number of keys in a row (N) - * @param inLowestBit Index of the lowest bit of inPort (using inLowestBit to inLowestBit+N). - * @param outPins Pins to be used for powering each key row. - * @param handler Event handler called to report keyboard state after each complete scan. - */ - KeyboardMonitor(PortName inPort, std::size_t numKeysPerRow, std::size_t inLowestBit, - const OutPinsSet &outPins, KeyboardStateHandler *handler); - - /** - * @brief Enables the polling of the keyboard state. - * @param pollingPeriod Frequency of the polling ticker (1kHz by default, min 20 microsec). - */ - void start(float pollingPeriod = 0.001); - - /** - * @brief Disables the polling of the keyboard state. - */ - void stop(); - -private: - void timerHandler(); - - PortIn in; - int inBitShift; - OutPinsSet outPins; - KeyboardStateHandler *handler; - - Ticker ticker; - std::size_t scanRow; /*!< next key row to be scanned */ - KeyboardState currentState; /*!< currently being built keyboard state */ -}; - -} // kbd_mgr - -#endif // KEYBOARD_MONITOR_H_ +#ifndef KEYBOARD_MONITOR_H_ +#define KEYBOARD_MONITOR_H_ + +#include "kbd_mgr/KeyboardStateEventServer.h" +#include "kbd_mgr/KeyboardState.h" + +#include "mbed.h" +#include <vector> + +namespace kbd_mgr { + +/** + * @brief A class that polls the state of a switch-matrix keyboard. + * For efficiency reasons, this class uses contiguous bits in a GPIO ports for reading the state of the keys in a row. + * Key rows are activated one by one using a set of digital outputs. + * When a full keyboard scan has been done, it is provided to the registered handler. + */ +class KeyboardMonitor : public KeyboardStateEventServer { +public: + typedef std::vector<PinName> OutPinsSet; + + /** + * @param inPort Port to be used for reading the key state. + * @param numKeysPerRow Number of keys in a row (N) + * @param inLowestBit Index of the lowest bit of inPort (using inLowestBit to inLowestBit+N). + * @param outPins Pins to be used for powering each key row. + */ + KeyboardMonitor(PortName inPort, std::size_t numKeysPerRow, std::size_t inLowestBit, + const OutPinsSet &outPins); + + ~KeyboardMonitor(); + + /** + * @brief Starts the polling of the keyboard state. + */ + void start(float pollingPeriod = 0.001); + + /** + * @brief Disables the polling of the keyboard state. + */ + void stop(); + +private: + void timerHandler(); + + PortIn in; + int inBitShift; + OutPinsSet outPins; + + Ticker ticker; + std::size_t scanRow; /*!< next key row to be scanned */ + KeyboardState currentState; /*!< currently being built keyboard state */ +}; + +} // kbd_mgr + +#endif // KEYBOARD_MONITOR_H_
--- a/kbd_mgr/KeyboardState.h Sun Jan 23 23:15:36 2011 +0000 +++ b/kbd_mgr/KeyboardState.h Thu Feb 03 22:01:57 2011 +0000 @@ -1,94 +1,94 @@ -#ifndef KEYBOARD_STATE_H_ -#define KEYBOARD_STATE_H_ - -#include <vector> -#include <iostream> - -namespace kbd_mgr { - -/** - * @brief A class to hold the state of a keyboard. - * A keyboard is handled as a set of key rows. Each row can have as many keys as there are bits in integers. - * The class maintains an array of integers to handle the number of rows. - * If possible, multiple rows are combined in a single integer to reduce memory footprint. - */ -class KeyboardState { -public: - /** - * @brief Constructor for a 0x0 keyboard state. - */ - KeyboardState(); - - /** - * @brief Constructor for a NxM keyboard state. - * @param numRows Number of key rows (unlimited) - * @param numKeysPerRow Number of keys per row (limited to the number of bits in an integer). - */ - KeyboardState(std::size_t numRows, std::size_t numKeysPerRow); - - std::size_t getNumRows() const { return this->numRows; } - std::size_t getNumKeysPerRow() const { return this->numKeysPerRow; } - std::size_t getNumKeys() const { return this->numRows * this->numKeysPerRow; } - - void clear(); - void setRowState(std::size_t row, int rowState); - int getRowState(std::size_t row) const; - bool getKeyState(std::size_t key) const; - - /** - * @brief Executes a XOR between two states. - * @return a state that represents the keys that changed of state. - */ - KeyboardState operator^(const KeyboardState &other) const; - - /** - * @brief Executes an AND between two states. - */ - KeyboardState operator&(const KeyboardState &mask) const; - - bool operator==(const KeyboardState &other) const; - bool operator!=(const KeyboardState &other) const { return !(*this == other); } - - /** - * @brief Checks if a keyboard state is full of 0. - */ - bool empty() const; - - enum KeyPressType { - Idle, SingleKeyPress, MultiKeyPress - }; - - /** - * @brief Determines the kind of key press present in the state. - * The keyboard state can represent an idle keyboard, a single key pressed - * or a key combination. This method determines which type of state this is. - * If a single key is represented, the key index can be retrieved. - * @param key An integer where the single key pressed should be stored. - */ - KeyPressType getKeyPressType(int *key = NULL) const; - KeyPressType getKeyPressType(int &key) const { return getKeyPressType(&key); } - - void streamTo(std::ostream &out) const; - -private: - int getRowInfo(std::size_t row, std::size_t &wordIndex, std::size_t &rowShift, int &rowMask) const; - - std::size_t numRows; - std::size_t numKeysPerRow; - int rowMask; - std::size_t numRowsPerWord; - std::size_t numKeysPerWord; - std::size_t numWords; - - typedef std::vector<int> Data; - Data data; -}; - -inline std::ostream & operator<<(std::ostream &out, const KeyboardState &s) { - s.streamTo(out); - return out; -} - -} // kbd_mgr - -#endif // KEYBOARD_STATE_H_ +#ifndef KEYBOARD_STATE_H_ +#define KEYBOARD_STATE_H_ + +#include <vector> +#include <iostream> + +namespace kbd_mgr { + +/** + * @brief A class to hold the state of a keyboard. + * A keyboard is handled as a set of key rows. Each row can have as many keys as there are bits in integers. + * The class maintains an array of integers to handle the number of rows. + * If possible, multiple rows are combined in a single integer to reduce memory footprint. + */ +class KeyboardState { +public: + /** + * @brief Constructor for a 0x0 keyboard state. + */ + KeyboardState(); + + /** + * @brief Constructor for a NxM keyboard state. + * @param numRows Number of key rows (unlimited) + * @param numKeysPerRow Number of keys per row (limited to the number of bits in an integer). + */ + KeyboardState(std::size_t numRows, std::size_t numKeysPerRow); + + std::size_t getNumRows() const { return this->numRows; } + std::size_t getNumKeysPerRow() const { return this->numKeysPerRow; } + std::size_t getNumKeys() const { return this->numRows * this->numKeysPerRow; } + + void clear(); + void setRowState(std::size_t row, int rowState); + int getRowState(std::size_t row) const; + bool getKeyState(std::size_t key) const; + + /** + * @brief Executes a XOR between two states. + * @return a state that represents the keys that changed of state. + */ + KeyboardState operator^(const KeyboardState &other) const; + + /** + * @brief Executes an AND between two states. + */ + KeyboardState operator&(const KeyboardState &mask) const; + + bool operator==(const KeyboardState &other) const; + bool operator!=(const KeyboardState &other) const { return !(*this == other); } + + /** + * @brief Checks if a keyboard state is full of 0. + */ + bool empty() const; + + enum KeyPressType { + Idle, SingleKeyPress, MultiKeyPress + }; + + /** + * @brief Determines the kind of key press present in the state. + * The keyboard state can represent an idle keyboard, a single key pressed + * or a key combination. This method determines which type of state this is. + * If a single key is represented, the key index can be retrieved. + * @param key An integer where the single key pressed should be stored. + */ + KeyPressType getKeyPressType(int *key = NULL) const; + KeyPressType getKeyPressType(int &key) const { return getKeyPressType(&key); } + + void streamTo(std::ostream &out) const; + +private: + int getRowInfo(std::size_t row, std::size_t &wordIndex, std::size_t &rowShift, int &rowMask) const; + + std::size_t numRows; + std::size_t numKeysPerRow; + int rowMask; + std::size_t numRowsPerWord; + std::size_t numKeysPerWord; + std::size_t numWords; + + typedef std::vector<int> Data; + Data data; +}; + +inline std::ostream & operator<<(std::ostream &out, const KeyboardState &s) { + s.streamTo(out); + return out; +} + +} // kbd_mgr + +#endif // KEYBOARD_STATE_H_
--- a/kbd_mgr/KeyboardStateChangeMonitor.h Sun Jan 23 23:15:36 2011 +0000 +++ b/kbd_mgr/KeyboardStateChangeMonitor.h Thu Feb 03 22:01:57 2011 +0000 @@ -1,30 +1,22 @@ -#ifndef KEYBOARD_STATE_CHANGE_MONITOR_H_ -#define KEYBOARD_STATE_CHANGE_MONITOR_H_ - -#include "kbd_mgr/KeyboardState.h" -#include "kbd_mgr/KeyboardStateHandler.h" - -namespace kbd_mgr { - -/** - * @brief Interface used by the KeyboardStateChangeMonitor to report state changes. - */ -class KeyboardStateChangeHandler : public KeyboardStateHandler { }; - -/** - * @brief A keyboard state handler that reports only state changes. - */ -class KeyboardStateChangeMonitor : public KeyboardStateHandler { -public: - KeyboardStateChangeMonitor(KeyboardStateChangeHandler *handler) : handler(handler), lastState() { } - - virtual void operator()(const KeyboardState &newState); - -private: - KeyboardStateChangeHandler *handler; - KeyboardState lastState; -}; - -} // kbd_mgr - -#endif // KEYBOARD_STATE_CHANGE_MONITOR_H_ +#ifndef KEYBOARD_STATE_CHANGE_MONITOR_H_ +#define KEYBOARD_STATE_CHANGE_MONITOR_H_ + +#include "kbd_mgr/KeyboardStateEventServer.h" +#include "kbd_mgr/KeyboardState.h" + +namespace kbd_mgr { + +/** + * @brief A keyboard state handler that reports only state changes. + */ +class KeyboardStateChangeMonitor : public KeyboardStateEventServer, public KeyboardStateHandler { +public: + virtual void handleState(const KeyboardState &newState); + +private: + KeyboardState lastState; +}; + +} // kbd_mgr + +#endif // KEYBOARD_STATE_CHANGE_MONITOR_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kbd_mgr/KeyboardStateEventServer.h Thu Feb 03 22:01:57 2011 +0000 @@ -0,0 +1,43 @@ +#ifndef KEYBOARD_STATE_EVENT_SERVER_H_ +#define KEYBOARD_STATE_EVENT_SERVER_H_ + +#include "kbd_mgr/KeyboardEventServer.h" +#include "kbd_mgr/KeyboardStateHandler.h" + +namespace kbd_mgr { + +/** + * @brief A keyboard state handler that reports only state changes. + */ +class KeyboardStateEventServer : public KeyboardEventServer<KeyboardStateHandler> { +public: + /** + * @brief Attaches the monitor to a function. + * @param fn Event handler called to report keyboard state change. + */ + void attach(FunctionKeyboardStateHandler::HandlerFunction fn) { + setHandler(new FunctionKeyboardStateHandler(fn)); + } + + /** + * @brief Attaches the monitor to a method of an object. + * @param obj Event handler object + * @param fn Event handler method called to report keyboard state after each complete scan. + */ + template <class T> + void attach(T *obj, typename MemberKeyboardStateHandler<T>::MemberFunction fn) { + setHandler(new MemberKeyboardStateHandler<T>(obj, fn)); + } + + using KeyboardEventServer<KeyboardStateHandler>::attach; + + void invokeHandler(const KeyboardState &state) { + if (this->hasHandler()) { + this->handler()->handleState(state); + } + } +}; + +} // kbd_mgr + +#endif // KEYBOARD_STATE_EVENT_SERVER_H_
--- a/kbd_mgr/KeyboardStateHandler.h Sun Jan 23 23:15:36 2011 +0000 +++ b/kbd_mgr/KeyboardStateHandler.h Thu Feb 03 22:01:57 2011 +0000 @@ -1,19 +1,53 @@ -#ifndef KEYBOARD_STATE_HANDLER_H_ -#define KEYBOARD_STATE_HANDLER_H_ - -#include "kbd_mgr/KeyboardState.h" - -namespace kbd_mgr { - -/** - * @brief Interface used to report a keyboard state. - */ -class KeyboardStateHandler { -public: - virtual void operator()(const KeyboardState &newState) = 0; - virtual ~KeyboardStateHandler() { } -}; - -} // kbd_mgr - -#endif // KEYBOARD_STATE_HANDLER_H_ +#ifndef KEYBOARD_STATE_HANDLER_H_ +#define KEYBOARD_STATE_HANDLER_H_ + +#include "kbd_mgr/KeyboardState.h" + +namespace kbd_mgr { + +/** + * @brief Interface used to report a keyboard state. + */ +class KeyboardStateHandler { +public: + virtual void handleState(const KeyboardState &newState) = 0; + virtual ~KeyboardStateHandler() { } +}; + +template <class T> +class MemberKeyboardStateHandler : public KeyboardStateHandler { +public: + typedef void (T::*MemberFunction)(const KeyboardState &); + + MemberKeyboardStateHandler(T *obj, MemberFunction fn) : + object(obj), func(fn) + { } + + virtual void handleState(const KeyboardState &newState) { + (object->*func)(newState); + } + +private: + T *object; + MemberFunction func; +}; + +class FunctionKeyboardStateHandler : public KeyboardStateHandler { +public: + typedef void (*HandlerFunction)(const KeyboardState &); + + FunctionKeyboardStateHandler(HandlerFunction fn) : + func(fn) + { } + + virtual void handleState(const KeyboardState &newState) { + func(newState); + } + +private: + HandlerFunction func; +}; + +} // kbd_mgr + +#endif // KEYBOARD_STATE_HANDLER_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kbd_mgr/LongKeyPressMonitor.h Thu Feb 03 22:01:57 2011 +0000 @@ -0,0 +1,115 @@ +#ifndef LONG_KEY_PRESS_MONITOR_H_ +#define LONG_KEY_PRESS_MONITOR_H_ + +#include <kbd_mgr/KeyPressEventServer.h> +#include <set> + +#include "mbed.h" + +namespace kbd_mgr { + +/** + * @brief A key press event handler that detects long key presses and report them as specified. + * This class offers two specific reactions for long key presses. Either a specific long key press is reported + * or the key press event is auto repeated. The timing for both kind of reactions can be specified independently. + * The monitor reacts on key code, not on mapped key char. If a mapped key char is present in the event, it is retained + * in the generated key press events. + */ +class LongKeyPressMonitor : public KeyPressEventServer, public KeyPressEventHandler { +public: + LongKeyPressMonitor() : + repeatKeys_(), repeatInitTime_(0), repeatDelay_(0), longPressKeys_(), longPressTime_(0), + state(Idle), keyDownCount(0), timer() + { } + + class AutoRepeatSetupProxy { + public: + AutoRepeatSetupProxy(LongKeyPressMonitor *monitor) : monitor_(monitor) { } + AutoRepeatSetupProxy& operator()(int key) { this->monitor_->addAutoRepeatKey(key, key); return *this; } + AutoRepeatSetupProxy& operator()(int firstKey, int lastKey) { this->monitor_->addAutoRepeatKey(firstKey, lastKey); return *this; } + + private: + LongKeyPressMonitor *monitor_; + }; + + friend class AutoRepeatSetupProxy; + + /** + * @brief Sets up auto-repeat keys. + * This method takes the timing parameters. It returns a special class that allows specifying the keys + * between brackets. Eg: + * - monitor.autoRepeat(0.3, 0.1)(1)(2)(4,8) + * Sets up auto repeat after 300ms, every 100ms for keys 1, 2 and 4 to 8. + */ + AutoRepeatSetupProxy autoRepeat(float initTime, float delay); + + + class LongPressSetupProxy { + public: + LongPressSetupProxy(LongKeyPressMonitor *monitor) : monitor_(monitor) { } + LongPressSetupProxy& operator()(int key) { this->monitor_->addLongPressKey(key, key); return *this; } + LongPressSetupProxy& operator()(int firstKey, int lastKey) { this->monitor_->addLongPressKey(firstKey, lastKey); return *this; } + + private: + LongKeyPressMonitor *monitor_; + }; + + friend class LongPressSetupProxy; + + /** + * @brief Sets up long key press keys. + * This method takes the timing parameters. It returns a special class that allows specifying the keys + * between brackets. Eg: + * - monitor.longKeyPress(0.5)(3)(12,14) + * Sets up report of long key press after 500ms for keys 3 and 12 to 14. + */ + LongPressSetupProxy longKeyPress(float longPressTime); + + /** + * @brief KeyPressEventHandler interface + */ + virtual void handleKeyPress(const KeyEvent &keypress); + +private: + void addAutoRepeatKey(int firstKey, int lastKey); + bool isAutoRepeatKey(int key) const { return this->repeatKeys_.find(key) != this->repeatKeys_.end(); } + void addLongPressKey(int firstKey, int lastKey); + bool isLongPressKey(int key) const { return this->longPressKeys_.find(key) != this->longPressKeys_.end(); } + + void handleKeyDown(const KeyEvent &keypress); + void handleFirstKeyDown(const KeyEvent &keypress); + void handleOtherKeyDown(const KeyEvent &keypress); + void handleKeyUp(const KeyEvent &keypress); + void handleLastKeyUp(const KeyEvent &keypress); + + void handleTimer(); + void handleRepeatTimer(); + void handleLongPressTimer(); + + typedef std::set<int> KeySet; + + KeySet repeatKeys_; + float repeatInitTime_; + float repeatDelay_; + + KeySet longPressKeys_; + float longPressTime_; + + enum State { + Idle, + RepeatInitWait, + Repeating, + LongPressWait, + LongPressReported, + Invalid + }; + + State state; + KeyEvent keypress; + int keyDownCount; + Timeout timer; +}; + +} // kbd_mgr + +#endif // LONG_KEY_PRESS_MONITOR_H_
--- a/kbd_mgr/SingleKeyPressMonitor.h Sun Jan 23 23:15:36 2011 +0000 +++ b/kbd_mgr/SingleKeyPressMonitor.h Thu Feb 03 22:01:57 2011 +0000 @@ -1,29 +1,28 @@ -#ifndef SINGLE_KEY_PRESS_MONITOR_H_ -#define SINGLE_KEY_PRESS_MONITOR_H_ - -#include "kbd_mgr/KeyboardStateChangeMonitor.h" -#include "kbd_mgr/KeyPressEventHandler.h" - -namespace kbd_mgr { - -/** - * @brief A keyboard state change handler that reports on single keypresses. - * It voluntarily ignores key combinations (only the first key pressed in a combo is reported). - */ -class SingleKeyPressMonitor : public KeyboardStateChangeHandler { -public: - SingleKeyPressMonitor(KeyPressEventHandler *handler) : - handler(handler), lastReportedState(), lastReportedKey(KeyPressEventHandler::NoKey) - { } - - virtual void operator()(const KeyboardState &newState); - -private: - KeyPressEventHandler *handler; - KeyboardState lastReportedState; - int lastReportedKey; -}; - -} // kbd_mgr - -#endif // SINGLE_KEY_PRESS_MONITOR_H_ +#ifndef SINGLE_KEY_PRESS_MONITOR_H_ +#define SINGLE_KEY_PRESS_MONITOR_H_ + +#include "kbd_mgr/KeyPressEventServer.h" +#include "kbd_mgr/KeyboardStateHandler.h" + +namespace kbd_mgr { + +/** + * @brief A keyboard state change handler that reports on single keypresses. + * It voluntarily ignores key combinations (only the first key pressed in a combo is reported). + */ +class SingleKeyPressMonitor : public KeyPressEventServer, public KeyboardStateHandler { +public: + SingleKeyPressMonitor() : + lastReportedState(), lastReportedKey(KeyEvent::NoKey) + { } + + virtual void handleState(const KeyboardState &newState); + +private: + KeyboardState lastReportedState; + int lastReportedKey; +}; + +} // kbd_mgr + +#endif // SINGLE_KEY_PRESS_MONITOR_H_