Logo Search packages:      
Sourcecode: synaptiks version File versions  Download package

keyboardmonitor.cpp

Go to the documentation of this file.
/*
 * synaptiks -- a touchpad control tool
 *
 *
 * Copyright (C) 2009, 2010 Sebastian Wiesner <basti.wiesner@gmx.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */


#include "keyboardmonitor.h"
#include "qxlib.h"
#include <QtCore/QVector>
#include <QtCore/QTimer>
#include <QtCore/QTime>
#include <QtCore/QSharedPointer>
#include <KDebug>

/**
 * @file
 *
 * Implementation of KeyboardMonitor.  Much of this code is shamelessly
 * taken from syndaemon.c written by Peter Osterlund (petero2@telia.com).
 * syndaemon.c is part of xf86-input-synaptics, which in turn is distributed
 * as part of Xorg.
 *
 * @see http://cgit.freedesktop.org/xorg/driver/xf86-input-synaptics/tree/tools/syndaemon.c
 */

static const int KEYMAP_SIZE = 32;
static const int DEFAULT_IDLETIME = 2000; /* 2 s */
static const int DEFAULT_POLLDELAY = 200; /* 0.2 s */

/**
 * Clears the given @p bit in the given @p vector, which contains a sequence
 * of bytes.
 *
 * @param vector a sequence of bytes
 * @param bit the bit to clear
 */
00061 static void clearBit(QVector<unsigned char> &vector, int bit) {
    int byte_num = bit / 8;
    int bit_num = bit % 8;
    vector[byte_num] &= ~(1 << bit_num);
}


namespace synaptiks {

00070     class KeyboardMonitorPrivate {
        Q_DECLARE_PUBLIC(KeyboardMonitor)

    public:
        KeyboardMonitorPrivate(KeyboardMonitor *qq):
            q_ptr(qq), keyboardCheckTimer(new QTimer(qq)),
            oldState(KEYMAP_SIZE), keyboardMask(KEYMAP_SIZE),
            keyboardActive(false), idleTime(DEFAULT_IDLETIME) {
            Q_Q(KeyboardMonitor);
            q->connect(this->keyboardCheckTimer, SIGNAL(timeout()),
                       SLOT(_k_checkKeyboardActivity()));
            this->keyboardCheckTimer->setInterval(DEFAULT_POLLDELAY);
            this->setIgnoreKeys(KeyboardMonitor::IgnoreNoKeys);
        };

        void setupKeyboardMask();
        void _k_checkKeyboardActivity();
        bool isKeyboardActive();
        void setIgnoreKeys(KeyboardMonitor::IgnoreKeys keys) {
            this->keysToIgnore = keys;
            this->setupKeyboardMask();
        };

        KeyboardMonitor * const q_ptr;
        /** timer to periodically poll keyboard state */
00095         QTimer *keyboardCheckTimer;
        /** keyboard state from the last check */
00097         QVector<unsigned char> oldState;
        /** mask out certain keys */
00099         QVector<unsigned char> keyboardMask;
        /** time of the last keyboard activity */
00101         QTime activity;
        /** is the keyboard currently active */
00103         bool keyboardActive;
        /** which keys to ignore */
00105         KeyboardMonitor::IgnoreKeys keysToIgnore;
        /** idle time */
00107         int idleTime;
    };
}

using namespace synaptiks;


void KeyboardMonitorPrivate::setupKeyboardMask() {
    // don't mask any keys by default
    this->keyboardMask.fill(0xff);
    if (this->keysToIgnore >= KeyboardMonitor::IgnoreModifierKeys) {
        QSharedPointer<XModifierKeymap> modifiers =
            QX11::GetModifierMapping();
        for (int i=0; i < 8*modifiers->max_keypermod; i++) {
            // zero the key bit for all modifier keys
            KeyCode keycode = modifiers->modifiermap[i];
            if (keycode != 0) {
                clearBit(this->keyboardMask, keycode);
            }
        }
    }
}

void KeyboardMonitorPrivate::_k_checkKeyboardActivity() {
    Q_Q(KeyboardMonitor);
    if (this->isKeyboardActive()) {
        this->activity.start();
        if (!this->keyboardActive) {
            kDebug() << "keyboard becomes active";
            this->keyboardActive = true;
            emit q->typingStarted();
        }
    }
    if (this->activity.elapsed() > this->idleTime) {
        if (this->keyboardActive) {
            kDebug() << "keyboard becomes inactive";
            this->keyboardActive = false;
            emit q->typingStopped();
        }
    }
}

bool KeyboardMonitorPrivate::isKeyboardActive() {
    QVector<unsigned char> keyState(this->oldState.size());
    bool isActive = false;

    QX11::QueryKeymap(reinterpret_cast<char *>(keyState.data()));
    for (int i=0; i < keyState.size(); i++) {
        if (keyState.at(i) & ~(this->oldState.at(i)) &
            this->keyboardMask.at(i)) {
            isActive = true;
            break;
        }
    }

    if (this->keysToIgnore == KeyboardMonitor::IgnoreModifierCombos) {
        for (int i=0; i < keyState.size(); i++) {
            if (keyState.at(i) & ~ this->keyboardMask.at(i)) {
                isActive = false;
                break;
            }
        }
    }

    this->oldState = keyState;
    return isActive;
}

00175 KeyboardMonitor::KeyboardMonitor(QObject *parent):
    QObject(parent), d_ptr(new KeyboardMonitorPrivate(this)) {
}

00179 KeyboardMonitor::~KeyboardMonitor() {
    this->stop();
    delete this->d_ptr;
}

00184 void KeyboardMonitor::start() {
    Q_D(KeyboardMonitor);
    kDebug() << "starting monitor";
    d->keyboardCheckTimer->start();
}

00190 void KeyboardMonitor::stop() {
    Q_D(KeyboardMonitor);
    kDebug() << "stopping monitor";
    d->keyboardCheckTimer->stop();
}

KeyboardMonitor::IgnoreKeys KeyboardMonitor::ignoreKeys() const {
    Q_D(const KeyboardMonitor);
    return d->keysToIgnore;
}

00201 void KeyboardMonitor::setIgnoreKeys(IgnoreKeys keys) {
    Q_D(KeyboardMonitor);
    d->setIgnoreKeys(keys);
}

int KeyboardMonitor::idleTime() const {
    Q_D(const KeyboardMonitor);
    return d->idleTime;
}

00211 void KeyboardMonitor::setIdleTime(int msec) {
    Q_D(KeyboardMonitor);
    d->idleTime = msec;
}

int KeyboardMonitor::pollDelay() const {
    Q_D(const KeyboardMonitor);
    return d->keyboardCheckTimer->interval();
}

00221 void KeyboardMonitor::setPollDelay(int msec) {
    Q_D(KeyboardMonitor);
    d->keyboardCheckTimer->setInterval(msec);
}

00226 bool KeyboardMonitor::isKeyboardActive() const {
    Q_D(const KeyboardMonitor);
    return d->keyboardActive;
}

#include "moc_keyboardmonitor.cpp"

Generated by  Doxygen 1.6.0   Back to index