A DTMF sequence editor and player for HAM radio equipment command & control.

Dependencies:   mbed ExtTextLCD

KeyboardManager/KeyboardState.cpp

Committer:
osmeest
Date:
2011-03-07
Revision:
0:1324e7d9d471

File content as of revision 0:1324e7d9d471:

#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