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

Dependents:   KeyboardTest

Revision:
2:eb4cc53ff33d
Child:
3:1310c57aca77
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KeyboardState.cpp	Sun Jan 23 23:15:36 2011 +0000
@@ -0,0 +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);
+}
+
+} // kbd_mgr
\ No newline at end of file