KeyboardManager: a class to manage the polling of a switch-matrix keyboard

Dependents:   KeyboardTest

Files at this revision

API Documentation at this revision

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

KeyMapper.cpp Show annotated file Show diff for this revision Revisions of this file
KeyboardManager.cpp Show diff for this revision Revisions of this file
KeyboardMonitor.cpp Show annotated file Show diff for this revision Revisions of this file
KeyboardState.cpp Show annotated file Show diff for this revision Revisions of this file
KeyboardStateChangeMonitor.cpp Show annotated file Show diff for this revision Revisions of this file
LongKeyPressMonitor.cpp Show annotated file Show diff for this revision Revisions of this file
SingleKeyPressMonitor.cpp Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/KeyMapper.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/KeyPressEventHandler.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/KeyPressEventServer.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/KeyboardEventServer.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/KeyboardManager.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/KeyboardMonitor.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/KeyboardState.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/KeyboardStateChangeMonitor.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/KeyboardStateEventServer.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/KeyboardStateHandler.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/LongKeyPressMonitor.h Show annotated file Show diff for this revision Revisions of this file
kbd_mgr/SingleKeyPressMonitor.h Show annotated file Show diff for this revision Revisions of this file
diff -r eb4cc53ff33d -r 1310c57aca77 KeyMapper.cpp
--- /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
diff -r eb4cc53ff33d -r 1310c57aca77 KeyboardManager.cpp
--- 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
diff -r eb4cc53ff33d -r 1310c57aca77 KeyboardMonitor.cpp
--- 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
diff -r eb4cc53ff33d -r 1310c57aca77 KeyboardState.cpp
--- 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
diff -r eb4cc53ff33d -r 1310c57aca77 KeyboardStateChangeMonitor.cpp
--- 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
diff -r eb4cc53ff33d -r 1310c57aca77 LongKeyPressMonitor.cpp
--- /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
diff -r eb4cc53ff33d -r 1310c57aca77 SingleKeyPressMonitor.cpp
--- 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
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/KeyMapper.h
--- /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_
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/KeyPressEventHandler.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_
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/KeyPressEventServer.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_
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/KeyboardEventServer.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_
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/KeyboardManager.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"
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/KeyboardMonitor.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_
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/KeyboardState.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_
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/KeyboardStateChangeMonitor.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_
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/KeyboardStateEventServer.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_
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/KeyboardStateHandler.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_
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/LongKeyPressMonitor.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_
diff -r eb4cc53ff33d -r 1310c57aca77 kbd_mgr/SingleKeyPressMonitor.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_