Subversion Repositories tpanel

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2023 by Andreas Theofilu <andreas@theosys.at>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

#include <functional>

#include "tsystembutton.h"
#include "tpagemanager.h"
#include "tbutton.h"
#include "terror.h"
#include "tresources.h"

#define MAX_BANK        3

#define DISPLAY_LINE    0

// Key definitions
#define KB_DISPLAY_INPUT_S  4
#define KB_DISPLAY_INPUT_M  5
#define KB_DISPLAY_INFO     6

#define KB_KEYBOARD_KEY     201

#define KB_SPACE            202
#define KB_ENTER            203
#define KB_BACKSPACE        208
#define KB_CLEAR            210
#define KB_CANCEL           211
#define KB_SUBMIT           212
#define KB_CAPS_LOCK        221
#define KB_BANK3            222
#define KB_SHIFT            226

using std::string;
using std::vector;
using std::bind;
using namespace Button;

TSystemButton::SYS_BUTTONS _sysButtons[] = {
    {   0, 4, TSystemButton::KEY_INPUT_SINGLE },   // A single line textarea getting typed keys for keypad
    {   0, 5, TSystemButton::KEY_INPUT_MULTI },    // A multiline textarea getting typed keys for keyboard
    {   0, 6, TSystemButton::KEY_BUTTON },         // A button showing the prompt text comming from the call to the keyboard
    { 201, 0, TSystemButton::KEY_KEY },            // A keyboard key
    { 202, 0, TSystemButton::KEY_BUTTON },         // Space button
    { 203, 0, TSystemButton::KEY_BUTTON },         // Enter/Return button
    { 208, 0, TSystemButton::KEY_BUTTON },         // Backspace button
    { 210, 0, TSystemButton::KEY_BUTTON },         // Clear button
    { 211, 0, TSystemButton::KEY_BUTTON },         // The keyboard cancel button
    { 212, 0, TSystemButton::KEY_BUTTON },         // The keyboard submit button
    { 221, 0, TSystemButton::KEY_BUTTON },         // bank 2; Caps lock button
    { 222, 0, TSystemButton::KEY_BUTTON },         // Bank 3; lock button
    { 226, 0, TSystemButton::KEY_BUTTON },         // Bank 2; shift button
    // Virtual keyboard keys
    { 501, 0, TSystemButton::KEY_BUTTON },         // ESC
    { 502, 0, TSystemButton::KEY_BUTTON },         // !\n1
    { 503, 0, TSystemButton::KEY_BUTTON },         // @\n2
    { 504, 0, TSystemButton::KEY_BUTTON },         // #\n3
    { 505, 0, TSystemButton::KEY_BUTTON },         // $\n4
    { 506, 0, TSystemButton::KEY_BUTTON },         // %\n5
    { 507, 0, TSystemButton::KEY_BUTTON },         // ^\n6
    { 508, 0, TSystemButton::KEY_BUTTON },         // &\n7
    { 509, 0, TSystemButton::KEY_BUTTON },         // *\n8
    { 510, 0, TSystemButton::KEY_BUTTON },         // (\n9
    { 511, 0, TSystemButton::KEY_BUTTON },         // )\n0
    { 512, 0, TSystemButton::KEY_BUTTON },         // _\n-
    { 513, 0, TSystemButton::KEY_BUTTON },         // +\n=
    { 514, 0, TSystemButton::KEY_BUTTON },         // Backspace
    { 515, 0, TSystemButton::KEY_BUTTON },         // TAB
    { 516, 0, TSystemButton::KEY_BUTTON },         // Q
    { 517, 0, TSystemButton::KEY_BUTTON },         // W
    { 518, 0, TSystemButton::KEY_BUTTON },         // E
    { 519, 0, TSystemButton::KEY_BUTTON },         // R
    { 520, 0, TSystemButton::KEY_BUTTON },         // T
    { 521, 0, TSystemButton::KEY_BUTTON },         // Y
    { 522, 0, TSystemButton::KEY_BUTTON },         // U
    { 523, 0, TSystemButton::KEY_BUTTON },         // I
    { 524, 0, TSystemButton::KEY_BUTTON },         // O
    { 525, 0, TSystemButton::KEY_BUTTON },         // P
    { 526, 0, TSystemButton::KEY_BUTTON },         // {\n[
    { 527, 0, TSystemButton::KEY_BUTTON },         // }\n]
    { 528, 0, TSystemButton::KEY_BUTTON },         // Enter
    { 529, 0, TSystemButton::KEY_BUTTON },         // Ctrl left
    { 530, 0, TSystemButton::KEY_BUTTON },         // A
    { 531, 0, TSystemButton::KEY_BUTTON },         // S
    { 532, 0, TSystemButton::KEY_BUTTON },         // D
    { 533, 0, TSystemButton::KEY_BUTTON },         // F
    { 534, 0, TSystemButton::KEY_BUTTON },         // G
    { 535, 0, TSystemButton::KEY_BUTTON },         // H
    { 536, 0, TSystemButton::KEY_BUTTON },         // J
    { 537, 0, TSystemButton::KEY_BUTTON },         // K
    { 538, 0, TSystemButton::KEY_BUTTON },         // L
    { 539, 0, TSystemButton::KEY_BUTTON },         // :\n;
    { 540, 0, TSystemButton::KEY_BUTTON },         // "\n'
    { 541, 0, TSystemButton::KEY_BUTTON },         // ~\n`
    { 542, 0, TSystemButton::KEY_BUTTON },         // Shift left
    { 543, 0, TSystemButton::KEY_BUTTON },         // |
    { 544, 0, TSystemButton::KEY_BUTTON },         // Z
    { 545, 0, TSystemButton::KEY_BUTTON },         // X
    { 546, 0, TSystemButton::KEY_BUTTON },         // C
    { 547, 0, TSystemButton::KEY_BUTTON },         // V
    { 548, 0, TSystemButton::KEY_BUTTON },         // B
    { 549, 0, TSystemButton::KEY_BUTTON },         // N
    { 550, 0, TSystemButton::KEY_BUTTON },         // M
    { 551, 0, TSystemButton::KEY_BUTTON },         // <\n,
    { 552, 0, TSystemButton::KEY_BUTTON },         // >\n.
    { 553, 0, TSystemButton::KEY_BUTTON },         // ?\n/
    { 554, 0, TSystemButton::KEY_BUTTON },         // Shift right
    { 556, 0, TSystemButton::KEY_BUTTON },         // Alt left
    { 557, 0, TSystemButton::KEY_BUTTON },         // Space
    { 558, 0, TSystemButton::KEY_BUTTON },         // Caps lock
    { 559, 0, TSystemButton::KEY_BUTTON },         // F1
    { 560, 0, TSystemButton::KEY_BUTTON },         // F2
    { 561, 0, TSystemButton::KEY_BUTTON },         // F3
    { 562, 0, TSystemButton::KEY_BUTTON },         // F4
    { 563, 0, TSystemButton::KEY_BUTTON },         // F5
    { 564, 0, TSystemButton::KEY_BUTTON },         // F6
    { 565, 0, TSystemButton::KEY_BUTTON },         // F7
    { 566, 0, TSystemButton::KEY_BUTTON },         // F8
    { 567, 0, TSystemButton::KEY_BUTTON },         // F9
    { 568, 0, TSystemButton::KEY_BUTTON },         // F10
    { 587, 0, TSystemButton::KEY_BUTTON },         // F11
    { 588, 0, TSystemButton::KEY_BUTTON },         // F12

    { 597, 0, TSystemButton::KEY_BUTTON },         // Ctrl right

    { 600, 0, TSystemButton::KEY_BUTTON },         // Alt right (AltGr)

    { 602, 0, TSystemButton::KEY_BUTTON },         // Home
    { 603, 0, TSystemButton::KEY_BUTTON },         // Arrow up
    { 604, 0, TSystemButton::KEY_BUTTON },         // PgUp
    { 605, 0, TSystemButton::KEY_BUTTON },         // Arrow left
    { 606, 0, TSystemButton::KEY_BUTTON },         // Arrow right
    { 607, 0, TSystemButton::KEY_BUTTON },         // End
    { 608, 0, TSystemButton::KEY_BUTTON },         // Arrow down
    { 609, 0, TSystemButton::KEY_BUTTON },         // PgDn
    { 610, 0, TSystemButton::KEY_BUTTON },         // Insert
    { 611, 0, TSystemButton::KEY_BUTTON },         // Delete
    {   0, 0, TSystemButton::KEY_UNDEFINED}        // End of table marker
};

TSystemButton::TSystemButton()
{
    DECL_TRACER("TSystemButton::TSystemButton()");
}

TSystemButton::~TSystemButton()
{
    DECL_TRACER("TSystemButton::~TSystemButton()");

    setBank(1);
    mButtons.clear();
}

void TSystemButton::addSysButton(TButton *bt)
{
    DECL_TRACER("TSystemButton::addButton(TButton *bt)");

    if (!bt)
    {
        MSG_WARNING("No valid button pointer!");
        return;
    }

    if (!(bt->getAddressPort() == 0 && bt->getAddressChannel() > 0) &&
        !(bt->getChannelPort() == 0 && bt->getChannelNumber() > 0) &&
        bt->getButtonType() != TEXT_INPUT)
    {
        MSG_DEBUG("No system keyboard button: channel number=" << bt->getChannelNumber() << ", channel port=" << bt->getChannelPort());
        return;
    }

    // First we look if the button is already there
    if (!mButtons.empty())
    {
        vector<TButton *>::iterator iter;
        int channel = bt->getChannelNumber();
        int addrChannel = bt->getAddressChannel();

        for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
        {
            TButton *button = *iter;

            if (channel == button->getChannelNumber() &&
                addrChannel == button->getAddressChannel() &&
                bt->getName() == button->getName())
            {
                MSG_WARNING("Don't add the keyboard button " << button->getName() << " again!");
                return;
            }
        }
    }

    // If the button is an input text field then we add it in any case.
    if (bt->getButtonType() == TEXT_INPUT)
    {
        mButtons.push_back(bt);
        return;
    }

    // Is the button a recognized system button
    int i = 0;

    while(_sysButtons[i].type != KEY_UNDEFINED)
    {
        if (_sysButtons[i].channel == bt->getChannelNumber() &&
            _sysButtons[i].port == bt->getAddressChannel())
        {
            if (!isKeyboard && bt->getChannelNumber() == KB_KEYBOARD_KEY)
            {
                char ch = bt->getText(STATE_1)[0];

                if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
                    isKeyboard = true;
            }

            bt->regCallButtonPress(bind(&TSystemButton::buttonPress, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
            mButtons.push_back(bt);
            MSG_DEBUG("Button " << bt->getName() << " was added to system keyboard buttons list.");
            return;
        }

        i++;
    }

    MSG_DEBUG("Button " << bt->getName() << " is not a supported system keyboard button!");
}

TButton *TSystemButton::getSysButton(int channel, int port)
{
    DECL_TRACER("TSystemButton::getButton(int channel, int port)");

    if (channel == 0 && port == 0)
        return nullptr;

    if (mButtons.empty())
        return nullptr;

    vector<TButton *>::iterator iter;

    for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
    {
        TButton *button = *iter;

        if (button->getChannelNumber() == channel && button->getAddressChannel() == port)
            return *iter;
    }

    return nullptr;
}

void TSystemButton::dropButton(Button::TButton* bt)
{
    DECL_TRACER("TSystemButton::dropButton(Button::TButton* bt)");

    if (mButtons.empty())
        return;

    vector<TButton *>::iterator iter;

    for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
    {
        TButton *button = *iter;

        if (button == bt)
        {
            mButtons.erase(iter);
            return;
        }
    }
}

void TSystemButton::setBank(int bank)
{
    DECL_TRACER("TSystemButton::setBank(int bank)");

    if (bank < BANK_1 || bank > BANK_3)
    {
        MSG_WARNING("Illegal bank " << bank << "! Ignoring it.");
        return;
    }

    if (mButtons.empty())
        return;

    mStateKeyActive = (bank - 1) * 2;
    vector<TButton *>::iterator iter;

    for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
    {
        TButton *button = *iter;

        if (button->getActiveInstance() == mStateKeyActive)
            continue;

        if (getSystemButtonType(button->getChannelNumber(), button->getAddressChannel()) == KEY_KEY && button->getNumberInstances() <= (MAX_BANK * 2))
            button->setActive(mStateKeyActive);
    }
}

TSystemButton::SYS_BUTTON_TYPE TSystemButton::getSystemButtonType(int channel, int port)
{
    DECL_TRACER("TSystemButton::getSystemButtonType(int channel, int port)");

    int i = 0;

    while(_sysButtons[i].type != KEY_UNDEFINED)
    {
        if (_sysButtons[i].channel == channel && _sysButtons[i].port == port)
            return _sysButtons[i].type;

        i++;
    }

    return KEY_UNDEFINED;
}

TButton *TSystemButton::getSystemInputLine()
{
    DECL_TRACER("TSystemButton::getSystemInputLine()");

    if (mButtons.empty())
        return nullptr;

    vector<TButton *> buffer;
    vector<TButton *>::iterator iter;
    // The first loop looks for a system input line. If there is one (or more)
    // The first one is taken. All other input lines are stored into a temporary
    // buffer.
    for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
    {
        TButton *button = *iter;
        int chan = button->getAddressChannel();

        if (button->getButtonType() == TEXT_INPUT)
        {
            if (chan == KB_DISPLAY_INPUT_S || chan == KB_DISPLAY_INPUT_M)
                return *iter;

            buffer.push_back(button);
        }
    }
    // The second loop is executed only if there was one or more normal input
    // lines.
    if (!buffer.empty())
    {
        for (iter = buffer.begin(); iter != buffer.end(); ++iter)
        {
            TButton *button = *iter;
            // If there is a line which has the focus, it is selected.
            if (button->isFocused())
                return *iter;
        }
        // We're here because there were no system input line nor one with
        // the focus. Because of this we take the first line in the buffer.
        return buffer[0];
    }

    return nullptr;
}

void TSystemButton::setDistinctFocus(ulong handle)
{
    DECL_TRACER("TSystemButton::setDistinctFocus(ulong handle)");

    if (mButtons.empty())
        return;

    std::thread thr = std::thread([=] {
        vector<TButton *>::iterator iter;

        for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
        {
            TButton *button = *iter;

            if (button->getButtonType() == TEXT_INPUT)
            {
                if (button->getHandle() == handle && !button->isFocused())
                    button->setTextFocus(true);
                else if (button->isFocused())
                    button->setTextFocus(false);
            }
        }
    });

    thr.detach();
}

void TSystemButton::setCursorPosition(ulong handle, int oldPos, int newPos)
{
    DECL_TRACER("TSystemButton::setCursorPosition(ulong handle, int pos)");

    vector<TButton *>::iterator iter;

    for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
    {
        TButton *button = *iter;

        if (button->getHandle() == handle)
        {
            button->setTextCursorPosition(oldPos, newPos);

            if (mLineHandle == handle || button->isFocused())
                mCursorPosition = newPos;

            return;
        }
    }
}

void TSystemButton::setInputFocus(ulong handle, bool in)
{
    DECL_TRACER("TSystemButton::setInputFocus(ulong handle, bool in)");

    if (mLineHandle == handle)
        return;

    vector<TButton *>::iterator iter;

    for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
    {
        TButton *button = *iter;

        if (button->getHandle() == handle && button->getButtonType() == TEXT_INPUT)
        {
            mLineHandle = handle;
            mCursorPosition = button->getTextCursorPosition();
            mInputText = button->getText();
            button->setTextFocus(in);
            MSG_DEBUG("Input text: " << mInputText << ", cursor position: " << mCursorPosition << ", handle: " << handleToString(handle));
        }
        else if (button->getButtonType() == TEXT_INPUT)
            button->setTextFocus(false);
    }
}

TButton *TSystemButton::getSystemKey(int channel, uint handle)
{
    DECL_TRACER("TSystemButton::getSystemKey(int channel)");

    uint intHandle = handle;

    vector<TButton *>::iterator iter;

    for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
    {
        TButton *button = *iter;

        if (handle == 0)
            intHandle = button->getHandle();

        if (button->getChannelNumber() == channel && button->getHandle() == intHandle)
        {
            MSG_DEBUG("Found system key " << button->getName());
            return *iter;
        }
    }

    return nullptr;
}

void TSystemButton::buttonPress(int channel, uint handle, bool pressed)
{
    DECL_TRACER("TSystemButton::buttonPress(int channel, const std::string& text, bool pressed);");

    if (mButtons.empty())
        return;

    SYS_BUTTON_TYPE type = getSystemButtonType(channel, 0);

    if (type == KEY_UNDEFINED)
        return;

    MSG_DEBUG("Found button of type " << typeToString(type));

    if (channel > 500)
    {
        handleDedicatedKeys(channel, pressed);
        return;
    }

    TButton *btShift = nullptr;
    TButton *btBank3 = nullptr;
    TButton *btCaps = nullptr;

    // Handle the switch keys
    if (pressed)
    {
        if (type == KEY_BUTTON)
        {
            if (channel == KB_SHIFT)
            {
                mShift = !mShift;

                if (mShift)
                {
                    mCapsLock = mBank3 = false;
                    mBank = BANK_2;
                }
                else
                    mBank = BANK_1;
            }
            else if (channel == KB_CAPS_LOCK)
            {
                mCapsLock = !mCapsLock;

                if (mCapsLock)
                {
                    mShift = mBank3 = false;
                    mBank = BANK_2;
                }
                else
                    mBank = BANK_1;
            }
            else if (channel == KB_BANK3)
            {
                mBank3 = !mBank3;

                if (mBank3)
                {
                    mBank = BANK_3;
                    mShift = mCapsLock = false;
                }
                else
                    mBank = BANK_1;
            }

            mStateKeyActive = (mBank - 1) * 2 + 1;
        }
        else if (type == KEY_KEY)
        {
            mBank = (mBank3 ? BANK_3 : (mShift || mCapsLock ? BANK_2 : BANK_1));
            mStateKeyActive = (mBank - 1) * 2 + 1;
        }

        btShift = getSystemKey(KB_SHIFT);
        btBank3 = getSystemKey(KB_BANK3);
        btCaps = getSystemKey(KB_CAPS_LOCK);
    }
    else
        mStateKeyActive = (mBank - 1) * 2;

    MSG_DEBUG("Button " << handleToString(handle) << ": shift is " << (mShift ? "TRUE" : "FALSE") << ", caps lock is " << (mCapsLock ? "TRUE" : "FALSE") << ", current bank: " << mBank << " (" << (mBank3 ? "TRUE" : "FALSE") << "), pressed is " << (pressed ? "TRUE" : "FALSE") << &quot;, instance is " << mStateKeyActive);
    // Handle all keys who must be switched as a group
    TButton *input = getSystemInputLine();
    MSG_DEBUG("Input line was " << (input ? "found" : "not found"));

    if (input && !input->isFocused())
        setDistinctFocus(input->getHandle());

    if (pressed)
    {
        if (btShift)
            btShift->setActive(mShift ? STATE_ON : STATE_OFF);

        if (btCaps)
            btCaps->setActive(mCapsLock ? STATE_ON : STATE_OFF);

        if (btBank3)
            btBank3->setActive(mBank3 ? STATE_ON : STATE_OFF);
    }

    uint hd = handle;

    if ((type == KEY_BUTTON && channel != KB_SHIFT && channel != KB_CAPS_LOCK && channel != KB_BANK3) ||
        (type == KEY_KEY && !pressed))
        hd = HANDLE_UNDEF;

    if (type == KEY_BUTTON && hd != HANDLE_UNDEF && !mShift && !mCapsLock && !mBank3)
        hd = HANDLE_UNDEF;

    if (pressed && (channel == KB_BACKSPACE || channel == KB_CANCEL ||
        channel == KB_CLEAR || channel == KB_ENTER || channel == KB_SPACE ||
        channel == KB_SUBMIT) && hd == HANDLE_UNDEF)
        hd = handle;

    setKeysToBank(mBank, hd);

    if (channel == KB_SHIFT || channel == KB_CAPS_LOCK || channel == KB_BANK3)
        return;

    TButton *button = nullptr;

    if (channel == KB_SHIFT)
        button = btShift;
    else if (channel == KB_CAPS_LOCK)
        button = btCaps;
    else if (channel == KB_BANK3)
        button = btBank3;
    else
        button = getSystemKey(channel, (type == KEY_KEY ? handle : 0));

    if (!button)
        return;

    if (pressed && type == KEY_KEY)
    {
        string letter = button->getText(mStateKeyActive);

        if ((size_t)mCursorPosition < mInputText.length())
        {
            string left, right;

            if (mCursorPosition > 0)
                left = mInputText.substr(0, mCursorPosition);

            right = mInputText.substr(mCursorPosition);
            mInputText = left + letter + right;
            mCursorPosition++;
        }
        else
        {
            mInputText.append(letter);
            mCursorPosition++;
        }

        if (input)
        {
            input->setText(mInputText, 0);
            input->setTextCursorPosition(0, mCursorPosition);
        }

        if (gPageManager)
            gPageManager->sendKeyStroke(letter[0]);

        MSG_DEBUG("Actual text: " << mInputText);
        mShift = mBank3 = false;
        mBank = (mCapsLock ? BANK_2 : BANK_1);
        return;
    }

    // Handle control keys
    if (pressed)
    {
        string kbtype = (isKeyboard ? "KEYB-" : "KEYP-");

        switch(channel)
        {
            case KB_BACKSPACE:
                if (gPageManager)
                    gPageManager->sendKeyboard(kbtype + "BACKSPACE");

                if (mCursorPosition > 0)
                {
                    if ((size_t)mCursorPosition < mInputText.length())
                    {
                        string old = mInputText;
                        mInputText = mInputText.substr(0, mCursorPosition - 1);

                        if (old.length() > (size_t)mCursorPosition)
                            mInputText = old.substr(mCursorPosition);
                    }
                    else
                        mInputText = mInputText.substr(0, mInputText.length() - 1);

                    mCursorPosition--;

                    if (input)
                    {
                        input->setText(mInputText, 0);
                        input->setTextCursorPosition(0, mCursorPosition);
                    }
                }

                mShift = mBank3 = false;
                mBank = (mCapsLock ? BANK_2 : BANK_1);
            break;

            case KB_CANCEL:
                if (gPageManager)
                    gPageManager->sendKeyboard(kbtype + "ABORT");

                mInputText.clear();
                mCursorPosition = 0;

                if (input)
                {
                    input->setText("", 0);
                    input->setTextCursorPosition(0, mCursorPosition);
                }

                mShift = mBank3 = mCapsLock = false;
                mBank = BANK_1;
            break;

            case KB_CLEAR:
                if (gPageManager)
                    gPageManager->sendKeyboard(kbtype + "CLEAR");

                mInputText.clear();
                mCursorPosition = 0;

                if (input)
                {
                    input->setText(mInputText, 0);
                    input->setTextCursorPosition(0, mCursorPosition);
                }

                mShift = mBank3 = false;
                mBank = (mCapsLock ? BANK_2 : BANK_1);
            break;

            case KB_ENTER:
                if (gPageManager)
                    gPageManager->sendKeyboard(kbtype + "ENTER");

                if ((size_t)mCursorPosition < mInputText.length())
                {
                    string left, right;

                    if (mCursorPosition > 0)
                        left = mInputText.substr(0, mCursorPosition);

                    right = mInputText.substr(mCursorPosition);
                    mInputText = left + "\n" + right;
                    mCursorPosition++;
                }
                else
                {
                    mInputText.append("\n");
                    mCursorPosition++;
                }

                if (input)
                {
                    input->setText(mInputText, 0);
                    input->setTextCursorPosition(0, mCursorPosition);
                }
            break;

            case KB_SPACE:
                if (gPageManager)
                    gPageManager->sendKeyboard(kbtype + "SPACE");

                if ((size_t)mCursorPosition < mInputText.length())
                {
                    string left, right;

                    if (mCursorPosition > 0)
                        left = mInputText.substr(0, mCursorPosition);

                    right = mInputText.substr(mCursorPosition);
                    mInputText = left + " " + right;
                    mCursorPosition++;
                }
                else
                {
                    mInputText.append(" ");
                    mCursorPosition++;
                }

                if (input)
                {
                    input->setText(mInputText, 0);
                    input->setTextCursorPosition(0, mCursorPosition);
                }

                mShift = mBank3 = false;
                mBank = (mCapsLock ? BANK_2 : BANK_1);
            break;

            case KB_SUBMIT:
                if (gPageManager)
                    gPageManager->sendKeyboard(kbtype + mInputText);

                mInputText.clear();

                if (input)
                    input->setText(mInputText, 0);

                mShift = mBank3 = mCapsLock = false;
                mBank = 1;
            break;
        }

        MSG_DEBUG("Current string: " << mInputText);
    }
}

/**
 * Set the keys of a keyboard or keypad to the given \b bank. With the \b handle
 * one key can be set to pressed state.
 * This works for multi bargraph keys with 6 states as well as normal keys
 * with only 2 states.
 *
 * @param bank      The number of the bank the multi bargraph keys should be set.
 *                  This is a number between 1 and 3.
 * @param handle    If this is >0 and a button with the given handle is found,
 *                  The state is increased by 1, so that the button appears
 *                  highlighted.
 */
void TSystemButton::setKeysToBank(int bank, uint handle)
{
    DECL_TRACER("TSystemButton::setKeysToBank(int bank, int handle)");

    if (mButtons.empty() || bank < BANK_1 || bank > BANK_3)
        return;

    std::thread thr = std::thread([=] {
        vector<TButton *>::iterator iter;
        int inst = (bank - 1) * 2;

        for (iter = mButtons.begin(); iter != mButtons.end(); ++iter)
        {
            TButton *button = *iter;
            int channelNumber = button->getChannelNumber();
            uint hdl = button->getHandle();
            SYS_BUTTON_TYPE tp = getSystemButtonType(channelNumber, 0);

            if (tp == KEY_KEY)
            {
                if (handle == hdl)
                    button->setBargraphLevel(inst + 1);
                else
                    button->setBargraphLevel(inst);
            }
            else if (tp == KEY_BUTTON)
            {
                if (handle == hdl || (channelNumber == KB_CAPS_LOCK && mCapsLock))
                    button->setActive(STATE_ON);
                else
                    button->setActive(STATE_OFF);
            }
        }
    });

    thr.detach();
}

void TSystemButton::handleDedicatedKeys(int channel, bool pressed)
{
    DECL_TRACER("TSystemButton::handleDedicatedKeys(int channel, bool pressed)");

    if (!gPageManager)
        return;

    string kbtype = "KEYB-";

    if (mCapsLock)
        mShift = true;

    switch (channel)
    {
        case 501: sendDedicatedKey(channel, kbtype + "ESC", pressed); break;
        case 502: sendDedicatedKey(channel, kbtype + (mShift ? "!" : "1"), pressed); break;
        case 503: sendDedicatedKey(channel, kbtype + (mShift ? "@" : "2"), pressed); break;
        case 504: sendDedicatedKey(channel, kbtype + (mShift ? "#" : "3"), pressed); break;
        case 505: sendDedicatedKey(channel, kbtype + (mShift ? "$" : "4"), pressed); break;
        case 506: sendDedicatedKey(channel, kbtype + (mShift ? "%" : "5"), pressed); break;
        case 507: sendDedicatedKey(channel, kbtype + (mShift ? "^" : "6"), pressed); break;
        case 508: sendDedicatedKey(channel, kbtype + (mShift ? "&" : "7"), pressed); break;
        case 509: sendDedicatedKey(channel, kbtype + (mShift ? "*" : "8"), pressed); break;
        case 510: sendDedicatedKey(channel, kbtype + (mShift ? "(" : "9"), pressed); break;
        case 511: sendDedicatedKey(channel, kbtype + (mShift ? ")" : "0"), pressed); break;
        case 512: sendDedicatedKey(channel, kbtype + (mShift ? "_" : "-"), pressed); break;
        case 513: sendDedicatedKey(channel, kbtype + (mShift ? "+" : "="), pressed); break;
        case 514: sendDedicatedKey(channel, kbtype + "BACKSPACE", pressed); break;
        case 515: sendDedicatedKey(channel, kbtype + "TAB", pressed); break;
        case 516: sendDedicatedKey(channel, kbtype + (mShift ? "Q" : "q"), pressed); break;
        case 517: sendDedicatedKey(channel, kbtype + (mShift ? "W" : "w"), pressed); break;
        case 518: sendDedicatedKey(channel, kbtype + (mShift ? "E" : "e"), pressed); break;
        case 519: sendDedicatedKey(channel, kbtype + (mShift ? "R" : "r"), pressed); break;
        case 520: sendDedicatedKey(channel, kbtype + (mShift ? "T" : "t"), pressed); break;
        case 521: sendDedicatedKey(channel, kbtype + (mShift ? "Y" : "y"), pressed); break;
        case 522: sendDedicatedKey(channel, kbtype + (mShift ? "U" : "u"), pressed); break;
        case 523: sendDedicatedKey(channel, kbtype + (mShift ? "I" : "i"), pressed); break;
        case 524: sendDedicatedKey(channel, kbtype + (mShift ? "O" : "o"), pressed); break;
        case 525: sendDedicatedKey(channel, kbtype + (mShift ? "P" : "p"), pressed); break;
        case 526: sendDedicatedKey(channel, kbtype + (mShift ? "{" : "["), pressed); break;
        case 527: sendDedicatedKey(channel, kbtype + (mShift ? "}" : "]"), pressed); break;
        case 528: sendDedicatedKey(channel, kbtype + "ENTER", pressed); break;
        case 529: sendDedicatedKey(channel, kbtype + "CTRLL", pressed); break;
        case 530: sendDedicatedKey(channel, kbtype + (mShift ? "A" : "a"), pressed); break;
        case 531: sendDedicatedKey(channel, kbtype + (mShift ? "S" : "s"), pressed); break;
        case 532: sendDedicatedKey(channel, kbtype + (mShift ? "D" : "d"), pressed); break;
        case 533: sendDedicatedKey(channel, kbtype + (mShift ? "F" : "f"), pressed); break;
        case 534: sendDedicatedKey(channel, kbtype + (mShift ? "G" : "g"), pressed); break;
        case 535: sendDedicatedKey(channel, kbtype + (mShift ? "H" : "h"), pressed); break;
        case 536: sendDedicatedKey(channel, kbtype + (mShift ? "J" : "j"), pressed); break;
        case 537: sendDedicatedKey(channel, kbtype + (mShift ? "K" : "k"), pressed); break;
        case 538: sendDedicatedKey(channel, kbtype + (mShift ? "L" : "l"), pressed); break;
        case 539: sendDedicatedKey(channel, kbtype + (mShift ? ":" : ";"), pressed); break;
        case 540: sendDedicatedKey(channel, kbtype + (mShift ? "\"" : "'"), pressed); break;
        case 541: sendDedicatedKey(channel, kbtype + (mShift ? "~" : "`"), pressed); break;
        case 542: sendDedicatedKey(channel, kbtype + "SHIFTL", pressed); mShift = !mShift; break;
        case 543: sendDedicatedKey(channel, kbtype + (mShift ? "|" : "\\"), pressed); break;
        case 544: sendDedicatedKey(channel, kbtype + (mShift ? "Z" : "z"), pressed); break;
        case 545: sendDedicatedKey(channel, kbtype + (mShift ? "X" : "x"), pressed); break;
        case 546: sendDedicatedKey(channel, kbtype + (mShift ? "C" : "c"), pressed); break;
        case 547: sendDedicatedKey(channel, kbtype + (mShift ? "V" : "v"), pressed); break;
        case 548: sendDedicatedKey(channel, kbtype + (mShift ? "B" : "b"), pressed); break;
        case 549: sendDedicatedKey(channel, kbtype + (mShift ? "N" : "n"), pressed); break;
        case 550: sendDedicatedKey(channel, kbtype + (mShift ? "M" : "m"), pressed); break;
        case 551: sendDedicatedKey(channel, kbtype + (mShift ? "<" : ","), pressed); break;
        case 552: sendDedicatedKey(channel, kbtype + (mShift ? ">" : "."), pressed); break;
        case 553: sendDedicatedKey(channel, kbtype + (mShift ? "?" : "/"), pressed); break;
        case 554: sendDedicatedKey(channel, kbtype + "SHIFTR", pressed); mShift = !mShift; break;
        case 556: sendDedicatedKey(channel, kbtype + "ALT", pressed); break;
        case 557: sendDedicatedKey(channel, kbtype + "SPACE", pressed); break;
        case 558: sendDedicatedKey(channel, kbtype + "CAPS", pressed); mCapsLock = !mCapsLock; break;
        case 559: sendDedicatedKey(channel, kbtype + "F1", pressed); break;
        case 560: sendDedicatedKey(channel, kbtype + "F2", pressed); break;
        case 561: sendDedicatedKey(channel, kbtype + "F3", pressed); break;
        case 562: sendDedicatedKey(channel, kbtype + "F4", pressed); break;
        case 563: sendDedicatedKey(channel, kbtype + "F5", pressed); break;
        case 564: sendDedicatedKey(channel, kbtype + "F6", pressed); break;
        case 565: sendDedicatedKey(channel, kbtype + "F7", pressed); break;
        case 566: sendDedicatedKey(channel, kbtype + "F8", pressed); break;
        case 567: sendDedicatedKey(channel, kbtype + "F9", pressed); break;
        case 568: sendDedicatedKey(channel, kbtype + "F10", pressed); break;
        case 587: sendDedicatedKey(channel, kbtype + "F11", pressed); break;
        case 588: sendDedicatedKey(channel, kbtype + "F12", pressed); break;
        case 597: sendDedicatedKey(channel, kbtype + "CTRLR", pressed); break;
        case 600: sendDedicatedKey(channel, kbtype + "ALTGR", pressed); break;
        case 602: sendDedicatedKey(channel, kbtype + "HOME", pressed); break;
        case 603: sendDedicatedKey(channel, kbtype + "UP", pressed); break;
        case 604: sendDedicatedKey(channel, kbtype + "PGDN", pressed); break;
        case 605: sendDedicatedKey(channel, kbtype + "LEFT", pressed); break;
        case 606: sendDedicatedKey(channel, kbtype + "RIGHT", pressed); break;
        case 607: sendDedicatedKey(channel, kbtype + "END", pressed); break;
        case 608: sendDedicatedKey(channel, kbtype + "DOWN", pressed); break;
        case 609: sendDedicatedKey(channel, kbtype + "PGDN", pressed); break;
        case 610: sendDedicatedKey(channel, kbtype + "INS", pressed); break;
        case 611: sendDedicatedKey(channel, kbtype + "DEL", pressed); break;
    }

    if ((mShift && channel != 554 && channel != 542) || mCapsLock)
        mShift = false;
}

void TSystemButton::sendDedicatedKey(int channel, const string str, bool pressed)
{
    DECL_TRACER("TSystemButton::sendDedicatedKey(int channel, const string str)");

    TButton *button = getSysButton(channel, 0);

    if (button)
        button->setActive(pressed ? STATE_ON : STATE_OFF);

    gPageManager->sendKeyboard(str);
}

/**
 * @brief Translates the button types into a string.
 * This method is for debugging purposes only!
 *
 * @param type  The enum number of the button type.
 *
 * @return Returns the string representation of the button type.
 */
string TSystemButton::typeToString(TSystemButton::SYS_BUUTON_TYPE type)
{
    switch (type)
    {
        case KEY_BUTTON:            return "KEY_BUTTON";
        case KEY_INPUT_MULTI:       return "KEY_INPUT_MULTI";
        case KEY_INPUT_SINGLE:      return "KEY_INPUT_SINGLE";
        case KEY_KEY:               return "KEY_KEY";
        case KEY_UNDEFINED:         return "KEY_UNDEFINED";
    }

    return string();
}