#include "virtualKeyboard.hpp" #include #include #include #include #include #include #include #include #include VirtualKeyboard::VirtualKeyboard(QWidget* parent) : QWidget(parent) , m_mainLayout(nullptr) , m_keyboardLayout(nullptr) , m_functionLayout(nullptr) , m_displayEdit(nullptr) , m_targetWidget(nullptr) , m_capsLock(false) , m_shift(false) , m_spaceButton(nullptr) , m_backspaceButton(nullptr) , m_enterButton(nullptr) , m_shiftButton(nullptr) , m_capsLockButton(nullptr) , m_hideButton(nullptr) { // Ne pas créer de fenêtre séparée, utiliser le parent setAttribute(Qt::WA_ShowWithoutActivating); setAutoFillBackground(true); // Permettre le fond personnalisé // Initialize key layouts m_qwertyLayout << "q" << "w" << "e" << "r" << "t" << "y" << "u" << "i" << "o" << "p" << "a" << "s" << "d" << "f" << "g" << "h" << "j" << "k" << "l" << "z" << "x" << "c" << "v" << "b" << "n" << "m"; m_numericLayout << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8" << "9" << "0"; setupKeyboard(); applyKeyboardStyling(); updateKeyLabels(); } VirtualKeyboard::~VirtualKeyboard() { // Qt handles cleanup automatically } void VirtualKeyboard::setTargetWidget(QWidget* target) { m_targetWidget = target; } void VirtualKeyboard::showForWidget(QWidget* target) { setTargetWidget(target); // Initialiser la zone d'affichage avec le contenu actuel if (QLineEdit* lineEdit = qobject_cast(target)) { m_displayEdit->setText(lineEdit->text()); } else if (QTextEdit* textEdit = qobject_cast(target)) { m_displayEdit->setText(textEdit->toPlainText()); } else { m_displayEdit->clear(); } // Positionner le clavier comme overlay sur l'application parent if (parentWidget()) { setGeometry(parentWidget()->rect()); } show(); raise(); } void VirtualKeyboard::hideKeyboard() { hide(); m_targetWidget = nullptr; m_displayEdit->clear(); } void VirtualKeyboard::setupKeyboard() { m_mainLayout = new QVBoxLayout(this); m_mainLayout->setSpacing(20); m_mainLayout->setContentsMargins(50, 50, 50, 50); // Header with title and hide button QHBoxLayout* headerLayout = new QHBoxLayout(); QLabel* titleLabel = new QLabel("Clavier Virtuel"); titleLabel->setObjectName("keyboardTitle"); m_hideButton = new QPushButton("✕ Fermer"); m_hideButton->setObjectName("hideButton"); m_hideButton->setFixedSize(180, 70); connect(m_hideButton, &QPushButton::clicked, this, &VirtualKeyboard::hideKeyboard); headerLayout->addWidget(titleLabel); headerLayout->addStretch(); headerLayout->addWidget(m_hideButton); m_mainLayout->addLayout(headerLayout); // Zone d'affichage du texte en cours de saisie m_displayEdit = new QLineEdit(); m_displayEdit->setObjectName("displayEdit"); m_displayEdit->setReadOnly(true); m_displayEdit->setFixedHeight(80); m_displayEdit->setPlaceholderText("Le texte saisi apparaîtra ici..."); m_mainLayout->addWidget(m_displayEdit); // Add spacer to center keyboard m_mainLayout->addStretch(1); // Numeric row setupNumericKeys(); // Alphabetic rows setupAlphabeticKeys(); // Function keys row setupFunctionKeys(); // Add spacer to center keyboard m_mainLayout->addStretch(1); } void VirtualKeyboard::setupNumericKeys() { QHBoxLayout* numericLayout = new QHBoxLayout(); numericLayout->setSpacing(15); numericLayout->addStretch(); // Centrer les touches for (const QString& key : m_numericLayout) { QPushButton* button = new QPushButton(key); button->setObjectName("numericKey"); button->setFixedSize(60, 60); connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed); m_numericKeys.append(button); numericLayout->addWidget(button); } // Add special numeric characters QStringList specialChars = {"-", "=", "[", "]", "\\"}; for (const QString& key : specialChars) { QPushButton* button = new QPushButton(key); button->setObjectName("specialKey"); button->setFixedSize(60, 60); connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed); numericLayout->addWidget(button); } numericLayout->addStretch(); // Centrer les touches m_mainLayout->addLayout(numericLayout); } void VirtualKeyboard::setupAlphabeticKeys() { // First row: QWERTYUIOP QHBoxLayout* firstRow = new QHBoxLayout(); firstRow->setSpacing(15); firstRow->addStretch(); for (int i = 0; i < 10; ++i) { QPushButton* button = new QPushButton(m_qwertyLayout[i]); button->setObjectName("alphabeticKey"); button->setFixedSize(60, 60); connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed); m_alphabeticKeys.append(button); firstRow->addWidget(button); } firstRow->addStretch(); m_mainLayout->addLayout(firstRow); // Second row: ASDFGHJKL QHBoxLayout* secondRow = new QHBoxLayout(); secondRow->setSpacing(15); secondRow->addStretch(); for (int i = 10; i < 19; ++i) { QPushButton* button = new QPushButton(m_qwertyLayout[i]); button->setObjectName("alphabeticKey"); button->setFixedSize(60, 60); connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed); m_alphabeticKeys.append(button); secondRow->addWidget(button); } secondRow->addStretch(); m_mainLayout->addLayout(secondRow); // Third row: ZXCVBNM QHBoxLayout* thirdRow = new QHBoxLayout(); thirdRow->setSpacing(15); thirdRow->addStretch(); // Shift button m_shiftButton = new QPushButton("⇧"); m_shiftButton->setObjectName("functionKey"); m_shiftButton->setFixedSize(80, 60); m_shiftButton->setCheckable(true); connect(m_shiftButton, &QPushButton::clicked, this, &VirtualKeyboard::onShiftPressed); thirdRow->addWidget(m_shiftButton); for (int i = 19; i < 26; ++i) { QPushButton* button = new QPushButton(m_qwertyLayout[i]); button->setObjectName("alphabeticKey"); button->setFixedSize(60, 60); connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed); m_alphabeticKeys.append(button); thirdRow->addWidget(button); } // Backspace button m_backspaceButton = new QPushButton("⌫"); m_backspaceButton->setObjectName("functionKey"); m_backspaceButton->setFixedSize(80, 60); connect(m_backspaceButton, &QPushButton::clicked, this, &VirtualKeyboard::onBackspacePressed); thirdRow->addWidget(m_backspaceButton); thirdRow->addStretch(); m_mainLayout->addLayout(thirdRow); } void VirtualKeyboard::setupFunctionKeys() { m_functionLayout = new QHBoxLayout(); m_functionLayout->setSpacing(20); m_functionLayout->addStretch(); // Caps Lock m_capsLockButton = new QPushButton("Caps"); m_capsLockButton->setObjectName("functionKey"); m_capsLockButton->setFixedSize(80, 60); m_capsLockButton->setCheckable(true); connect(m_capsLockButton, &QPushButton::clicked, this, &VirtualKeyboard::onCapsLockPressed); m_functionLayout->addWidget(m_capsLockButton); // Space bar m_spaceButton = new QPushButton("Espace"); m_spaceButton->setObjectName("spaceKey"); m_spaceButton->setFixedSize(240, 60); connect(m_spaceButton, &QPushButton::clicked, this, &VirtualKeyboard::onSpacePressed); m_functionLayout->addWidget(m_spaceButton); // Enter m_enterButton = new QPushButton("↵"); m_enterButton->setObjectName("functionKey"); m_enterButton->setFixedSize(80, 60); connect(m_enterButton, &QPushButton::clicked, this, &VirtualKeyboard::onEnterPressed); m_functionLayout->addWidget(m_enterButton); // Common punctuation QStringList punctuation = {".", ",", "?", "!", ":", ";"}; for (const QString& key : punctuation) { QPushButton* button = new QPushButton(key); button->setObjectName("punctuationKey"); button->setFixedSize(60, 60); connect(button, &QPushButton::clicked, this, &VirtualKeyboard::onKeyPressed); m_functionLayout->addWidget(button); } m_functionLayout->addStretch(); m_mainLayout->addLayout(m_functionLayout); } void VirtualKeyboard::applyKeyboardStyling() { // Utiliser une palette pour le fond au lieu du stylesheet QPalette palette = this->palette(); palette.setColor(QPalette::Window, QColor(44, 62, 80, 250)); setPalette(palette); setStyleSheet(R"( #keyboardTitle { color: #ecf0f1; font-size: 28px; font-weight: bold; padding: 15px; } #displayEdit { background-color: #34495e; color: #ecf0f1; border: 2px solid #5d6d7e; border-radius: 12px; font-size: 22px; padding: 15px; font-family: monospace; } #hideButton { background-color: #e74c3c; color: white; border: none; border-radius: 25px; font-size: 18px; font-weight: bold; } #hideButton:hover { background-color: #c0392b; } #hideButton:pressed { background-color: #a93226; } #alphabeticKey, #numericKey { background-color: #34495e; color: #ecf0f1; border: 2px solid #5d6d7e; border-radius: 12px; font-size: 24px; font-weight: bold; } #alphabeticKey:hover, #numericKey:hover { background-color: #4a5f7a; } #alphabeticKey:pressed, #numericKey:pressed { background-color: #3498db; } #functionKey { background-color: #e67e22; color: white; border: 2px solid #d68910; border-radius: 12px; font-size: 18px; font-weight: bold; } #functionKey:hover { background-color: #f39c12; } #functionKey:pressed, #functionKey:checked { background-color: #d35400; } #spaceKey { background-color: #27ae60; color: white; border: 2px solid #229954; border-radius: 12px; font-size: 20px; font-weight: bold; } #spaceKey:hover { background-color: #2ecc71; } #spaceKey:pressed { background-color: #1e8449; } #specialKey, #punctuationKey { background-color: #8e44ad; color: white; border: 2px solid #7d3c98; border-radius: 12px; font-size: 20px; font-weight: bold; } #specialKey:hover, #punctuationKey:hover { background-color: #a569bd; } #specialKey:pressed, #punctuationKey:pressed { background-color: #6c3483; } )"); } void VirtualKeyboard::updateKeyLabels() { bool upperCase = m_capsLock || m_shift; for (int i = 0; i < m_alphabeticKeys.size(); ++i) { QString key = m_qwertyLayout[i]; if (upperCase) { key = key.toUpper(); } m_alphabeticKeys[i]->setText(key); } // Update shift button appearance m_shiftButton->setChecked(m_shift); m_capsLockButton->setChecked(m_capsLock); } void VirtualKeyboard::insertTextToTarget(const QString& text) { if (!m_targetWidget) return; if (QLineEdit* lineEdit = qobject_cast(m_targetWidget)) { lineEdit->insert(text); // Mettre à jour la zone d'affichage m_displayEdit->setText(lineEdit->text()); } else if (QTextEdit* textEdit = qobject_cast(m_targetWidget)) { textEdit->insertPlainText(text); // Mettre à jour la zone d'affichage m_displayEdit->setText(textEdit->toPlainText()); } } void VirtualKeyboard::positionKeyboard() { if (!m_targetWidget) return; // Get screen geometry QScreen* screen = QApplication::primaryScreen(); QRect screenGeometry = screen->availableGeometry(); // Get target widget global position QPoint targetPos = m_targetWidget->mapToGlobal(QPoint(0, 0)); QSize targetSize = m_targetWidget->size(); // Calculate keyboard size adjustSize(); QSize keyboardSize = size(); // Position keyboard below the target widget int x = targetPos.x(); int y = targetPos.y() + targetSize.height() + 10; // Ensure keyboard stays within screen bounds if (x + keyboardSize.width() > screenGeometry.right()) { x = screenGeometry.right() - keyboardSize.width(); } if (x < screenGeometry.left()) { x = screenGeometry.left(); } if (y + keyboardSize.height() > screenGeometry.bottom()) { // If no space below, position above the target widget y = targetPos.y() - keyboardSize.height() - 10; } move(x, y); } void VirtualKeyboard::showEvent(QShowEvent* event) { QWidget::showEvent(event); // Le clavier est maintenant en plein écran, pas besoin de positionner } void VirtualKeyboard::hideEvent(QHideEvent* event) { QWidget::hideEvent(event); m_targetWidget = nullptr; } void VirtualKeyboard::resizeEvent(QResizeEvent* event) { QWidget::resizeEvent(event); // S'assurer que le clavier couvre toute la fenêtre parent si visible if (isVisible() && parentWidget()) { setGeometry(parentWidget()->rect()); } } void VirtualKeyboard::paintEvent(QPaintEvent* event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // Dessiner le fond avec transparence QColor backgroundColor(44, 62, 80, 250); painter.fillRect(rect(), backgroundColor); // Dessiner la bordure QPen borderPen(QColor(52, 73, 94), 3); painter.setPen(borderPen); painter.drawRoundedRect(rect().adjusted(1, 1, -1, -1), 15, 15); QWidget::paintEvent(event); } // Slot implementations void VirtualKeyboard::onKeyPressed() { QPushButton* button = qobject_cast(sender()); if (!button) return; QString text = button->text(); insertTextToTarget(text); // Reset shift after key press (but not caps lock) if (m_shift && !m_capsLock) { m_shift = false; updateKeyLabels(); } } void VirtualKeyboard::onBackspacePressed() { if (!m_targetWidget) return; if (QLineEdit* lineEdit = qobject_cast(m_targetWidget)) { lineEdit->backspace(); // Mettre à jour la zone d'affichage m_displayEdit->setText(lineEdit->text()); } else if (QTextEdit* textEdit = qobject_cast(m_targetWidget)) { QTextCursor cursor = textEdit->textCursor(); cursor.deletePreviousChar(); textEdit->setTextCursor(cursor); // Mettre à jour la zone d'affichage m_displayEdit->setText(textEdit->toPlainText()); } } void VirtualKeyboard::onSpacePressed() { insertTextToTarget(" "); // Reset shift after space (but not caps lock) if (m_shift && !m_capsLock) { m_shift = false; updateKeyLabels(); } } void VirtualKeyboard::onEnterPressed() { insertTextToTarget("\n"); // Reset shift after enter (but not caps lock) if (m_shift && !m_capsLock) { m_shift = false; updateKeyLabels(); } } void VirtualKeyboard::onShiftPressed() { m_shift = !m_shift; updateKeyLabels(); } void VirtualKeyboard::onCapsLockPressed() { m_capsLock = !m_capsLock; // If caps lock is on, turn off shift if (m_capsLock) { m_shift = false; } updateKeyLabels(); }