From 923faef13632079ef5c24abd592c00a20465ebe1 Mon Sep 17 00:00:00 2001 From: liuyuanpeng Date: Thu, 9 Jan 2020 19:53:36 +0800 Subject: [PATCH 1/3] * Fix the problem that the on-screen keyboard is displayed incorrectly when dual screen. * Fixed the issue that the second-user cannot use biometrics when switching users to lock the screen. * Fixed the lock screen issue when root user switched tty back and forth. * Keep lock screen stays on top. * Extended mode, login interface cannot be switched between two monitors with the mouse. * Fixed the problem that the first user could not lock the screen when logging in two users at the same time by user switching. * UI interface adjustment. --- .gitmodules | 3 - BiometricAuth/biometricauthwidget.cpp | 22 +- BiometricAuth/biometricauthwidget.h | 1 + BiometricAuth/biometricproxy.cpp | 33 ++- BiometricAuth/biometricproxy.h | 8 + data/org.ukui.screensaver.gschema.xml | 1 - i18n_ts/es.ts | 119 ++++++++-- i18n_ts/fr.ts | 119 ++++++++-- i18n_ts/pt.ts | 119 ++++++++-- i18n_ts/ru.ts | 119 ++++++++-- i18n_ts/zh_CN.ts | 83 ++++--- src/CMakeLists.txt | 3 + src/assets/authdialog.qss | 2 +- src/authdialog.cpp | 126 ++++++++-- src/authdialog.h | 4 + src/configuration.cpp | 24 +- src/configuration.h | 2 - src/fullbackgroundwidget.cpp | 146 ++++++++++-- src/fullbackgroundwidget.h | 6 +- src/iconedit.cpp | 11 +- src/interface.cpp | 21 +- src/lockwidget.cpp | 62 ++++- src/lockwidget.h | 5 + src/pam-tally.c | 323 ++++++++++++++++++++++++++ src/pam-tally.h | 49 ++++ src/screensaver.cpp | 6 +- src/screensaver.h | 3 +- src/screensaverwidget.cpp | 177 +------------- src/screensaverwidget.h | 16 +- src/users.cpp | 4 +- 30 files changed, 1221 insertions(+), 396 deletions(-) delete mode 100644 .gitmodules create mode 100644 src/pam-tally.c create mode 100644 src/pam-tally.h diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 4c80b20..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "VirtualKeyboard"] - path = VirtualKeyboard - url = https://github.com/ukui/VirtualKeyboard.git diff --git a/BiometricAuth/biometricauthwidget.cpp b/BiometricAuth/biometricauthwidget.cpp index d79f45c..0291fce 100644 --- a/BiometricAuth/biometricauthwidget.cpp +++ b/BiometricAuth/biometricauthwidget.cpp @@ -26,18 +26,20 @@ BiometricAuthWidget::BiometricAuthWidget(BiometricProxy *proxy, QWidget *parent) proxy(proxy), isInAuth(false), movieTimer(nullptr), + retrytimer(nullptr), failedCount(0), timeoutCount(0), beStopped(false) { initUI(); - resize(400, 300); + resize(400, 200); if(this->proxy) { connect(this->proxy, &BiometricProxy::StatusChanged, this, &BiometricAuthWidget::onStatusChanged); } + } void BiometricAuthWidget::initUI() @@ -87,7 +89,8 @@ void BiometricAuthWidget::startAuth(DeviceInfoPtr device, int uid) this->failedCount = 0; this->timeoutCount = 0; this->beStopped = false; - + + proxy->StopOps(device->id); startAuth_(); } @@ -115,6 +118,11 @@ void BiometricAuthWidget::stopAuth() return; } proxy->StopOps(device->id); + if(retrytimer&&retrytimer->isActive()){ + retrytimer->stop(); + delete retrytimer; + retrytimer = nullptr; + } isInAuth = false; updateImage(0); } @@ -150,7 +158,15 @@ void BiometricAuthWidget::onIdentifyComplete(QDBusPendingCallWatcher *watcher) else { lblNotify->setText(tr("Identify failed, Please retry.")); - QTimer::singleShot(1000, this, &BiometricAuthWidget::startAuth_); + if(!beStopped){ + // QTimer::singleShot(1000, this, &BiometricAuthWidget::startAuth_); + if(!retrytimer){ + retrytimer = new QTimer(this); + retrytimer->setSingleShot(true); + connect(retrytimer, &QTimer::timeout, this, &BiometricAuthWidget::startAuth_); + } + retrytimer->start(1000); + } } } //识别发生错误 diff --git a/BiometricAuth/biometricauthwidget.h b/BiometricAuth/biometricauthwidget.h index 4350be7..b3f1d54 100644 --- a/BiometricAuth/biometricauthwidget.h +++ b/BiometricAuth/biometricauthwidget.h @@ -81,6 +81,7 @@ private Q_SLOTS: int failedCount; int timeoutCount; bool beStopped; + QTimer *retrytimer; }; #endif // BIOMETRICAUTHWIDGET_H diff --git a/BiometricAuth/biometricproxy.cpp b/BiometricAuth/biometricproxy.cpp index 357efa2..52b4402 100644 --- a/BiometricAuth/biometricproxy.cpp +++ b/BiometricAuth/biometricproxy.cpp @@ -17,7 +17,7 @@ * 02110-1301, USA. **/ #include "biometricproxy.h" - +#include BiometricProxy::BiometricProxy(QObject *parent) : QDBusAbstractInterface(BIOMETRIC_DBUS_SERVICE, @@ -36,6 +36,37 @@ QDBusPendingCall BiometricProxy::Identify(int drvid, int uid, int indexStart, in return asyncCallWithArgumentList(QStringLiteral("Identify"), argList); } +int BiometricProxy::GetFeatureCount(int uid, int indexStart, int indexEnd) +{ + QDBusMessage result = call(QStringLiteral("GetDevList")); + if(result.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "GetDevList error:" << result.errorMessage(); + return 0; + } + auto dbusArg = result.arguments().at(1).value(); + QList variantList; + dbusArg >> variantList; + int res = 0; + for(int i = 0; i < variantList.size(); i++) + { + + DeviceInfoPtr pDeviceInfo = std::make_shared(); + + auto arg = variantList.at(i).value(); + arg >> *pDeviceInfo; + StopOps(pDeviceInfo->id); + QDBusMessage FeatureResult = call(QStringLiteral("GetFeatureList"),pDeviceInfo->id,uid,indexStart,indexEnd); + if(FeatureResult.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "GetFeatureList error:" << FeatureResult.errorMessage(); + return 0; + } + res += FeatureResult.arguments().takeFirst().toInt(); + } + return res; +} + int BiometricProxy::StopOps(int drvid, int waiting) { QDBusReply reply = call(QStringLiteral("StopOps"), drvid, waiting); diff --git a/BiometricAuth/biometricproxy.h b/BiometricAuth/biometricproxy.h index 3c161ae..62be56d 100644 --- a/BiometricAuth/biometricproxy.h +++ b/BiometricAuth/biometricproxy.h @@ -71,6 +71,14 @@ public Q_SLOTS: * @return */ int StopOps(int drvid, int waiting = 5); + /** + * @brief 获取当前用户已连接设备对应特征数目 + * @param uid 用户id + * @param indexStart 用于认证的特征索引范围 + * @param indexEnd + * @return + */ + int GetFeatureCount(int uid, int indexStart = 0, int indexEnd = -1); /** * @brief 获取已连接的设备列表 * @return diff --git a/data/org.ukui.screensaver.gschema.xml b/data/org.ukui.screensaver.gschema.xml index 04cee2f..8673291 100644 --- a/data/org.ukui.screensaver.gschema.xml +++ b/data/org.ukui.screensaver.gschema.xml @@ -4,7 +4,6 @@ - diff --git a/i18n_ts/es.ts b/i18n_ts/es.ts index 1961923..d9c3a80 100644 --- a/i18n_ts/es.ts +++ b/i18n_ts/es.ts @@ -1,23 +1,23 @@ - + AuthDialog Form - Formar + Formar More Devices - Más dispositivos + Más dispositivos Biometric - Biometrico + Biometrico Password - Contraseña + Contraseña Retry @@ -25,80 +25,157 @@ UnLock - Desbloquear + Desbloquear LoggedIn - Conectado + Conectado Password Incorrect, Please try again Contraseña incorrecta, por favor intente de nuevo + + Password: + + + + Account locked %1 minutes due to %2 fail attempts + + + + Authentication failure,there are still %1 remaining opportunities + + + + Biometric Authentication + + + + Password Authentication + + + + Other Devices + + BioAuthWidget Form - Formar + Formar TextLabel - TextLabel + TextLabel More - Más + Más Retry - Procesar de nuevo + Procesar de nuevo Password - Contraseña + Contraseña BioDevices FingerPrint - Huella dactilar + Huella dactilar FingerVein - FingerVein + FingerVein Iris - Iris + Iris Face - Cara + Cara VoicePrint - Impresión de voz + Impresión de voz BioDevicesWidget Form - Formar + Formar Please select other biometric devices - Por favor seleccione otros dispositivos biométricos + Por favor seleccione otros dispositivos biométricos Device Type: - Tipo de dispositivo: + Tipo de dispositivo: Device Name: - Nombre del dispositivo: + Nombre del dispositivo: + + + + BiometricAuthWidget + + Current device: + + + + Identify failed, Please retry. + + + + + BiometricDevicesWidget + + Please select the biometric device + + + + Device type: + + + + Device name: + + + + OK + + + + + DeviceType + + FingerPrint + Huella dactilar + + + FingerVein + FingerVein + + + Iris + Iris + + + Face + Cara + + + VoicePrint + Impresión de voz diff --git a/i18n_ts/fr.ts b/i18n_ts/fr.ts index 2808658..4f9c447 100644 --- a/i18n_ts/fr.ts +++ b/i18n_ts/fr.ts @@ -1,23 +1,23 @@ - + AuthDialog Form - Forme + Forme More Devices - Plus d'appareils + Plus d'appareils Biometric - Biométrique + Biométrique Password - Mot de passe + Mot de passe Retry @@ -25,80 +25,157 @@ UnLock - Ouvrir + Ouvrir LoggedIn - Connecté + Connecté Password Incorrect, Please try again Mot de passe incorrect, veuillez réessayer + + Password: + + + + Account locked %1 minutes due to %2 fail attempts + + + + Authentication failure,there are still %1 remaining opportunities + + + + Biometric Authentication + + + + Password Authentication + + + + Other Devices + + BioAuthWidget Form - Forme + Forme TextLabel - TextLabel + TextLabel More - Plus + Plus Retry - Réessayez + Réessayez Password - Mot de passe + Mot de passe BioDevices FingerPrint - Empreinte digitale + Empreinte digitale FingerVein - FingerVein + FingerVein Iris - Iris + Iris Face - Visage + Visage VoicePrint - VoicePrint + VoicePrint BioDevicesWidget Form - Forme + Forme Please select other biometric devices - Veuillez sélectionner d'autres appareils biométriques + Veuillez sélectionner d'autres appareils biométriques Device Type: - Type d'appareil: + Type d'appareil: Device Name: - Nom de l'appareil: + Nom de l'appareil: + + + + BiometricAuthWidget + + Current device: + + + + Identify failed, Please retry. + + + + + BiometricDevicesWidget + + Please select the biometric device + + + + Device type: + + + + Device name: + + + + OK + + + + + DeviceType + + FingerPrint + Empreinte digitale + + + FingerVein + FingerVein + + + Iris + Iris + + + Face + Visage + + + VoicePrint + VoicePrint diff --git a/i18n_ts/pt.ts b/i18n_ts/pt.ts index a1b0965..0588734 100644 --- a/i18n_ts/pt.ts +++ b/i18n_ts/pt.ts @@ -1,23 +1,23 @@ - + AuthDialog Form - Formato + Formato More Devices - Mais dispositivos + Mais dispositivos Biometric - Biométrico + Biométrico Password - Senha + Senha Retry @@ -25,80 +25,157 @@ UnLock - Desbloquear + Desbloquear LoggedIn - Logado + Logado Password Incorrect, Please try again Senha incorreta, por favor tente novamente + + Password: + + + + Account locked %1 minutes due to %2 fail attempts + + + + Authentication failure,there are still %1 remaining opportunities + + + + Biometric Authentication + + + + Password Authentication + + + + Other Devices + + BioAuthWidget Form - Formato + Formato TextLabel - TextLabel + TextLabel More - Mais + Mais Retry - Tente novamente + Tente novamente Password - Senha + Senha BioDevices FingerPrint - Impressão digital + Impressão digital FingerVein - FingerVein + FingerVein Iris - Íris + Íris Face - Face + Face VoicePrint - VoicePrint + VoicePrint BioDevicesWidget Form - Formato + Formato Please select other biometric devices - Por favor, selecione outros dispositivos biométricos + Por favor, selecione outros dispositivos biométricos Device Type: - Tipo de dispositivo: + Tipo de dispositivo: Device Name: - Nome do dispositivo: + Nome do dispositivo: + + + + BiometricAuthWidget + + Current device: + + + + Identify failed, Please retry. + + + + + BiometricDevicesWidget + + Please select the biometric device + + + + Device type: + + + + Device name: + + + + OK + + + + + DeviceType + + FingerPrint + Impressão digital + + + FingerVein + FingerVein + + + Iris + Íris + + + Face + Face + + + VoicePrint + VoicePrint diff --git a/i18n_ts/ru.ts b/i18n_ts/ru.ts index 8743fb4..a7763bf 100644 --- a/i18n_ts/ru.ts +++ b/i18n_ts/ru.ts @@ -1,23 +1,23 @@ - + AuthDialog Form - форма + форма More Devices - Дополнительные устройства + Дополнительные устройства Biometric - Биометрические + Биометрические Password - пароль + пароль Retry @@ -25,80 +25,157 @@ UnLock - отпереть + отпереть LoggedIn - LoggedIn + LoggedIn Password Incorrect, Please try again Пароль неверен, повторите попытку + + Password: + + + + Account locked %1 minutes due to %2 fail attempts + + + + Authentication failure,there are still %1 remaining opportunities + + + + Biometric Authentication + + + + Password Authentication + + + + Other Devices + + BioAuthWidget Form - форма + форма TextLabel - TextLabel + TextLabel More - Больше + Больше Retry - Retry + Retry Password - пароль + пароль BioDevices FingerPrint - FingerPrint + FingerPrint FingerVein - FingerVein + FingerVein Iris - Ирис + Ирис Face - Лицо + Лицо VoicePrint - Voiceprint + Voiceprint BioDevicesWidget Form - форма + форма Please select other biometric devices - Выберите другие биометрические устройства + Выберите другие биометрические устройства Device Type: - Тип устройства: + Тип устройства: Device Name: - Имя устройства: + Имя устройства: + + + + BiometricAuthWidget + + Current device: + + + + Identify failed, Please retry. + + + + + BiometricDevicesWidget + + Please select the biometric device + + + + Device type: + + + + Device name: + + + + OK + + + + + DeviceType + + FingerPrint + FingerPrint + + + FingerVein + FingerVein + + + Iris + Ирис + + + Face + Лицо + + + VoicePrint + Voiceprint diff --git a/i18n_ts/zh_CN.ts b/i18n_ts/zh_CN.ts index c16bdab..34f29c7 100644 --- a/i18n_ts/zh_CN.ts +++ b/i18n_ts/zh_CN.ts @@ -1,55 +1,66 @@ - + AuthDialog More Devices - 选择其他设备 + 选择其他设备 Biometric - 使用生物识别认证 + 使用生物识别认证 Password - 使用密码认证 + 使用密码认证 - + Retry 重试 UnLock - 解锁 + 解锁 LoggedIn - 已登录 + 已登录 - + Password: 密码: - + + + Account locked %1 minutes due to %2 fail attempts + 账户锁定%1分钟由于%2次错误尝试 + + + Password Incorrect, Please try again 密码错误,请重试 - + + Authentication failure,there are still %1 remaining opportunities + 认证失败,还剩%1次尝试机会 + + + Biometric Authentication 生物识别认证 - + Password Authentication 密码认证 - + Other Devices 其他设备 @@ -58,49 +69,49 @@ BioDevices FingerPrint - 指纹 + 指纹 FingerVein - 指静脉 + 指静脉 Iris - 虹膜 + 虹膜 Face - 人脸 + 人脸 VoicePrint - 声纹 + 声纹 BioDevicesWidget Please select other biometric devices - 请选择其他生物识别设备 + 请选择其他生物识别设备 Device Type: - 设备类型: + 设备类型: Device Name: - 设备名称: + 设备名称: BiometricAuthWidget - + Current device: 当前设备: - + Identify failed, Please retry. 识别失败,请重试 @@ -108,22 +119,22 @@ BiometricDevicesWidget - + Please select the biometric device 请选择生物设备 - + Device type: 设备类型: - + Device name: 设备型号: - + OK 确定 @@ -131,27 +142,27 @@ DeviceType - + FingerPrint 指纹 - + FingerVein 指静脉 - + Iris 虹膜 - + Face 人脸 - + VoicePrint 声纹 @@ -182,12 +193,12 @@ - + Guest 游客 - + SwitchUser 切换用户 @@ -201,17 +212,17 @@ - + lock the screen immediately - + Dialog for the ukui ScreenSaver. - + activated by session idle signal diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0015798..5fe1506 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,7 @@ set(EXTRA_LIBS ${XTST_LIBRARIES} ${XCB_LIBRARIES} ${QGS_LIBRARIES} + -lrt ) qt5_wrap_ui(dialog_SRC @@ -35,6 +36,7 @@ qt5_add_resources(dialog_SRC # 头文件中包含了Xlib.h,需要单独拿出来处理,不知道原因 qt5_wrap_cpp(dialog_SRC + pam-tally.h fullbackgroundwidget.h lockwidget.h authdialog.h @@ -52,6 +54,7 @@ qt5_wrap_cpp(dialog_SRC set(dialog_SRC ${dialog_SRC} + pam-tally.c ukui-screensaver-dialog.cpp fullbackgroundwidget.cpp lockwidget.cpp diff --git a/src/assets/authdialog.qss b/src/assets/authdialog.qss index f3b4785..64a9038 100644 --- a/src/assets/authdialog.qss +++ b/src/assets/authdialog.qss @@ -163,7 +163,7 @@ QComboBox QListView::item:selected{ #OKButton { background: rgba(255, 255, 255, 20%); - font-size: 14px; + font-size: 18px; border: 1px solid rgba(255, 255, 255, 30%); color: white; } diff --git a/src/authdialog.cpp b/src/authdialog.cpp index a95b095..9ae260f 100644 --- a/src/authdialog.cpp +++ b/src/authdialog.cpp @@ -20,9 +20,10 @@ #include #include #include - +#include #include #include +#include #include "users.h" #include "iconedit.h" @@ -43,6 +44,8 @@ AuthDialog::AuthDialog(const UserItem &user, QWidget *parent) : { initUI(); + pam_tally_init(); + connect(auth, &Auth::showMessage, this, &AuthDialog::onShowMessage); connect(auth, &Auth::showPrompt, this, &AuthDialog::onShowPrompt); connect(auth, &Auth::authenticateComplete, this, &AuthDialog::onAuthComplete); @@ -77,9 +80,50 @@ void AuthDialog::stopAuth() } } +QPixmap AuthDialog::DrawRound(QPixmap &src, int radius) +{ + + QPixmap pixmap(src); + + QPainter painter(&pixmap); + painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + QRect drawRect = pixmap.rect(); + QPoint point(radius,radius); + QRadialGradient rg(point,drawRect.width()/2,point); + rg.setColorAt(0,Qt::transparent); + rg.setColorAt(0.93,Qt::transparent); + rg.setColorAt(0.94,Qt::white); + rg.setColorAt(1,Qt::white); + painter.setBrush(rg); + QPen pen(Qt::white);//定义画笔 + painter.setPen(pen); + painter.drawEllipse(drawRect); + + return pixmap; +} + +QPixmap AuthDialog::PixmapToRound(const QPixmap &src, int radius) +{ + if (src.isNull()) { + return QPixmap(); + } + + QPixmap pixmapa(src); + QPixmap pixmap(radius*2,radius*2); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + QPainterPath path; + path.addEllipse(0, 0, radius*2, radius*2); + painter.setClipPath(path); + painter.drawPixmap(0, 0, radius*2, radius*2, pixmapa); + return pixmap; +} + void AuthDialog::initUI() { setFixedWidth(500); + const QString SheetStyle = "min-width: 128px; min-height: 128px;max-width:128px; max-height: 128px;border-radius: 64px; border:0px solid white;"; m_userWidget = new QWidget(this); m_userWidget->setObjectName(QStringLiteral("userWidget")); @@ -88,9 +132,15 @@ void AuthDialog::initUI() m_faceLabel = new QLabel(m_userWidget); m_faceLabel->setObjectName(QStringLiteral("faceLabel")); m_faceLabel->setFocusPolicy(Qt::NoFocus); + m_faceLabel->setStyleSheet(SheetStyle); QPixmap facePixmap(user.icon); - facePixmap = facePixmap.scaled(128, 128, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - m_faceLabel->setPixmap(facePixmap); + // facePixmap = facePixmap.scaled(120, 120, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + QPixmap pixMap= facePixmap.scaled(128,128, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + //50为圆形的半径 + pixMap = PixmapToRound(pixMap, 64); + pixMap = DrawRound(pixMap,64); + m_faceLabel->setAlignment(Qt::AlignCenter); + m_faceLabel->setPixmap(pixMap); /* 用户名 */ m_nameLabel = new QLabel(m_userWidget); @@ -112,6 +162,7 @@ void AuthDialog::initUI() m_passwordEdit->installEventFilter(this); // m_passwordEdit->hide(); //收到请求密码的prompt才显示出来 m_passwordEdit->setEnabled(false); + m_passwordEdit->setType(QLineEdit::Password); connect(m_passwordEdit, SIGNAL(clicked(const QString&)), this, SLOT(onRespond(const QString&))); @@ -138,9 +189,9 @@ void AuthDialog::setChildrenGeometry() // 密码框和提示信息显示位置 m_passwdWidget->setGeometry(0, m_userWidget->geometry().bottom(), width(), 150); m_passwordEdit->setGeometry((m_passwdWidget->width() - 400)/2, 0, 400, 40); - m_messageLabel->setGeometry((m_passwdWidget->width() - 300)/2, + m_messageLabel->setGeometry((m_passwdWidget->width() - 600)/2, m_passwordEdit->geometry().bottom() + 25, - 300, 20); + 600, 20); setBiometricWidgetGeometry(); @@ -189,10 +240,6 @@ void AuthDialog::onShowPrompt(const QString &prompt, Auth::PromptType type) m_passwordEdit->setEnabled(true); m_passwordEdit->setFocus(); - if(type != Auth::PromptTypeSecret) - m_passwordEdit->setType(QLineEdit::Normal); - else - m_passwordEdit->setType(QLineEdit::Password); if(text == "Password: ") text = tr("Password: "); @@ -204,15 +251,53 @@ void AuthDialog::onShowPrompt(const QString &prompt, Auth::PromptType type) void AuthDialog::onAuthComplete() { + if(auth->isAuthenticated()) { - Q_EMIT authenticateCompete(true); + if(pam_tally_is_enbled() && !pam_tally_is_canUnlock()) + { + pam_tally_add_failed(); + int unlock_time = pam_tally_unlock_time(); + int failed_count = pam_tally_failed_count(); + int unlock_time_min = unlock_time /60; + // sprintf(msg, "您已经输错%d次,将锁定账户%d分钟", failed_count, unlock_time_min); + // onShowMessage(tr(msg), Auth::MessageTypeError); + int deny = pam_tally_deny(); + onShowMessage(tr("Account locked %1 minutes due to %2 fail attempts").arg(unlock_time_min).arg(deny), Auth::MessageTypeError); + authMode = PASSWORD; + startAuth(); + } + else + { + pam_tally_clear_failed(); + Q_EMIT authenticateCompete(true); + } + } else { onShowMessage(tr("Password Incorrect, Please try again"), Auth::MessageTypeError); //认证失败,重新认证 + + if(pam_tally_is_enbled()) + { + pam_tally_add_failed(); + int deny = pam_tally_deny(); + int failed_count = pam_tally_failed_count(); + int unlock_time = pam_tally_unlock_time(); + int unlock_time_min = unlock_time / 60; + + if (failed_count >= 0 && failed_count < deny) + { + onShowMessage(tr("Authentication failure,there are still %1 remaining opportunities").arg(deny-failed_count), Auth::MessageTypeError); + } + else if (failed_count >= deny) + { + onShowMessage(tr("Account locked %1 minutes due to %2 fail attempts").arg(unlock_time_min).arg(deny), Auth::MessageTypeError); + } + } + authMode = PASSWORD; startAuth(); } @@ -281,6 +366,17 @@ void AuthDialog::performBiometricAuth() skipBiometricAuth(); return; } + + //初始化用户对应特征数量 + m_featureCount = m_biometricProxy->GetFeatureCount(user.uid); + + qDebug()<<"m_featureCount = "<setObjectName(QStringLiteral("buttonsWidget")); - m_buttonsWidget->setFixedHeight(25); + m_buttonsWidget->setFixedHeight(38); QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); sizePolicy.setHorizontalStretch(0); @@ -368,7 +464,7 @@ void AuthDialog::initBiometricButtonWidget() m_biometricButton->setCursor(Qt::PointingHandCursor); QFontMetrics fm(m_biometricButton->font(), m_biometricButton); int width = fm.width(m_biometricButton->text()); - m_biometricButton->setMaximumWidth(width + 20); + m_biometricButton->setMaximumWidth(std::max(width + 20, 190)); connect(m_biometricButton, &QPushButton::clicked, this, &AuthDialog::onBiometricButtonClicked); @@ -377,7 +473,7 @@ void AuthDialog::initBiometricButtonWidget() m_passwordButton->setText(tr("Password Authentication")); fm = QFontMetrics(m_passwordButton->font(), m_passwordButton); width = fm.width(m_passwordButton->text()); - m_passwordButton->setMaximumWidth(std::max(width + 20, 110)); + m_passwordButton->setMaximumWidth(std::max(width + 20, 140)); m_passwordButton->setSizePolicy(sizePolicy); m_passwordButton->setVisible(false); m_passwordButton->setCursor(Qt::PointingHandCursor); @@ -388,7 +484,7 @@ void AuthDialog::initBiometricButtonWidget() m_otherDeviceButton->setObjectName(QStringLiteral("otherDeviceButton")); m_otherDeviceButton->setText(tr("Other Devices")); m_otherDeviceButton->setSizePolicy(sizePolicy); - m_otherDeviceButton->setMaximumWidth(std::max(width + 20, 110)); + m_otherDeviceButton->setMaximumWidth(std::max(width + 20, 140)); m_otherDeviceButton->setVisible(false); m_otherDeviceButton->setCursor(Qt::PointingHandCursor); connect(m_otherDeviceButton, &QPushButton::clicked, @@ -438,7 +534,7 @@ void AuthDialog::setBiometricButtonWidgetGeometry() { if(m_buttonsWidget) { - m_buttonsWidget->setGeometry(0, height() - m_buttonsWidget->height() - 20, + m_buttonsWidget->setGeometry(0, height() - m_buttonsWidget->height() - 100, width(), m_buttonsWidget->height()); } } diff --git a/src/authdialog.h b/src/authdialog.h index f38b1e8..d5d759e 100644 --- a/src/authdialog.h +++ b/src/authdialog.h @@ -27,6 +27,7 @@ #include "types.h" #include "users.h" #include "biometricdeviceinfo.h" +#include "pam-tally.h" namespace Ui { @@ -67,6 +68,8 @@ class AuthDialog : public QWidget void showPasswordAuthWidget(); void showBiometricAuthWidget(); void showBiometricDeviceWidget(); + QPixmap PixmapToRound(const QPixmap &src, int radius); + QPixmap DrawRound(QPixmap &src, int radius); private Q_SLOTS: void onShowMessage(const QString &message, Auth::MessageType type); @@ -105,6 +108,7 @@ public Q_SLOTS: // biometric auth int m_deviceCount; + int m_featureCount; QString m_deviceName; DeviceInfoPtr m_deviceInfo; BiometricProxy *m_biometricProxy; diff --git a/src/configuration.cpp b/src/configuration.cpp index 4e49be5..d547fd9 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,7 @@ Configuration::Configuration(QObject *parent) : QObject(parent) qDebug() << mode << themes; qDebug() << imageSwitchInterval << imageTSEffect; - int FileisExist = 0; + int FileisExist = 0; if(!background.isEmpty()) { QFileInfo file(background); @@ -114,7 +115,7 @@ void Configuration::onConfigurationChanged(QString key) /* Get the executable path of xscreensaver */ ScreenSaver *Configuration::getScreensaver() { - QStringList modeStr{"blank-only", "random", "single", "image","default"}; + QStringList modeStr{"blank-only", "random", "single", "image"}; ScreenSaver *saver = new ScreenSaver; int index = modeStr.indexOf(mode); @@ -123,9 +124,6 @@ ScreenSaver *Configuration::getScreensaver() saver->effect = TransitionEffect(imageTSEffect); switch(index){ - case SAVER_DEFAULT: - saver->path = getBackground(); - break; case SAVER_BLANK_ONLY: break; case SAVER_RANDOM: @@ -173,12 +171,24 @@ bool Configuration::ispicture(QString filepath) return mime.name().startsWith("image/"); } +QString getSystemVersion() +{ + QSettings settings("/etc/lsb-release", QSettings::IniFormat); + QString release = settings.value("DISTRIB_RELEASE").toString(); + QString description = settings.value("DISTRIB_DESCRIPTION").toString(); + if(description.right(3) == "LTS") + release = release + " LTS"; + return release; +} + QString Configuration::getBackground() { if(ispicture(background)) return background; - else - return "/usr/share/backgrounds/warty-final-ubuntukylin.jpg"; + else if(getSystemDistrib().contains("Ubuntu",Qt::CaseInsensitive)) + return "/usr/share/backgrounds/warty-final-ubuntukylin.jpg"; + else + return "/usr/share/backgrounds/kylin/kylin-background.png"; } bool Configuration::xscreensaverActivatedWhenIdle() diff --git a/src/configuration.h b/src/configuration.h index 076dbd6..c9fae51 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -57,8 +57,6 @@ public Q_SLOTS: bool lockEnabled; int imageTSEffect; int imageSwitchInterval; - bool ispicture(QString filepath); - }; #endif // CONFIGURATION_H diff --git a/src/fullbackgroundwidget.cpp b/src/fullbackgroundwidget.cpp index f9c8748..6ab702b 100644 --- a/src/fullbackgroundwidget.cpp +++ b/src/fullbackgroundwidget.cpp @@ -19,10 +19,10 @@ #include #include -#include #include #include #include +#include #include #include #include @@ -39,6 +39,8 @@ #include #include #include + +#include #include "lockwidget.h" #include "xeventmonitor.h" #include "monitorwatcher.h" @@ -126,14 +128,16 @@ FullBackgroundWidget::FullBackgroundWidget(QWidget *parent) screenStatus(UNDEFINED) { qDebug() << "init - screenStatus: " << screenStatus; - + setMouseTracking(true); connect(monitorWatcher, &MonitorWatcher::monitorCountChanged, this, &FullBackgroundWidget::onScreenCountChanged); QDesktopWidget *desktop = QApplication::desktop(); - connect(desktop, &QDesktopWidget::workAreaResized, - this, &FullBackgroundWidget::onDesktopResized); + connect(desktop, &QDesktopWidget::resized, this, &FullBackgroundWidget::onDesktopResized); + connect(desktop, &QDesktopWidget::workAreaResized, + this, &FullBackgroundWidget::onDesktopResized); + QDBusInterface *iface = new QDBusInterface("org.freedesktop.login1", "/org/freedesktop/login1", @@ -141,9 +145,21 @@ FullBackgroundWidget::FullBackgroundWidget(QWidget *parent) QDBusConnection::systemBus(), this); connect(iface, SIGNAL(PrepareForSleep(bool)), this, SLOT(onPrepareForSleep(bool))); - - QTimer::singleShot(500,this,SLOT(switchToLinux())); + init(); + qApp->installNativeEventFilter(this); +/* + QString username = getenv("USER"); + int uid = getuid(); + QDBusInterface *interface = new QDBusInterface("cn.kylinos.Kydroid2", + "/cn/kylinos/Kydroid2", + "cn.kylinos.Kydroid2", + QDBusConnection::systemBus(), + this); + + QDBusMessage msg = interface->call(QStringLiteral("SetPropOfContainer"),username, uid, "is_kydroid_on_focus", "0"); +*/ + QTimer::singleShot(500,this,SLOT(switchToLinux())); } void FullBackgroundWidget::switchToLinux() @@ -159,12 +175,25 @@ void FullBackgroundWidget::switchToLinux() switch_to_linux(container); } + void FullBackgroundWidget::paintEvent(QPaintEvent *event) { - for(auto screen : QGuiApplication::screens()) + QDesktopWidget *desktop = QApplication::desktop(); + if(!desktop->isVirtualDesktop()) { + int width=0,height = 0; + x11_get_screen_size(&width,&height); QPainter painter(this); - painter.drawPixmap(screen->geometry(), background); + QRect rec(0,0,width,height); + painter.drawPixmap(rec, background); + } + else + { + for(auto screen : QGuiApplication::screens()) + { + QPainter painter(this); + painter.drawPixmap(screen->geometry(), background); + } } return QWidget::paintEvent(event); } @@ -184,18 +213,53 @@ void FullBackgroundWidget::closeEvent(QCloseEvent *event) void FullBackgroundWidget::showEvent(QShowEvent *event) { - XSetWindowAttributes top_attrs; - top_attrs.override_redirect = False; -// XChangeWindowAttributes(QX11Info::display(), this->winId(), CWOverrideRedirect, &top_attrs); - XRaiseWindow(QX11Info::display(), this->winId()); + // XSetWindowAttributes top_attrs; + // top_attrs.override_redirect = False; + // XChangeWindowAttributes(QX11Info::display(), this->winId(), CWOverrideRedirect, &top_attrs); + // XRaiseWindow(QX11Info::display(), this->winId()); + // raise(); + return QWidget::showEvent(event); } + +bool FullBackgroundWidget::nativeEventFilter(const QByteArray &eventType, void *message, long *result) +{ + if (qstrcmp(eventType, "xcb_generic_event_t") != 0) { + return false; + } + xcb_generic_event_t *event = reinterpret_cast(message); + const uint8_t responseType = event->response_type & ~0x80; + if (responseType == XCB_CONFIGURE_NOTIFY) { + xcb_configure_notify_event_t *xc = reinterpret_cast(event); + if (xc->event == QX11Info::appRootWindow()) + { + this->onDesktopResized(); + XRaiseWindow(QX11Info::display(), this->winId()); + XFlush(QX11Info::display()); + } + return false; + } + else if(responseType == XCB_PROPERTY_NOTIFY) + { + XRaiseWindow(QX11Info::display(), this->winId()); + XFlush(QX11Info::display()); + } + return false; +} + +void FullBackgroundWidget::mouseMoveEvent(QMouseEvent *e) +{ + onCursorMoved(cursor().pos()); + return QWidget::mouseMoveEvent(e); +} + void FullBackgroundWidget::init() { setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); // setAttribute(Qt::WA_DeleteOnClose); +/*捕获键盘,如果捕获失败,则可能是由于弹出菜单项已经捕获,那么模拟一次esc按键来退出菜单,如果仍捕获失败,则放弃锁屏,避免密码无法输入*/ if(establishGrab()) qDebug()<<"establishGrab : true"; else { @@ -204,7 +268,10 @@ void FullBackgroundWidget::init() XTestFakeKeyEvent(QX11Info::display(), XKeysymToKeycode(QX11Info::display(),XK_Escape), False, 1); XFlush(QX11Info::display()); sleep(1); - establishGrab(); + if(!establishGrab()) + { + exit(1); + } } // 监听session信号 smInterface = new QDBusInterface(SM_DBUS_SERVICE, @@ -243,11 +310,13 @@ void FullBackgroundWidget::onCursorMoved(const QPoint &pos) } for(auto screen : QGuiApplication::screens()) { - if(screen->geometry().contains(pos)) - { - lockWidget->setGeometry(screen->geometry()); - break; - } + if(screen->geometry().contains(pos)) + { + // lockWidget->hide(); //避免闪屏,所以先隐藏,设置大小后再显示 + lockWidget->setGeometry(screen->geometry()); + // lockWidget->show(); + break; + } } } @@ -273,7 +342,7 @@ void FullBackgroundWidget::showLockWidget() onCursorMoved(cursor().pos()); } lockWidget->setFocus(); - XSetInputFocus(QX11Info::display(),this->winId(),RevertToNone,CurrentTime); + XSetInputFocus(QX11Info::display(),this->winId(),RevertToParent,CurrentTime); } void FullBackgroundWidget::showScreensaver() @@ -296,6 +365,8 @@ void FullBackgroundWidget::showScreensaver() { lockWidget->stopAuth(); } + // XSetInputFocus(QX11Info::display(),this->winId(),RevertToNone,CurrentTime); + } void FullBackgroundWidget::clearScreensavers() @@ -320,6 +391,7 @@ void FullBackgroundWidget::clearScreensavers() { lock(); } + } int FullBackgroundWidget::onSessionStatusChanged(uint status) @@ -365,7 +437,6 @@ int FullBackgroundWidget::onSessionStatusChanged(uint status) void FullBackgroundWidget::onGlobalKeyPress(const QString &key) { - } void FullBackgroundWidget::onGlobalKeyRelease(const QString &key) @@ -382,6 +453,7 @@ void FullBackgroundWidget::onGlobalKeyRelease(const QString &key) { clearScreensavers(); } + } void FullBackgroundWidget::onGlobalButtonDrag(int xPos, int yPos) @@ -397,17 +469,43 @@ void FullBackgroundWidget::onScreenCountChanged(int) { QSize newSize = monitorWatcher->getVirtualSize(); setGeometry(0, 0, newSize.width(), newSize.height()); - repaint(); + //repaint(); + update(); clearScreensavers(); } void FullBackgroundWidget::onDesktopResized() { QDesktopWidget *desktop = QApplication::desktop(); - setGeometry(desktop->geometry()); - repaint(); + if(!desktop->isVirtualDesktop()) + { + int width=0,height = 0; + x11_get_screen_size(&width,&height); + if(width==0||height==0) + { + setGeometry(desktop->geometry()); + if(lockWidget) + lockWidget->setGeometry(QApplication::primaryScreen()->geometry()); + } + else + { + qDebug()<<"width = "<setGeometry(0,0,width,height); + } + } + else{ + qDebug()<<"desktop"<geometry(); + setGeometry(desktop->geometry()); + if(lockWidget) + onCursorMoved(cursor().pos()); + } + // clearScreensavers(); - lockWidget->setGeometry(QApplication::primaryScreen()->geometry()); + //repaint(); + update(); + } void FullBackgroundWidget::onPrepareForSleep(bool sleep) diff --git a/src/fullbackgroundwidget.h b/src/fullbackgroundwidget.h index be8463f..b47b93d 100644 --- a/src/fullbackgroundwidget.h +++ b/src/fullbackgroundwidget.h @@ -24,6 +24,7 @@ #include #include "types.h" +#include class LockWidget; class XEventMonitor; @@ -31,7 +32,7 @@ class MonitorWatcher; class Configuration; class QDBusInterface; -class FullBackgroundWidget : public QWidget +class FullBackgroundWidget : public QWidget , public QAbstractNativeEventFilter { Q_OBJECT public: @@ -39,6 +40,9 @@ class FullBackgroundWidget : public QWidget void paintEvent(QPaintEvent *event); void closeEvent(QCloseEvent *event); void showEvent(QShowEvent *event); + virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override; + void mouseMoveEvent(QMouseEvent *e); + public Q_SLOTS: void onCursorMoved(const QPoint &pos); void lock(); diff --git a/src/iconedit.cpp b/src/iconedit.cpp index c6807f9..7c4ad11 100644 --- a/src/iconedit.cpp +++ b/src/iconedit.cpp @@ -28,6 +28,7 @@ #include #include + /** * @brief 判断大写键状态 * @return true: 大写锁定 @@ -90,6 +91,10 @@ IconEdit::IconEdit(QWidget *parent) void IconEdit::setType(QLineEdit::EchoMode type) { m_edit->setEchoMode(type); + if(type == 0) + m_modeButton->setChecked(true); + else + m_modeButton->setChecked(false); } @@ -110,9 +115,9 @@ bool IconEdit::eventFilter(QObject *obj, QEvent *event) return true; } } - if(event->type() == 23) + if(event->type() == 23) { - XSetInputFocus(QX11Info::display(),this->winId(),RevertToNone,CurrentTime); + XSetInputFocus(QX11Info::display(),this->winId(),RevertToParent,CurrentTime); } } return false; @@ -120,7 +125,6 @@ bool IconEdit::eventFilter(QObject *obj, QEvent *event) void IconEdit::clicked_cb() { -// m_iconButton->setFocus(); //按回车后输入框光标会消失或者不再闪烁,先让其他控件获取焦点,就会解决该问题 startWaiting(); emit clicked(m_edit->text()); } @@ -209,6 +213,7 @@ void IconEdit::updatePixmap() void IconEdit::setEnabled(bool enabled) { + m_edit->setAttribute(Qt::WA_InputMethodEnabled, false); m_edit->setEnabled(enabled); m_iconButton->setEnabled(enabled); } diff --git a/src/interface.cpp b/src/interface.cpp index 9abc8dc..9e217af 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -28,7 +28,7 @@ Interface::Interface(QObject *parent) m_logind = new LogindIntegration(this); connect(m_logind, &LogindIntegration::requestLock, this, [this]() { - this->Lock(); + this->onSessionIdleReceived(); } ); connect(m_logind, &LogindIntegration::requestUnlock, this, @@ -58,29 +58,22 @@ void Interface::Lock() { qDebug() << "Lock requested"; - if(!checkExistChild()) - { - QString cmd = QString("/usr/bin/ukui-screensaver-dialog --lock"); - qDebug() << cmd; + QString cmd = QString("/usr/bin/ukui-screensaver-dialog --lock"); + qDebug() << cmd; + process.startDetached(cmd); - process.startDetached(cmd); - - } } void Interface::onSessionIdleReceived() { qDebug() << "emit SessionIdle"; - if(!checkExistChild()) - { - QString cmd = QString("/usr/bin/ukui-screensaver-dialog --session-idle"); - qDebug() << cmd; + QString cmd = QString("/usr/bin/ukui-screensaver-dialog --session-idle"); + qDebug() << cmd; - process.startDetached(cmd); + process.startDetached(cmd); - } } bool Interface::checkExistChild() diff --git a/src/lockwidget.cpp b/src/lockwidget.cpp index 83b33e4..07c313f 100644 --- a/src/lockwidget.cpp +++ b/src/lockwidget.cpp @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include "authdialog.h" #include "virtualkeyboard.h" @@ -43,6 +46,7 @@ LockWidget::LockWidget(QWidget *parent) this, &LockWidget::closed); connect(this, &LockWidget::capsLockChanged, authDialog, &AuthDialog::onCapsLockChanged); + this->installEventFilter(this); initUI(); } @@ -58,6 +62,18 @@ void LockWidget::closeEvent(QCloseEvent *event) return QWidget::closeEvent(event); } +bool LockWidget::eventFilter(QObject *obj, QEvent *event) +{ + if(obj == this){ + if(event->type() == 2){ + if(usersMenu->isVisible()) + usersMenu->hide(); + return false; + } + } + return false; +} + void LockWidget::startAuth() { if(authDialog) @@ -108,11 +124,14 @@ void LockWidget::initUI() ui->btnKeyboard->setIcon(QIcon(":/image/assets/keyboard.png")); ui->btnKeyboard->setFixedSize(39, 39); ui->btnKeyboard->setIconSize(QSize(39, 39)); - connect(ui->btnKeyboard, &QPushButton::clicked, +/* connect(ui->btnKeyboard, &QPushButton::clicked, this, [&]{ qDebug() << vKeyboard->isHidden(); vKeyboard->setVisible(vKeyboard->isHidden()); }); +*/ + connect(ui->btnKeyboard, &QPushButton::clicked, + this, &LockWidget::showVirtualKeyboard); //用户切换 if(displayManager->canSwitch()) @@ -121,18 +140,47 @@ void LockWidget::initUI() } } +void LockWidget::showVirtualKeyboard() +{ + vKeyboard->setVisible(vKeyboard->isHidden()); + setVirkeyboardPos(); +} + +void LockWidget::setVirkeyboardPos() +{ + if(vKeyboard) + { + vKeyboard->setGeometry(0, + height() - height()/3, + width(), height()/3); + + } +} + + void LockWidget::initUserMenu() { ui->btnSwitchUser->setIcon(QIcon(":/image/assets/avatar.png")); ui->btnSwitchUser->setIconSize(QSize(39, 39)); ui->btnSwitchUser->setFixedSize(39, 39); - if(!usersMenu) { usersMenu = new QMenu(this); - ui->btnSwitchUser->setMenu(usersMenu); + + //如果没有设置x11属性,则由于弹出菜单受窗口管理器管理,而主窗口不受,在点击菜单又点回主窗口会闪屏。 + usersMenu->setWindowFlags(Qt::X11BypassWindowManagerHint); + usersMenu->hide(); + usersMenu->move(width() - 150, 60); + // ui->btnSwitchUser->setMenu(usersMenu); connect(usersMenu, &QMenu::triggered, this, &LockWidget::onUserMenuTrigged); + connect(ui->btnSwitchUser, &QPushButton::clicked, + this, [&]{ + if(usersMenu->isVisible()) + usersMenu->hide(); + else + usersMenu->show(); + }); } connect(users, &Users::userAdded, this, &LockWidget::onUserAdded); @@ -157,7 +205,7 @@ void LockWidget::initUserMenu() action->setData("SwitchUser"); usersMenu->addAction(action); } - + } /* lockscreen follows cursor */ @@ -174,6 +222,12 @@ void LockWidget::resizeEvent(QResizeEvent */*event*/) ui->btnKeyboard->move(width() - 60, 20); ui->btnSwitchUser->move(width() - 120, 20); + + setVirkeyboardPos(); + usersMenu->move(width() - 150, 60); + XSetInputFocus(QX11Info::display(),this->winId(),RevertToParent,CurrentTime); + + } diff --git a/src/lockwidget.h b/src/lockwidget.h index 2ce6ba8..e4904c3 100644 --- a/src/lockwidget.h +++ b/src/lockwidget.h @@ -54,11 +54,16 @@ class LockWidget : public QWidget private: void initUI(); void initUserMenu(); + void setVirkeyboardPos(); private Q_SLOTS: void onUserAdded(const UserItem &user); void onUserDeleted(const UserItem &user); void onUserMenuTrigged(QAction *action); + void showVirtualKeyboard(); + +protected: + bool eventFilter(QObject *obj, QEvent *event); private: Ui::LockWidget *ui; diff --git a/src/pam-tally.c b/src/pam-tally.c new file mode 100644 index 0000000..53bd377 --- /dev/null +++ b/src/pam-tally.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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, 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, see . + * +**/ + +#include "pam-tally.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +//#include "gs-debug.h" + +char shm_tally_real[128]; + +#define FILE_MODE (S_IRUSR | S_IWUSR) + +#define CONFIG_FILE "/usr/share/lightdm/lightdm.conf.d/96-kylin-setting.conf" + + + +static +int get_is_open_other_authentication() +{ + char buf[128]; + FILE *config_file; + + if( (config_file = fopen(CONFIG_FILE, "r")) == NULL) + { + //gs_debug("open %s failed", CONFIG_FILE); + return 0; + } + + int open_other_authentication = 0; + while(fgets(buf, sizeof(buf), config_file)) { + if(strlen(buf) == 0 || buf[0] == '#') + { + memset(buf, sizeof(buf), 0); + continue; + } + if(buf[strlen(buf)-1] == '\n') + buf[strlen(buf)-1] = '\0'; + + char *p = strchr(buf, '='); + if(!p) + continue; + *p = '\0'; + + size_t len = strlen(buf); + if(len == 0) + continue; + //去掉=之前的空格 + while(len--) + if(buf[len] == ' ' || buf[len] == '\t') + buf[len] = '\0'; + if(strcmp(buf, "open-other-authentication") != 0) + continue; + + p++; + len = strlen(p); + if(len == 0) + break; + //去掉等号之后的空格 + while(*p == ' ' || *p == '\t') + { + p++; + len--; + } + //去掉尾部空格 + while(len--) + if(*(p+len) == ' ' || *(p+len) == '\t') + *(p+len) = '\0'; + + if(*p == '0') + break; + if(*p == '1') + { + open_other_authentication = 1; + break; + } + } + fclose(config_file); + //gs_debug("--------------------------%d", open_other_authentication); + return open_other_authentication; +} + +static +int get_pam_tally(int *deny, int *unlock_time) +{ + char buf[128]; + FILE *auth_file; + + if( (auth_file = fopen("/etc/pam.d/common-auth", "r")) == NULL) + return -1; + + while(fgets(buf, sizeof(buf), auth_file)) { + if(strlen(buf) == 0 || buf[0] == '#') + continue; + if(!strstr(buf, "deny")) + continue; + + char *ptr = strtok(buf, " \t"); + while(ptr) { + if(strncmp(ptr, "deny=", 5)==0){ + sscanf(ptr, "deny=%d", deny); + //gs_debug("-------------------- deny=%d", *deny); + } + if(strncmp(ptr, "unlock_time=", 12)==0){ + sscanf(ptr, "unlock_time=%d", unlock_time); + //gs_debug("-------------------- unlock_time=%d", *unlock_time); + } + ptr = strtok(NULL, " \t"); + } + return 1; + } + return 0; +} + +static +void set_shm_tally_real() +{ + sprintf(shm_tally_real, "%s_%d", SHM_TALLY, getuid()); +} + +int pam_tally_init() +{ + int fd; + int deny = 0, unlock_time = 0; + pam_tally *tally_ptr; + + set_shm_tally_real(); + + printf("shm path =========== : %s\n", shm_tally_real); + + shm_unlink(shm_tally_real); + + if(get_is_open_other_authentication()) + { + //gs_debug("open other authentication, disable pam_tally."); + return 0; + } + if(!get_pam_tally(&deny, &unlock_time)) + { + //gs_debug("get pam_tally configuration failed, disable pam_tally."); + return 0; + } + + /* if(deny <= 0) + deny = 3; + if(unlock_time <= 0) + unlock_time = 1800; +*/ + if( (fd = shm_open(shm_tally_real, O_RDWR | O_CREAT, FILE_MODE)) == -1) + { + printf("shm_open error: %s\n", strerror(errno)); + return -1; + } + + ftruncate(fd, sizeof(pam_tally)); + + if( (tally_ptr = mmap(NULL, sizeof(pam_tally), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) + { + //gs_debug("mmap error: %s", strerror(errno)); + close(fd); + return -1; + } + close(fd); + + tally_ptr->deny = deny; + tally_ptr->unlock_time = unlock_time; + tally_ptr->failed = 0; + tally_ptr->lock_start_time = 0; + + return 1; +} + +static +pam_tally* pam_tally_memory() +{ + int fd; + pam_tally *tally_ptr; + + set_shm_tally_real(); + + if( (fd = shm_open(shm_tally_real, O_RDWR, FILE_MODE)) == -1) + { + //gs_debug("shm_open error: %s", strerror(errno)); + return NULL; + } + + if( (tally_ptr = mmap(NULL, sizeof(pam_tally), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) + { + //gs_debug("mmap error: %s", strerror(errno)); + close(fd); + return NULL; + } + close(fd); + return tally_ptr; +} + +int pam_tally_is_enbled() +{ + int fd; + + set_shm_tally_real(); + + if( (fd = shm_open(shm_tally_real, O_RDONLY, FILE_MODE)) == -1) + { + printf("shm_open error: %s\n", strerror(errno)); + return 0; + } + + pam_tally *tally_ptr; + + if((tally_ptr = pam_tally_memory()) == NULL) + return -1; + + if(tally_ptr->deny == 0 || tally_ptr->unlock_time == 0) + return 0; + return 1; +} + +int pam_tally_add_failed() +{ + pam_tally *tally_ptr; + + if((tally_ptr = pam_tally_memory()) == NULL) + return -1; + + tally_ptr->failed++; + + //如果失败次数达到上限,开始计时 + if(tally_ptr->failed >= tally_ptr->deny) + tally_ptr->lock_start_time = time(NULL); + + return 0; +} + +int pam_tally_clear_failed() +{ + pam_tally *tally_ptr; + + if((tally_ptr = pam_tally_memory()) == NULL) + return -1; + + tally_ptr->failed = 0; + tally_ptr->lock_start_time = 0; + return 0; +} + +int pam_tally_failure_is_out() +{ + pam_tally *tally_ptr; + + if((tally_ptr = pam_tally_memory()) == NULL) + return -1; + + return (tally_ptr->failed >= tally_ptr->deny ? 1 : 0); +} + +int pam_tally_deny() +{ + pam_tally *tally_ptr; + + if((tally_ptr = pam_tally_memory()) == NULL) + return -1; + + return tally_ptr->deny; +} + +int pam_tally_failed_count() +{ + pam_tally *tally_ptr; + + if((tally_ptr = pam_tally_memory()) == NULL) + return -1; + + return tally_ptr->failed; +} + +int pam_tally_unlock_time() +{ + pam_tally *tally_ptr; + + if((tally_ptr = pam_tally_memory()) == NULL) + return -1; + + printf("########################### unlock time = %d\n", tally_ptr->unlock_time); + return tally_ptr->unlock_time; +} + +int pam_tally_is_canUnlock() +{ + pam_tally *tally_ptr; + + if((tally_ptr = pam_tally_memory()) == NULL) + return -1; + + if(tally_ptr->failed >= tally_ptr->deny && + time(NULL) - tally_ptr->lock_start_time < tally_ptr->unlock_time) + return 0; + return 1; +} diff --git a/src/pam-tally.h b/src/pam-tally.h new file mode 100644 index 0000000..19c52d6 --- /dev/null +++ b/src/pam-tally.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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, 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, see . + * +**/ +#ifndef PAM_TALLY_H +#define PAM_TALLY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SHM_TALLY "/shm_tally" +struct _pam_tally { + int deny; //失败次数上限 + int unlock_time; //失败次数达到上限后,多少秒之后才能解锁 + int failed; //当前失败的次数 + time_t lock_start_time; //失败次数达到上限后,开始计时 +}; +typedef struct _pam_tally pam_tally; + +int pam_tally_init(); +int pam_tally_add_failed(); +int pam_tally_clear_failed(); +int pam_tally_falure_is_out(); +int pam_tally_deny(); +int pam_tally_failed_count(); +int pam_tally_unlock_time(); +int pam_tally_is_enbled(); +int pam_tally_is_canUnlock(); +#ifdef __cplusplus +} +#endif + +#endif // PAM_TALLY_H diff --git a/src/screensaver.cpp b/src/screensaver.cpp index 9531029..601b325 100644 --- a/src/screensaver.cpp +++ b/src/screensaver.cpp @@ -62,8 +62,6 @@ bool ScreenSaver::exists() return QFile(path).exists(); case SAVER_IMAGE: return QDir(path).exists(); - case SAVER_DEFAULT: - return true; } } @@ -113,7 +111,7 @@ bool ScreenSaver::timerStatus() QDebug &operator<<(QDebug debug, const ScreenSaver &screensaver) { - QString modes[] = {"blank-only", "random", "single", "image","default"}; + QString modes[] = {"blank-only", "random", "single", "image"}; QString effects[] = {"none", "fade-in-out"}; debug.nospace()<< "screensaver: "<< modes[screensaver.mode]; switch(screensaver.mode) { @@ -125,8 +123,6 @@ QDebug &operator<<(QDebug debug, const ScreenSaver &screensaver) break; case SAVER_IMAGE: debug.nospace() << screensaver.path << effects[screensaver.effect] << screensaver.interval; - case SAVER_DEFAULT: - break; } return debug.maybeSpace(); diff --git a/src/screensaver.h b/src/screensaver.h index d140d27..66a4a91 100644 --- a/src/screensaver.h +++ b/src/screensaver.h @@ -27,8 +27,7 @@ enum SaverMode SAVER_BLANK_ONLY = 0, SAVER_RANDOM, SAVER_SINGLE, - SAVER_IMAGE, - SAVER_DEFAULT + SAVER_IMAGE }; enum TransitionEffect diff --git a/src/screensaverwidget.cpp b/src/screensaverwidget.cpp index 595335c..9a679e1 100644 --- a/src/screensaverwidget.cpp +++ b/src/screensaverwidget.cpp @@ -16,17 +16,10 @@ * **/ #include "screensaverwidget.h" -#include "configuration.h" #include #include #include -#include #include -#include -#include -#include -#include -#include #include #include #include @@ -43,12 +36,13 @@ ScreenSaverWidget::ScreenSaverWidget(ScreenSaver *screensaver, QWidget *parent) qDebug() << *screensaver; setMouseTracking(true); setFocus(); - this->installEventFilter(this); + this->installEventFilter(this); QPalette plt; plt.setBrush(QPalette::Window, Qt::black); setPalette(plt); setAutoFillBackground(true); + switch(screensaver->mode) { case SAVER_RANDOM: case SAVER_SINGLE: @@ -69,17 +63,10 @@ ScreenSaverWidget::ScreenSaverWidget(ScreenSaver *screensaver, QWidget *parent) this, &ScreenSaverWidget::onBackgroundChanged); break; } - case SAVER_DEFAULT: - initUI(); - break; } show(); } -ScreenSaverWidget::~ScreenSaverWidget() -{ - -} void ScreenSaverWidget::closeEvent(QCloseEvent *event) { qDebug() << "ScreenSaverWidget::closeEvent---beginStop"; @@ -97,28 +84,6 @@ void ScreenSaverWidget::closeEvent(QCloseEvent *event) return QWidget::closeEvent(event); } -QImage ScreenSaverWidget::Bright1(QImage &image,int brightness) -{ - uchar *line =image.scanLine(0); - uchar *pixel = line; - - for (int y = 0; y < image.height(); ++y) - { - pixel = line; - for (int x = 0; x < image.width(); ++x) - { - *pixel = qBound(0, *pixel + brightness, 255); - *(pixel + 1) = qBound(0, *(pixel + 1) + brightness, 255); - *(pixel + 2) = qBound(0, *(pixel + 2) + brightness, 255); - pixel += 4; - } - - line += image.bytesPerLine(); - } - return image; - -} - void ScreenSaverWidget::paintEvent(QPaintEvent *event) { if(!screensaver->exists()) @@ -126,18 +91,6 @@ void ScreenSaverWidget::paintEvent(QPaintEvent *event) QPainter painter(this); painter.fillRect(geometry(), Qt::black); } - if(screensaver->mode == SAVER_DEFAULT) - { - QPixmap pixmap(screensaver->path); - QImage tempImage = pixmap.toImage(); - tempImage = Bright1(tempImage,-80); - pixmap = QPixmap::fromImage(tempImage); - pixmap.scaled(size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - QPainter painter(this); - - painter.setOpacity(0.8); - painter.drawPixmap(geometry(), pixmap); - } if(screensaver->mode == SAVER_IMAGE) { switch(screensaver->effect) { case TRANSITION_NONE: @@ -173,11 +126,12 @@ bool ScreenSaverWidget::eventFilter(QObject *obj, QEvent *event) { if(event->type() == 23) { - XSetInputFocus(QX11Info::display(),this->winId(),RevertToNone,CurrentTime); + XSetInputFocus(QX11Info::display(),this->winId(),RevertToParent,CurrentTime); } return false; } + /* Embed xscreensavers */ void ScreenSaverWidget::embedXScreensaver(const QString &path) { @@ -215,126 +169,3 @@ void ScreenSaverWidget::onBackgroundChanged(const QString &/*path*/) } } -QString ScreenSaverWidget::getlocktime() -{ - - QString ssec,sminu,shour; - QString res; - if(sec>=60) - { - minu+=1; - sec-=60; - } - if(minu>=60) - { - hour+=1; - minu-=60; - } - - if(sec<10){ - ssec.setNum(sec); - ssec = "0" + ssec; - } - else { - ssec.setNum(sec); - } - - if(minu<10){ - sminu.setNum(minu); - sminu = "0" + sminu; - } - else { - sminu.setNum(minu); - } - - if(hour<10){ - shour.setNum(hour); - shour = "0" + shour; - } - else { - shour.setNum(hour); - } - res = tr("You have rested") + ":" + shour + ":" + sminu + ":"+ssec; - return res; -} - -void ScreenSaverWidget::initUI() -{ - for(auto screen : QGuiApplication::screens()) - { - this->setGeometry(screen->geometry()); - - } - - - setAutoFillBackground(true); - QPalette pal = this->palette(); - pal.setBrush(QPalette::Background, Qt::black); - setPalette(pal); - - timer = new QTimer(this); - lblTime = new QLabel (this); - lblDate = new QLabel (this); - lblWeek = new QLabel (this); - lbllocktime = new QLabel (this); - connect(timer, &QTimer::timeout, this, [&]{ - QString time = QDateTime::currentDateTime().toString("hh:mm:ss"); - lblTime->setText(time); - QString date = QDate::currentDate().toString("yyyy/MM/dd dddd"); - QStringList datelist = date.split(" "); - lblDate->setText(datelist.at(0)); - lblWeek->setText(datelist.at(1)); - }); - - QString time = QDateTime::currentDateTime().toString("hh:mm:ss"); - lblTime->setText(time); - lblTime->setStyleSheet("QLabel{color:white; font-size: 70px;}"); - lblTime->adjustSize(); - int y = this->geometry().height()/8 + 60; - int x = (this->geometry().width()-lblTime->width())/2; - lblTime->setGeometry(x,y,lblTime->width(),lblTime->height()); - timer->start(1000); - - QString date = QDate::currentDate().toString("yyyy/MM/dd dddd"); - QStringList datelist = date.split(" "); - lblDate->setText(datelist.at(0)) ; - lblDate->setStyleSheet("QLabel{color:white; font-size: 30px;}"); - lblDate->adjustSize(); - y = this->geometry().height()/8 + 170; - x = (this->geometry().width()-lblDate->width())/2; - lblDate->setGeometry(x,y,lblDate->width(),lblDate->height()); - - lblWeek->setText(datelist.at(1)); - lblWeek->setStyleSheet("QLabel{color:white; font-size: 40px;}"); - lblWeek->adjustSize(); - y = this->geometry().height()/8; - x = (this->geometry().width()-lblWeek->width())/2; - lblWeek->setGeometry(x,y,lblWeek->width(),lblWeek->height()); - - label = new QLabel(this); - label->setText("因为有梦,所以披星戴月\n因为有梦,所以奋不顾身"); - label->setStyleSheet("QLabel{color:white; font-size: 55px;}"); - label->adjustSize(); - y = this->geometry().height()/6 + 240; - x = (this->geometry().width()-label->width())/2; - label->setGeometry(x,y,label->width(),label->height()); - - tim = new QTimer(this); - qDebug()<<"sec = "<setText(locktime); - sec += 1; - }); - tim->start(1000); - QString locktime = getlocktime(); - lbllocktime->setText(locktime); - lbllocktime->setStyleSheet("QLabel{color:white; font-size: 40px;}"); - lbllocktime->adjustSize(); - y = this->geometry().height()-lbllocktime->height()-50; - x = this->geometry().width()-lbllocktime->width() - 50; - - lbllocktime->setGeometry(x,y,lbllocktime->width(),lbllocktime->height()); - - -} diff --git a/src/screensaverwidget.h b/src/screensaverwidget.h index f24682e..5bd7fcd 100644 --- a/src/screensaverwidget.h +++ b/src/screensaverwidget.h @@ -19,8 +19,7 @@ #define SCREENSAVERWIDGET_H #include -#include -#include + #include "screensaver.h" @@ -38,29 +37,16 @@ class ScreenSaverWidget : public QWidget bool eventFilter(QObject *obj, QEvent *event); private: void embedXScreensaver(const QString &path); - void initUI(); - QImage Bright1(QImage& source, int factor); - QString getlocktime(); private Q_SLOTS: void onBackgroundChanged(const QString &path); private: - QTimer *timer; - QTimer *tim; - QLabel *lblTime; - QLabel *lblDate; - QLabel *lblWeek; - QLabel *label; - QLabel *lbllocktime; int xscreensaverPid; ScreenSaver *screensaver; bool closing; float opacity; - int sec = 0,minu = 0,hour = 0; - - }; #endif // SCREENSAVERWIDGET_H diff --git a/src/users.cpp b/src/users.cpp index a6692c4..2b1ccbe 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -156,7 +156,7 @@ UserItem Users::getUser(const QString &path) void Users::onUserAdded(const QDBusObjectPath& path) { int index = findUserByPath(path.path()); - if(index != -1) + if(index >=0 &&index= 0 && index Date: Thu, 9 Jan 2020 21:05:36 +0800 Subject: [PATCH 2/3] remove VirtualKeyboard --- VirtualKeyboard | 1 - 1 file changed, 1 deletion(-) delete mode 160000 VirtualKeyboard diff --git a/VirtualKeyboard b/VirtualKeyboard deleted file mode 160000 index 5b620e1..0000000 --- a/VirtualKeyboard +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5b620e1437fa56738b00b635e0563de745b22c79 From 0df3848f7673e55c3f76134e73e2658ca079d2a3 Mon Sep 17 00:00:00 2001 From: liuyuanpeng Date: Thu, 9 Jan 2020 21:06:35 +0800 Subject: [PATCH 3/3] add VirtualKeyboard --- VirtualKeyboard/CMakeLists.txt | 24 + VirtualKeyboard/README.md | 1 + VirtualKeyboard/VirtualKeyboard.pri | 19 + VirtualKeyboard/VirtualKeyboard.pro | 32 + VirtualKeyboard/src/cursormonitor.cpp | 66 + VirtualKeyboard/src/cursormonitor.h | 36 + VirtualKeyboard/src/images/backspace.svg | 1 + .../src/images/backspace_click.svg | 1 + VirtualKeyboard/src/images/capslock.svg | 1 + VirtualKeyboard/src/images/capslock_click.svg | 1 + VirtualKeyboard/src/images/capslock_hl.svg | 1 + .../src/images/capslock_hl_click.svg | 1 + VirtualKeyboard/src/images/close.svg | 25 + VirtualKeyboard/src/images/close_click.svg | 27 + VirtualKeyboard/src/images/down.svg | 1 + VirtualKeyboard/src/images/down_click.svg | 1 + VirtualKeyboard/src/images/enter.svg | 12 + VirtualKeyboard/src/images/enter_click.svg | 12 + VirtualKeyboard/src/images/left.svg | 1 + VirtualKeyboard/src/images/left_click.svg | 1 + VirtualKeyboard/src/images/right.svg | 1 + VirtualKeyboard/src/images/right_click.svg | 1 + VirtualKeyboard/src/images/super.svg | 1 + VirtualKeyboard/src/images/super_click.svg | 1 + VirtualKeyboard/src/images/up.svg | 1 + VirtualKeyboard/src/images/up_click.svg | 13 + VirtualKeyboard/src/keyboard.qrc | 27 + VirtualKeyboard/src/keyboard.qss | 37 + VirtualKeyboard/src/keyboardwidget.cpp | 448 +++++++ VirtualKeyboard/src/keyboardwidget.h | 77 ++ VirtualKeyboard/src/keyboardwidget.ui | 1190 +++++++++++++++++ VirtualKeyboard/src/main.cpp | 31 + VirtualKeyboard/src/virtualkeyboard.cpp | 79 ++ VirtualKeyboard/src/virtualkeyboard.h | 47 + VirtualKeyboard/src/x11keyboard.cpp | 208 +++ VirtualKeyboard/src/x11keyboard.h | 116 ++ 36 files changed, 2542 insertions(+) create mode 100644 VirtualKeyboard/CMakeLists.txt create mode 100644 VirtualKeyboard/README.md create mode 100644 VirtualKeyboard/VirtualKeyboard.pri create mode 100644 VirtualKeyboard/VirtualKeyboard.pro create mode 100644 VirtualKeyboard/src/cursormonitor.cpp create mode 100644 VirtualKeyboard/src/cursormonitor.h create mode 100644 VirtualKeyboard/src/images/backspace.svg create mode 100644 VirtualKeyboard/src/images/backspace_click.svg create mode 100644 VirtualKeyboard/src/images/capslock.svg create mode 100644 VirtualKeyboard/src/images/capslock_click.svg create mode 100644 VirtualKeyboard/src/images/capslock_hl.svg create mode 100644 VirtualKeyboard/src/images/capslock_hl_click.svg create mode 100644 VirtualKeyboard/src/images/close.svg create mode 100644 VirtualKeyboard/src/images/close_click.svg create mode 100644 VirtualKeyboard/src/images/down.svg create mode 100644 VirtualKeyboard/src/images/down_click.svg create mode 100644 VirtualKeyboard/src/images/enter.svg create mode 100644 VirtualKeyboard/src/images/enter_click.svg create mode 100644 VirtualKeyboard/src/images/left.svg create mode 100644 VirtualKeyboard/src/images/left_click.svg create mode 100644 VirtualKeyboard/src/images/right.svg create mode 100644 VirtualKeyboard/src/images/right_click.svg create mode 100644 VirtualKeyboard/src/images/super.svg create mode 100644 VirtualKeyboard/src/images/super_click.svg create mode 100644 VirtualKeyboard/src/images/up.svg create mode 100644 VirtualKeyboard/src/images/up_click.svg create mode 100644 VirtualKeyboard/src/keyboard.qrc create mode 100644 VirtualKeyboard/src/keyboard.qss create mode 100644 VirtualKeyboard/src/keyboardwidget.cpp create mode 100644 VirtualKeyboard/src/keyboardwidget.h create mode 100644 VirtualKeyboard/src/keyboardwidget.ui create mode 100644 VirtualKeyboard/src/main.cpp create mode 100644 VirtualKeyboard/src/virtualkeyboard.cpp create mode 100644 VirtualKeyboard/src/virtualkeyboard.h create mode 100644 VirtualKeyboard/src/x11keyboard.cpp create mode 100644 VirtualKeyboard/src/x11keyboard.h diff --git a/VirtualKeyboard/CMakeLists.txt b/VirtualKeyboard/CMakeLists.txt new file mode 100644 index 0000000..f9d52c7 --- /dev/null +++ b/VirtualKeyboard/CMakeLists.txt @@ -0,0 +1,24 @@ +find_package(Qt5 COMPONENTS Core Widgets REQUIRED) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +qt5_add_resources(VirtualKeyboard_SRC + src/keyboard.qrc) + +set(VirtualKeyboard_SRC + ${VirtualKeyboard_SRC} + src/cursormonitor.cpp + src/keyboardwidget.cpp + src/virtualkeyboard.cpp + src/x11keyboard.cpp + src/keyboard.qrc) + +include_directories( + ${Qt5Core_INCLUDE_DIRS} + ${Qt5Widgets_INCLUDE_DIRS} + ) + +add_library(VirtualKeyboard STATIC ${VirtualKeyboard_SRC}) +target_link_libraries(VirtualKeyboard Qt5::Core Qt5::Widgets) diff --git a/VirtualKeyboard/README.md b/VirtualKeyboard/README.md new file mode 100644 index 0000000..c067665 --- /dev/null +++ b/VirtualKeyboard/README.md @@ -0,0 +1 @@ +A simple virtual keyboard in X11 diff --git a/VirtualKeyboard/VirtualKeyboard.pri b/VirtualKeyboard/VirtualKeyboard.pri new file mode 100644 index 0000000..e8029dc --- /dev/null +++ b/VirtualKeyboard/VirtualKeyboard.pri @@ -0,0 +1,19 @@ +SOURCES += \ + $$PWD/src/keyboardwidget.cpp \ + $$PWD/src/x11keyboard.cpp \ + $$PWD/src/cursormonitor.cpp \ + $$PWD/src/virtualkeyboard.cpp + + +HEADERS += \ + $$PWD/src/keyboardwidget.h \ + $$PWD/src/x11keyboard.h \ + $$PWD/src/cursormonitor.h \ + $$PWD/src/virtualkeyboard.h + +FORMS += \ + $$PWD/src/keyboardwidget.ui + + +RESOURCES += \ + $$PWD/src/keyboard.qrc diff --git a/VirtualKeyboard/VirtualKeyboard.pro b/VirtualKeyboard/VirtualKeyboard.pro new file mode 100644 index 0000000..0e979d8 --- /dev/null +++ b/VirtualKeyboard/VirtualKeyboard.pro @@ -0,0 +1,32 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-10-12T16:43:42 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = VirtualKeyboard +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +CONFIG += link_pkgconfig debug + +PKGCONFIG += xtst x11 + +include(VirtualKeyboard.pri) + +SOURCES += \ + $$PWD/src/main.cpp diff --git a/VirtualKeyboard/src/cursormonitor.cpp b/VirtualKeyboard/src/cursormonitor.cpp new file mode 100644 index 0000000..144b5dd --- /dev/null +++ b/VirtualKeyboard/src/cursormonitor.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 2, 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 St, Fifth Floor, Boston, MA + * 02110-1301, USA. +**/ +#include "cursormonitor.h" +#include +#include + +CursorMonitor::CursorMonitor(QObject *parent) : QThread(parent) +{ + +} + +void CursorMonitor::run() +{ + Display *display; + XEvent xevent; + Window window; + + display = XOpenDisplay(NULL); + + + window = DefaultRootWindow(display); + XAllowEvents(display, AsyncBoth, CurrentTime); + + XGrabPointer(display, + window, + 1, + PointerMotionMask | ButtonPressMask | ButtonReleaseMask , + GrabModeAsync, + GrabModeAsync, + None, + None, + CurrentTime); + + while(1) { + XNextEvent(display, &xevent); + + switch (xevent.type) { + case MotionNotify: + //printf("Mouse move : [%d, %d]\n", xevent.xmotion.x_root, xevent.xmotion.y_root); + Q_EMIT cursorPosChanged(QPoint(xevent.xmotion.x_root, xevent.xmotion.y_root)); + break; + case ButtonPress: +// printf("Button pressed : %s\n", key_name[xevent.xbutton.button - 1]); + break; + case ButtonRelease: +// printf("Button released : %s\n", key_name[xevent.xbutton.button - 1]); + break; + } + } +} diff --git a/VirtualKeyboard/src/cursormonitor.h b/VirtualKeyboard/src/cursormonitor.h new file mode 100644 index 0000000..7722453 --- /dev/null +++ b/VirtualKeyboard/src/cursormonitor.h @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 2, 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 St, Fifth Floor, Boston, MA + * 02110-1301, USA. +**/ +#ifndef CURSORMONITOR_H +#define CURSORMONITOR_H + +#include +#include + +class CursorMonitor : public QThread +{ + Q_OBJECT +public: + explicit CursorMonitor(QObject *parent = nullptr); + void run(); + +Q_SIGNALS: + void cursorPosChanged(const QPoint& pos); +}; + +#endif // CURSORMONITOR_H diff --git a/VirtualKeyboard/src/images/backspace.svg b/VirtualKeyboard/src/images/backspace.svg new file mode 100644 index 0000000..a7d3c0f --- /dev/null +++ b/VirtualKeyboard/src/images/backspace.svg @@ -0,0 +1 @@ +画板 5 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/backspace_click.svg b/VirtualKeyboard/src/images/backspace_click.svg new file mode 100644 index 0000000..403c255 --- /dev/null +++ b/VirtualKeyboard/src/images/backspace_click.svg @@ -0,0 +1 @@ +画板 6 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/capslock.svg b/VirtualKeyboard/src/images/capslock.svg new file mode 100644 index 0000000..e3528aa --- /dev/null +++ b/VirtualKeyboard/src/images/capslock.svg @@ -0,0 +1 @@ +画板 1 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/capslock_click.svg b/VirtualKeyboard/src/images/capslock_click.svg new file mode 100644 index 0000000..d628669 --- /dev/null +++ b/VirtualKeyboard/src/images/capslock_click.svg @@ -0,0 +1 @@ +画板 2 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/capslock_hl.svg b/VirtualKeyboard/src/images/capslock_hl.svg new file mode 100644 index 0000000..111e7f7 --- /dev/null +++ b/VirtualKeyboard/src/images/capslock_hl.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/VirtualKeyboard/src/images/capslock_hl_click.svg b/VirtualKeyboard/src/images/capslock_hl_click.svg new file mode 100644 index 0000000..c5fe4bb --- /dev/null +++ b/VirtualKeyboard/src/images/capslock_hl_click.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/VirtualKeyboard/src/images/close.svg b/VirtualKeyboard/src/images/close.svg new file mode 100644 index 0000000..e66790c --- /dev/null +++ b/VirtualKeyboard/src/images/close.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/VirtualKeyboard/src/images/close_click.svg b/VirtualKeyboard/src/images/close_click.svg new file mode 100644 index 0000000..0ad8243 --- /dev/null +++ b/VirtualKeyboard/src/images/close_click.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/VirtualKeyboard/src/images/down.svg b/VirtualKeyboard/src/images/down.svg new file mode 100644 index 0000000..5f3d25f --- /dev/null +++ b/VirtualKeyboard/src/images/down.svg @@ -0,0 +1 @@ +画板 15 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/down_click.svg b/VirtualKeyboard/src/images/down_click.svg new file mode 100644 index 0000000..5846434 --- /dev/null +++ b/VirtualKeyboard/src/images/down_click.svg @@ -0,0 +1 @@ +画板 16 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/enter.svg b/VirtualKeyboard/src/images/enter.svg new file mode 100644 index 0000000..becb298 --- /dev/null +++ b/VirtualKeyboard/src/images/enter.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/VirtualKeyboard/src/images/enter_click.svg b/VirtualKeyboard/src/images/enter_click.svg new file mode 100644 index 0000000..26760f5 --- /dev/null +++ b/VirtualKeyboard/src/images/enter_click.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/VirtualKeyboard/src/images/left.svg b/VirtualKeyboard/src/images/left.svg new file mode 100644 index 0000000..31daacd --- /dev/null +++ b/VirtualKeyboard/src/images/left.svg @@ -0,0 +1 @@ +画板 19 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/left_click.svg b/VirtualKeyboard/src/images/left_click.svg new file mode 100644 index 0000000..7646744 --- /dev/null +++ b/VirtualKeyboard/src/images/left_click.svg @@ -0,0 +1 @@ +画板 20 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/right.svg b/VirtualKeyboard/src/images/right.svg new file mode 100644 index 0000000..e4469b6 --- /dev/null +++ b/VirtualKeyboard/src/images/right.svg @@ -0,0 +1 @@ +画板 17 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/right_click.svg b/VirtualKeyboard/src/images/right_click.svg new file mode 100644 index 0000000..48177eb --- /dev/null +++ b/VirtualKeyboard/src/images/right_click.svg @@ -0,0 +1 @@ +画板 18 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/super.svg b/VirtualKeyboard/src/images/super.svg new file mode 100644 index 0000000..c847e44 --- /dev/null +++ b/VirtualKeyboard/src/images/super.svg @@ -0,0 +1 @@ +画板 11 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/super_click.svg b/VirtualKeyboard/src/images/super_click.svg new file mode 100644 index 0000000..7fcc495 --- /dev/null +++ b/VirtualKeyboard/src/images/super_click.svg @@ -0,0 +1 @@ +画板 12 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/up.svg b/VirtualKeyboard/src/images/up.svg new file mode 100644 index 0000000..ba22ea9 --- /dev/null +++ b/VirtualKeyboard/src/images/up.svg @@ -0,0 +1 @@ +画板 13 \ No newline at end of file diff --git a/VirtualKeyboard/src/images/up_click.svg b/VirtualKeyboard/src/images/up_click.svg new file mode 100644 index 0000000..ed94534 --- /dev/null +++ b/VirtualKeyboard/src/images/up_click.svg @@ -0,0 +1,13 @@ + + + + +画板 13 + + + + diff --git a/VirtualKeyboard/src/keyboard.qrc b/VirtualKeyboard/src/keyboard.qrc new file mode 100644 index 0000000..4e38067 --- /dev/null +++ b/VirtualKeyboard/src/keyboard.qrc @@ -0,0 +1,27 @@ + + + keyboard.qss + + + images/backspace_click.svg + images/backspace.svg + images/capslock_click.svg + images/capslock_hl.svg + images/capslock.svg + images/down_click.svg + images/down.svg + images/enter_click.svg + images/enter.svg + images/left_click.svg + images/left.svg + images/right_click.svg + images/right.svg + images/super_click.svg + images/super.svg + images/up.svg + images/close_click.svg + images/close.svg + images/capslock_hl_click.svg + images/up_click.svg + + diff --git a/VirtualKeyboard/src/keyboard.qss b/VirtualKeyboard/src/keyboard.qss new file mode 100644 index 0000000..e91e23c --- /dev/null +++ b/VirtualKeyboard/src/keyboard.qss @@ -0,0 +1,37 @@ +QPushButton +{ + border: none; + font: 24px; + color: white; + background: #35322f; + border-radius: 5px; +} + +QPushButton::pressed +{ + color: gray; + background: #2a2826; +} + +#btn_backspace, #btn_enter, #btn_shift_l, +#btn_shift_r, #btn_ctrl_l, #btn_ctrl_r, +#btn_alt_l, #btn_alt_r, #btn_super +{ + font: 16px; + background: #1e1b18 +} + +#btn_backspace::pressed, #btn_enter::pressed, #btn_shift_l::pressed, +#btn_shift_r::pressed, #btn_ctrl_l::pressed, #btn_ctrl_r::pressed, +#btn_alt_l::pressed, #btn_alt_r::pressed, #btn_super::pressed +{ + background: #181613; + color: gray; +} + +#btn_letter, #btn_symbol, #btn_number, +#btn_insert, #btn_delete, #btn_home, +#btn_end, #btn_pgup, #btn_pgdn, #btn_close +{ + font: 16px; +} diff --git a/VirtualKeyboard/src/keyboardwidget.cpp b/VirtualKeyboard/src/keyboardwidget.cpp new file mode 100644 index 0000000..b55a6cd --- /dev/null +++ b/VirtualKeyboard/src/keyboardwidget.cpp @@ -0,0 +1,448 @@ +/** + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 2, 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 St, Fifth Floor, Boston, MA + * 02110-1301, USA. +**/ +#include "keyboardwidget.h" +#include "ui_keyboardwidget.h" +#include +#include +#include + +#define SYMBOL_KEY_COUNT 29 +#define SYMBOL_PAGE_COUNT 2 + +#define BUTTON_BG "QPushButton{background:#1E1B18}" +#define BUTTON_BG_PRESSED "QPushButton{background: #181613;}" +#define BUTTON_BG_HL "QPushButton{background:#80c342}" +#define BUTTON_BG_HL_PRESSED "QPushButton{background:#486E25}" + + +QChar symbols[SYMBOL_PAGE_COUNT][SYMBOL_KEY_COUNT] = + { {'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', ',', '.', '/'}, + {'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', + '`', '-', '=', '[', ']', '\\', '|', '{', '}', + '~','<', '>', ':', ';', '\'', '"', '-', '+', '?'}}; + + +KeyboardWidget::KeyboardWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::KeyboardWidget), + capsLock(false), + isShift(false), + page(0) +{ + vKeyboard = new X11Keyboard(this); + connect(this, SIGNAL(keyPressed(QChar)), + vKeyboard, SLOT(onKeyPressed(QChar))); + connect(this, SIGNAL(keyPressed(FuncKey::FUNCKEY)), + vKeyboard, SLOT(onKeyPressed(FuncKey::FUNCKEY))); + + ui->setupUi(this); + bindSingal(); + setDefaultIcon(); +} + +KeyboardWidget::~KeyboardWidget() +{ + delete ui; +} + +void KeyboardWidget::resizeEvent(QResizeEvent */*event*/) +{ + int w = width(); + int h = height(); + int mainLeftMargin = ui->hl_main->contentsMargins().left(); + int mainRightMargin = ui->hl_main->contentsMargins().right(); + int mainTopMargin = ui->hl_main->contentsMargins().left(); + int mainBottomMargin = ui->hl_main->contentsMargins().right(); + int mainSpacing = ui->hl_main->spacing(); + int itemSpacing = ui->hl_1->spacing(); + + int btnWidthCount = w - 11 * itemSpacing - mainSpacing- mainLeftMargin - mainRightMargin; + int btnHeightCount = h - 3 * itemSpacing - mainTopMargin - mainBottomMargin; + double btnWidth = btnWidthCount / 12; + double btnHeight = btnHeightCount / 4; + for(int i = 0; i <= 28; i++) { + QString btnObjName = "btn_" + QString::number(i); + QPushButton *btn = ui->page_letter->findChild(btnObjName); + btn->setFixedSize(btnWidth, btnHeight); + } + ui->btn_ctrl_l->setFixedSize(btnWidth * 1.3, btnHeight); + ui->btn_ctrl_r->setFixedSize(btnWidth * 1.3, btnHeight); + ui->btn_alt_l->setFixedSize(btnWidth, btnHeight); + ui->btn_alt_r->setFixedSize(btnWidth, btnHeight); + ui->btn_super->setFixedSize(btnWidth, btnHeight); + ui->btn_shift_l->setFixedSize(btnWidth, btnHeight); + ui->spacer_2->changeSize(btnWidth / 2, 20); + + + for(int i = 1; i <= 9; i++) { + QString btnObjName = "btn_num_" + QString::number(i); + QPushButton *btn = ui->page_number->findChild(btnObjName); + btn->setFixedWidth(btnWidth); + } + ui->btn_backspace_num->setFixedSize(btnWidth,btnHeight); + ui->btn_insert->setFixedWidth(btnWidth); + ui->btn_delete->setFixedWidth(btnWidth); + ui->btn_home->setFixedWidth(btnWidth); + ui->btn_end->setFixedWidth(btnWidth); + ui->btn_pgup->setFixedWidth(btnWidth); + ui->btn_pgdn->setFixedWidth(btnWidth); + ui->btn_up->setFixedSize(btnWidth,btnHeight); + ui->btn_down->setFixedSize(btnWidth,btnHeight); + ui->btn_left->setFixedSize(btnWidth,btnHeight); + ui->btn_right->setFixedSize(btnWidth,btnHeight); + + ui->btn_close->setFixedHeight(btnHeight); + ui->btn_letter->setFixedHeight(btnHeight); + ui->btn_symbol->setFixedHeight(btnHeight); + ui->btn_number->setFixedHeight(btnHeight); + + setIconSize(); +} + +float hScale = 0.6; +float wScale = hScale; +#define SET_ICON_SIZE_SCALE(btn) \ + ui->btn_##btn->setIconSize(QSize(ui->btn_##btn->width() * hScale, ui->btn_##btn->height() * wScale)); + +#define SET_ICON_SIZE(btn) \ + ui->btn_##btn->setIconSize(QSize(ui->btn_##btn->width(), ui->btn_##btn->height())); + +void KeyboardWidget::setIconSize() +{ + SET_ICON_SIZE_SCALE(backspace); + SET_ICON_SIZE_SCALE(enter); + SET_ICON_SIZE_SCALE(close); + SET_ICON_SIZE_SCALE(super); + SET_ICON_SIZE_SCALE(shift_l); + SET_ICON_SIZE_SCALE(shift_r); + SET_ICON_SIZE(up); + SET_ICON_SIZE(down); + SET_ICON_SIZE(left); + SET_ICON_SIZE(right); +} + +void KeyboardWidget::bindSingal() +{ + for(auto obj : ui->page_letter->children()) { + if(obj->metaObject()->className() == QString("QPushButton")) { + QPushButton *btn = static_cast(obj); + btn->setFocusPolicy(Qt::NoFocus); + connect(btn, &QPushButton::clicked, this, &KeyboardWidget::onButtonClicked); + connect(btn, &QPushButton::pressed, this, &KeyboardWidget::onButtonPressed); + connect(btn, &QPushButton::released, this, &KeyboardWidget::onButtonReleased); + } + } + for(auto obj : ui->page_number->children()) { + if(obj->metaObject()->className() == QString("QPushButton")) { + QPushButton *btn = static_cast(obj); + btn->setFocusPolicy(Qt::NoFocus); + connect(btn, &QPushButton::clicked, this, &KeyboardWidget::onButtonClicked); + connect(btn, &QPushButton::pressed, this, &KeyboardWidget::onButtonPressed); + connect(btn, &QPushButton::released, this, &KeyboardWidget::onButtonReleased); + } + } + ui->btn_close->setFocusPolicy(Qt::NoFocus); + ui->btn_letter->setFocusPolicy(Qt::NoFocus); + ui->btn_symbol->setFocusPolicy(Qt::NoFocus); + ui->btn_number->setFocusPolicy(Qt::NoFocus); + + connect(ui->btn_letter, &QPushButton::clicked, this, [&] { + ui->stackedWidget->setCurrentWidget(ui->page_letter); + page = 0; + switchPage(); + }); + connect(ui->btn_symbol, &QPushButton::clicked, this, [&] { + ui->stackedWidget->setCurrentWidget(ui->page_letter); + page = 1; + switchPage(); + }); + connect(ui->btn_number, &QPushButton::clicked, this, [&] { + ui->stackedWidget->setCurrentWidget(ui->page_number); + }); + connect(ui->btn_close, &QPushButton::clicked, + this, &KeyboardWidget::aboutToClose); + + connect(ui->btn_close, &QPushButton::pressed, + this, &KeyboardWidget::onButtonPressed); + connect(ui->btn_close, &QPushButton::released, + this, &KeyboardWidget::onButtonReleased); +} + +void KeyboardWidget::setDefaultIcon() +{ + ui->btn_backspace->setIcon(QIcon(":/images/images/backspace.svg")); + ui->btn_backspace_num->setIcon(QIcon(":/images/images/backspace.svg")); + ui->btn_enter->setIcon(QIcon(":/images/images/enter.svg")); + ui->btn_shift_l->setIcon(QIcon(":/images/images/capslock.svg")); + ui->btn_shift_r->setIcon(QIcon(":/images/images/capslock.svg")); + ui->btn_close->setIcon(QIcon(":/images/images/close.svg")); + ui->btn_super->setIcon(QIcon(":/images/images/super.svg")); + ui->btn_up->setIcon(QIcon(":/images/images/up.svg")); + ui->btn_down->setIcon(QIcon(":/images/images/down.svg")); + ui->btn_left->setIcon(QIcon(":/images/images/left.svg")); + ui->btn_right->setIcon(QIcon(":/images/images/right.svg")); +} + +QString KeyboardWidget::getKeyName(QPushButton *btn) +{ + QString objName = btn->objectName(); + int lastUnderline = objName.lastIndexOf('_'); + int start = strlen("btn_"); + int keyLength = lastUnderline - start; + QString keyName = objName.mid(start, keyLength); + return keyName; +} + +void KeyboardWidget::changeFuncKeyStyle(QPushButton *btn, bool isPressed) +{ + QString modName = getKeyName(btn); + Modifier::MOD mod = Modifier::getModifier(modName); + + if(vKeyboard->hasModifier(mod)) { + if(isPressed) + btn->setStyleSheet(BUTTON_BG_HL_PRESSED); + else + btn->setStyleSheet(BUTTON_BG_HL); + } else { + if(isPressed) + btn->setStyleSheet(BUTTON_BG_PRESSED); + else + btn->setStyleSheet(BUTTON_BG); + } +} + +void KeyboardWidget::changeShitKeyStyle(QPushButton *btn, bool isPressed) +{ + if(page == 0){ + if(isShift) { + if(capsLock){ + if(isPressed) { + btn->setStyleSheet(BUTTON_BG_HL_PRESSED); + btn->setIcon(QIcon(":/images/images/capslock_click.svg")); + } else { + btn->setStyleSheet(BUTTON_BG_HL); + btn->setIcon(QIcon(":/images/images/capslock.svg")); + } + } + else { + if(isPressed) + btn->setIcon(QIcon(":/images/images/capslock_hl_click.svg")); + else + btn->setIcon(QIcon(":/images/images/capslock_hl.svg")); + } + } else { + if(isPressed) + btn->setIcon(QIcon(":/images/images/capslock_click.svg")); + else + btn->setIcon(QIcon(":/images/images/capslock.svg")); + } + } +} + + +void KeyboardWidget::changeDirectKeyStyle(QPushButton *btn, bool isPressed) +{ + QString keyName = getKeyName(btn); + FuncKey::FUNCKEY key = FuncKey::getKey(keyName); + if(key == FuncKey::UNKNOWN) + return; + + QString iconName = QString(":/images/images/%1.svg").arg(keyName); + QString iconNamePressed = QString(":/images/images/%1_click.svg").arg(keyName); + + if(isPressed) + btn->setIcon(QIcon(iconNamePressed)); + else + btn->setIcon(QIcon(iconName)); +} + +/** + * @brief 修改按键样式 + * @param obj 按键 + * @param isPressed 按下或者松开 + */ +void KeyboardWidget::changeKeyStyle(QPushButton *btn, bool isPressed) +{ + if(btn == ui->btn_ctrl_l || btn == ui->btn_ctrl_r || + btn == ui->btn_alt_l || btn == ui->btn_alt_r || + btn == ui->btn_super) { + changeFuncKeyStyle(btn, isPressed); + } + + if(btn == ui->btn_shift_l) + changeShitKeyStyle(ui->btn_shift_l, isPressed); + if(btn == ui->btn_shift_r) + changeShitKeyStyle(ui->btn_shift_r, isPressed); + + changeDirectKeyStyle(btn, isPressed); +} + +void KeyboardWidget::onButtonPressed() +{ + QPushButton *btn = static_cast(sender()); + changeKeyStyle(btn, true); +} + +void KeyboardWidget::onButtonReleased() +{ + QPushButton *btn = static_cast(sender()); + changeKeyStyle(btn, false); +} + +void KeyboardWidget::onButtonClicked() +{ + QObject *obj = sender(); + if(obj->metaObject()->className() != QString("QPushButton")) + return; + + QPushButton *btn = static_cast(obj); + QString keyName = getKeyName(btn); + qDebug() << "keyName: " << keyName; + + Modifier::MOD mod = Modifier::getModifier(keyName); + FuncKey::FUNCKEY funcKey = FuncKey::getKey(keyName); + + if(keyName == "shift") { + if(page == 0) { + isShift = !isShift; + if(isShift) { //第一次被按下 + capsLock = false; + shiftLastClicked = QTime::currentTime(); + ui->btn_shift_l->setIcon(QIcon(":/images/images/capslock_hl.svg")); + ui->btn_shift_r->setIcon(QIcon(":/images/images/capslock_hl.svg")); + } + else { + int doubleClickInterval = QApplication::doubleClickInterval(); + if(shiftLastClicked.msecsTo(QTime::currentTime()) <= doubleClickInterval) { + //shift键双击,锁定大写 + capsLock = true; + isShift = true; + ui->btn_shift_l->setIcon(QIcon(":/images/images/capslock.svg")); + ui->btn_shift_r->setIcon(QIcon(":/images/images/capslock.svg")); + ui->btn_shift_l->setStyleSheet("QPushButton{background:#80c342}"); + ui->btn_shift_r->setStyleSheet("QPushButton{background:#80c342}"); + } else { + ui->btn_shift_l->setIcon(QIcon(":/images/images/capslock.svg")); + ui->btn_shift_r->setIcon(QIcon(":/images/images/capslock.svg")); + ui->btn_shift_l->setStyleSheet("QPushButton{background:#1e1b18}"); + ui->btn_shift_r->setStyleSheet("QPushButton{background:#1e1b18}"); + } + } + toggleCase(); + } else { + page = page % (SYMBOL_PAGE_COUNT - 1) + 1; + switchPage(); + } + } else if(mod != Modifier::UNKNOWN) { + if(vKeyboard->hasModifier(mod)) { + vKeyboard->removeModifier(mod); + btn->setStyleSheet(BUTTON_BG); + btn->setStyleSheet(BUTTON_BG); + } else { + vKeyboard->addModifier(mod); + btn->setStyleSheet(BUTTON_BG_HL); + btn->setStyleSheet(BUTTON_BG_HL); + } + } else if(funcKey != FuncKey::UNKNOWN) { + Q_EMIT keyPressed(funcKey); + } else { //字符键 + QChar c; + QString text = btn->text(); + qDebug() << "clicked button text: " << text; + if(text == "&&") + c = '&'; + else if(text.length() == 1) + c = text.at(0); + + Q_EMIT keyPressed(c); + + //如果shift键被单击,按一个键后就恢复为小写 + if(isShift && !capsLock) { + isShift = false; + toggleCase(); + changeShitKeyStyle(ui->btn_shift_l, false); + changeShitKeyStyle(ui->btn_shift_r, false); + } + clearModifier(); + } +} + +void KeyboardWidget::clearModifier() +{ + for(auto mod : vKeyboard->getAllModifier()) { + QString modName = Modifier::getModifierName(mod); + if(mod == Modifier::SUPER) { + QString objName = QString("btn_%1").arg(modName); + QPushButton *btn = ui->page_letter->findChild(objName); + btn->setStyleSheet(BUTTON_BG); + } else { + QString objName = QString("btn_%1_l").arg(modName); + QPushButton *btn = ui->page_letter->findChild(objName); + btn->setStyleSheet(BUTTON_BG); + objName = QString("btn_%1_r").arg(modName); + btn = ui->page_letter->findChild(objName); + btn->setStyleSheet(BUTTON_BG); + } + } + vKeyboard->clearModifier(); +} + +void KeyboardWidget::toggleCase() +{ + for(int i = 0; i < 26; i++) { + QString objName = "btn_" + QString::number(i); + QPushButton *btn = findChild(objName); + QChar ch; + if(isShift) { //切换到大写 + ch = symbols[0][i].toUpper(); + } else { + ch = symbols[0][i]; + } + btn->setText(ch); + } +} + +void KeyboardWidget::switchPage() +{ + if(page == 0) { + ui->btn_shift_l->setText(""); + ui->btn_shift_r->setText(""); + ui->btn_shift_l->setIcon(QIcon(":/images/images/capslock.svg")); + ui->btn_shift_r->setIcon(QIcon(":/images/images/capslock.svg")); + } else { + QString text = QString("%1/%2").arg(page).arg(SYMBOL_PAGE_COUNT - 1); + ui->btn_shift_l->setText(text); + ui->btn_shift_r->setText(text); + ui->btn_shift_l->setIcon(QIcon()); + ui->btn_shift_r->setIcon(QIcon()); + } + + for(int i = 0; i < SYMBOL_KEY_COUNT; i++) { + QString btnObjName = "btn_" + QString::number(i); + QPushButton *btn = ui->page_letter->findChild(btnObjName); + QChar c = symbols[page][i]; + if(c == '&') + btn->setText("&&"); + else + btn->setText(c); + } +} + diff --git a/VirtualKeyboard/src/keyboardwidget.h b/VirtualKeyboard/src/keyboardwidget.h new file mode 100644 index 0000000..25591ae --- /dev/null +++ b/VirtualKeyboard/src/keyboardwidget.h @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 2, 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 St, Fifth Floor, Boston, MA + * 02110-1301, USA. +**/ +#ifndef KEYBOARDWIDGET_H +#define KEYBOARDWIDGET_H + +#include +#include +#include +#include "x11keyboard.h" + +namespace Ui { +class KeyboardWidget; +} + +class QPushButton; + +class KeyboardWidget : public QWidget +{ + Q_OBJECT + +public: + explicit KeyboardWidget(QWidget *parent = 0); + ~KeyboardWidget(); + +protected: + void resizeEvent(QResizeEvent *event); + +private: + void bindSingal(); + void toggleCase(); + void switchPage(); + void setDefaultIcon(); + void setIconSize(); + void changeKeyStyle(QPushButton *btn, bool isPressed); + void changeFuncKeyStyle(QPushButton *btn, bool isPressed); + void changeShitKeyStyle(QPushButton *btn, bool isPressed); + void changeDirectKeyStyle(QPushButton *btn, bool isPressed); + void clearModifier(); + QString getKeyName(QPushButton *btn); + + +private Q_SLOTS: + void onButtonClicked(); + void onButtonPressed(); + void onButtonReleased(); + +Q_SIGNALS: + void aboutToClose(); + void keyPressed(QChar c); + void keyPressed(FuncKey::FUNCKEY key); + +private: + Ui::KeyboardWidget *ui; + bool capsLock; //是否大写锁定 + bool isShift; + QTime shiftLastClicked; //shift键上次被点击的时间 + int page; //当前是第几页的键盘 + X11Keyboard *vKeyboard; +}; + +#endif // KEYBOARDWIDGET_H diff --git a/VirtualKeyboard/src/keyboardwidget.ui b/VirtualKeyboard/src/keyboardwidget.ui new file mode 100644 index 0000000..57e635f --- /dev/null +++ b/VirtualKeyboard/src/keyboardwidget.ui @@ -0,0 +1,1190 @@ + + + KeyboardWidget + + + Qt::NonModal + + + + 0 + 0 + 1106 + 293 + + + + + 0 + 0 + + + + + 0 + 0 + + + + KeyboardWidget + + + + 0 + + + QLayout::SetMinAndMaxSize + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + QLayout::SetNoConstraint + + + 10 + + + 10 + + + 10 + + + 10 + + + + + 0 + + + + + 0 + + + QLayout::SetNoConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 5 + + + QLayout::SetNoConstraint + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 10 + + + QLayout::SetNoConstraint + + + + + + 0 + 0 + + + + q + + + + + + + + 0 + 0 + + + + w + + + + + + + + 0 + 0 + + + + e + + + + + + + + 0 + 0 + + + + r + + + + + + + + 0 + 0 + + + + t + + + + + + + + 0 + 0 + + + + y + + + + + + + + 0 + 0 + + + + u + + + + + + + + 0 + 0 + + + + i + + + + + + + + 0 + 0 + + + + o + + + + + + + + 0 + 0 + + + + p + + + + + + + + 0 + 0 + + + + + + + + + + + + + 10 + + + QLayout::SetNoConstraint + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + a + + + + + + + + 0 + 0 + + + + s + + + + + + + + 0 + 0 + + + + d + + + + + + + + 0 + 0 + + + + f + + + + + + + + 0 + 0 + + + + g + + + + + + + + 0 + 0 + + + + h + + + + + + + + 0 + 0 + + + + j + + + + + + + + 0 + 0 + + + + k + + + + + + + + 0 + 0 + + + + l + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + 10 + + + QLayout::SetNoConstraint + + + + + + 0 + 0 + + + + + + + + + + + + + + + 0 + 0 + + + + z + + + + + + + + 0 + 0 + + + + x + + + + + + + + 0 + 0 + + + + c + + + + + + + + 0 + 0 + + + + v + + + + + + + + 0 + 0 + + + + b + + + + + + + + 0 + 0 + + + + n + + + + + + + + 0 + 0 + + + + m + + + + + + + + 0 + 0 + + + + , + + + + + + + + 0 + 0 + + + + . + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + 10 + + + QLayout::SetNoConstraint + + + + + + 0 + 0 + + + + + + + Ctrl + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + Alt + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + Alt + + + + + + + + 0 + 0 + + + + / + + + + + + + + 0 + 0 + + + + Ctrl + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + QLayout::SetNoConstraint + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 10 + + + QLayout::SetNoConstraint + + + + + QLayout::SetNoConstraint + + + 10 + + + + + + 0 + 0 + + + + 9 + + + + + + + + 0 + 0 + + + + 5 + + + + + + + + 0 + 0 + + + + 8 + + + + + + + + 0 + 0 + + + + 4 + + + + + + + + 0 + 0 + + + + 2 + + + + + + + + 0 + 0 + + + + 7 + + + + + + + + 0 + 0 + + + + 1 + + + + + + + + 0 + 0 + + + + 6 + + + + + + + + 0 + 0 + + + + 3 + + + + + + + + 0 + 0 + + + + 0 + + + + + + + + 0 + 0 + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QLayout::SetNoConstraint + + + 10 + + + + + + 0 + 0 + + + + Delete + + + + + + + + 0 + 0 + + + + End + + + + + + + + 0 + 0 + + + + Insert + + + + + + + + 0 + 0 + + + + PgUp + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + Home + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + PgDn + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 5 + + + QLayout::SetNoConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 100 + 16777215 + + + + + + + + + + + + 0 + 0 + + + + + 100 + 16777215 + + + + Abc + + + + + + + + 0 + 0 + + + + + 100 + 16777215 + + + + @ + + + + + + + + 0 + 0 + + + + + 100 + 16777215 + + + + 123 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + diff --git a/VirtualKeyboard/src/main.cpp b/VirtualKeyboard/src/main.cpp new file mode 100644 index 0000000..859879c --- /dev/null +++ b/VirtualKeyboard/src/main.cpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 2, 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 St, Fifth Floor, Boston, MA + * 02110-1301, USA. +**/ +#include "virtualkeyboard.h" +#include + +int main(int argc, char *argv[]) +{ +// qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); + QApplication a(argc, argv); + VirtualKeyboard *keyboard = new VirtualKeyboard; + QObject::connect(keyboard, &VirtualKeyboard::aboutToClose, &a, &QApplication::quit); + keyboard->show(); + + return a.exec(); +} diff --git a/VirtualKeyboard/src/virtualkeyboard.cpp b/VirtualKeyboard/src/virtualkeyboard.cpp new file mode 100644 index 0000000..ea46695 --- /dev/null +++ b/VirtualKeyboard/src/virtualkeyboard.cpp @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 2, 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 St, Fifth Floor, Boston, MA + * 02110-1301, USA. +**/ +#include "virtualkeyboard.h" +#include +#include +#include +#include + +VirtualKeyboard::VirtualKeyboard(QWidget *parent) + : QWidget(parent) +{ + Q_INIT_RESOURCE(keyboard); + + setAutoFillBackground(true); + QPalette plt; + plt.setBrush(QPalette::Background, Qt::black); + setPalette(plt); + + setWindowFlags(Qt::FramelessWindowHint | + Qt::WindowStaysOnTopHint | + Qt::WindowDoesNotAcceptFocus); + + + keyboardWidget = new KeyboardWidget(this); + QHBoxLayout *hl_keyboard = new QHBoxLayout(this); + QSpacerItem *spacer = new QSpacerItem(40, 20); + hl_keyboard->addSpacerItem(spacer); + hl_keyboard->addWidget(keyboardWidget); + QSpacerItem *spacer2 = new QSpacerItem(40, 20); + hl_keyboard->addSpacerItem(spacer2); + + QFile qssFile(":/qss/keyboard.qss"); + qssFile.open(QIODevice::ReadOnly); + setStyleSheet(qssFile.readAll()); + qssFile.close(); + + QDesktopWidget *desktop = QApplication::desktop(); + cursorMonitor = new CursorMonitor(this); + + //在多显示器情况下,监视鼠标指针的位置和主显示器变化信号 + connect(cursorMonitor, &CursorMonitor::cursorPosChanged, + this, [&](const QPoint &pos){ + adjustGeometry(desktop->screenNumber(pos)); + }); + + connect(desktop, &QDesktopWidget::primaryScreenChanged, + this, [&]{ + adjustGeometry(desktop->primaryScreen()); + }); + + connect(keyboardWidget, &KeyboardWidget::aboutToClose, + this, &VirtualKeyboard::aboutToClose); + + adjustGeometry(desktop->primaryScreen()); +} + +void VirtualKeyboard::adjustGeometry(int screen) +{ + QDesktopWidget *desktop = QApplication::desktop(); + QWidget *activateScreen = desktop->screen(screen); + setGeometry(0, activateScreen->height() - activateScreen->height() / 3, + activateScreen->width(), activateScreen->height() / 3); +} diff --git a/VirtualKeyboard/src/virtualkeyboard.h b/VirtualKeyboard/src/virtualkeyboard.h new file mode 100644 index 0000000..44b628a --- /dev/null +++ b/VirtualKeyboard/src/virtualkeyboard.h @@ -0,0 +1,47 @@ +/** + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 2, 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 St, Fifth Floor, Boston, MA + * 02110-1301, USA. +**/ +#ifndef VIRTUALKEYBOARD_H +#define VIRTUALKEYBOARD_H + +#include +#include + +#include "keyboardwidget.h" +#include "cursormonitor.h" + +class VirtualKeyboard : public QWidget +{ + Q_OBJECT +public: + explicit VirtualKeyboard(QWidget *parent = 0); + +private: + void adjustGeometry(int screen); + +Q_SIGNALS: + void aboutToClose(); + +private: + KeyboardWidget *keyboardWidget; + CursorMonitor *cursorMonitor; + bool isApplication; +}; + + +#endif // VIRTUALKEYBOARD_H diff --git a/VirtualKeyboard/src/x11keyboard.cpp b/VirtualKeyboard/src/x11keyboard.cpp new file mode 100644 index 0000000..5e160ed --- /dev/null +++ b/VirtualKeyboard/src/x11keyboard.cpp @@ -0,0 +1,208 @@ +/** + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 2, 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 St, Fifth Floor, Boston, MA + * 02110-1301, USA. +**/ +#include "x11keyboard.h" +#include +#include +#include +#include + + + +struct CharMap { + QChar name; + KeySym code; +}; + +struct CharMap XSpecialSymbolMap[] { + {' ', XK_space}, + {',', XK_comma}, + {'.', XK_period}, + {'\'', XK_quoteright}, + {'@', XK_at}, + {'#', XK_numbersign}, + {'$', XK_dollar}, + {'%', XK_percent}, + {'&', XK_ampersand}, + {'*', XK_asterisk}, + {'(', XK_parenleft}, + {')', XK_parenright}, + {'-', XK_minus}, + {'+', XK_plus}, + {'!', XK_exclam}, + {'"', XK_quotedbl}, + {'<', XK_less}, + {'>', XK_greater}, + {':', XK_colon}, + {';', XK_semicolon}, + {'/', XK_slash}, + {'?', XK_question}, + {'=', XK_equal}, + {'.', XK_kana_middledot}, + {'~', XK_asciitilde}, + {'`', XK_grave}, + {'|', XK_bar}, + {'^', XK_asciicircum}, + {'{', XK_braceleft}, + {'}', XK_braceright}, + {'[', XK_bracketleft}, + {']', XK_bracketright}, + {'_', XK_underscore}, + {'\\', XK_backslash}, +}; + +QMap funckeyMap = { + {FuncKey::SPACE, XK_space}, + {FuncKey::BACKSPACE, XK_BackSpace}, + {FuncKey::ENTER, XK_Return}, + {FuncKey::HOME, XK_Home}, + {FuncKey::END, XK_End}, + {FuncKey::PGUP, XK_Page_Up}, + {FuncKey::PGDN, XK_Page_Down}, + {FuncKey::INSERT, XK_Insert}, + {FuncKey::DELETE, XK_Delete}, + {FuncKey::UP, XK_Up}, + {FuncKey::DOWN, XK_Down}, + {FuncKey::LEFT, XK_Left}, + {FuncKey::RIGHT, XK_Right} +}; + +QMap modifierMap = { + {Modifier::CTRL, XK_Control_L}, + {Modifier::ALT, XK_Alt_L}, + {Modifier::SUPER, XK_Super_L}, + {Modifier::SHIFT, XK_Shift_L} +}; + +QVector shiftKeyVec = {'~', '!', '@', '#', '$', '%', '^', '&', '*', + '(', ')', '_', '+', '{', '}', '|', ':', '"', + '>', '?'}; + +static Display *display = XOpenDisplay(0); +bool isShift = false; +bool isLetter = false; +unsigned int keyCodeOfChar(QChar c) +{ + QString text(c); + + KeySym keysym = XStringToKeysym(text.toLocal8Bit().data()); + + if(keysym == NoSymbol) { + int symbolCount = sizeof(XSpecialSymbolMap) / sizeof(struct CharMap); + for(int i = 0; i < symbolCount; i++) { + if(XSpecialSymbolMap[i].name == c) { + keysym = XSpecialSymbolMap[i].code; + break; + } + } + } + qDebug() << "keysym: " << keysym; + + isShift = shiftKeyVec.contains(c) || (c >= 'A' && c <= 'Z'); + + isLetter = c.isLetter(); + + KeyCode code = XKeysymToKeycode(display, keysym); + + return code; +} + +X11Keyboard::X11Keyboard(QObject *parent) + : QObject(parent) +{ + +} + +X11Keyboard::~X11Keyboard() +{ + XCloseDisplay(display); +} + +void X11Keyboard::addModifier(Modifier::MOD mod) +{ + modList.push_back(mod); +} + +void X11Keyboard::removeModifier(Modifier::MOD mod) +{ + modList.removeOne(mod); +} + +bool X11Keyboard::hasModifier(Modifier::MOD mod) +{ + return modList.contains(mod); +} + +QList X11Keyboard::getAllModifier() +{ + return modList; +} + +void X11Keyboard::clearModifier() +{ + modList.clear(); +} + + +void X11Keyboard::onKeyPressed(QChar c) +{ + unsigned int keyCode = keyCodeOfChar(c); + sendKey(keyCode); +} + +void X11Keyboard::onKeyPressed(FuncKey::FUNCKEY key) +{ + KeyCode keyCode; + KeySym keysym = funckeyMap[key]; + + if(keysym != NoSymbol) + keyCode = XKeysymToKeycode(display, keysym); + + sendKey(keyCode); +} + +void X11Keyboard::sendKey(unsigned int keyCode) +{ + Window focusWindow; + int revert; + XGetInputFocus(display, &focusWindow, &revert); + + for(auto mod : modList){ + KeyCode keyCode = XKeysymToKeycode(display, modifierMap[mod]); + XTestFakeKeyEvent(display, keyCode, True, 2); + } + + //如果使用了修饰键(如ctrl、alt)且字符键是字母,则不起用shift键,否则快捷键不起作用 + if(!modList.isEmpty() && isLetter) + isShift = false; + + if(isShift) + XTestFakeKeyEvent(display, XKeysymToKeycode(display, XK_Shift_L), True, 2); + + XTestFakeKeyEvent(display, keyCode, True, CurrentTime); + XTestFakeKeyEvent(display, keyCode, False, CurrentTime); + + if(isShift) + XTestFakeKeyEvent(display, XKeysymToKeycode(display, XK_Shift_L), False, 2); + for(auto mod : modList){ + KeyCode keyCode = XKeysymToKeycode(display, modifierMap[mod]); + XTestFakeKeyEvent(display, keyCode, False, 2); + } + + XFlush(display); +} diff --git a/VirtualKeyboard/src/x11keyboard.h b/VirtualKeyboard/src/x11keyboard.h new file mode 100644 index 0000000..42fd997 --- /dev/null +++ b/VirtualKeyboard/src/x11keyboard.h @@ -0,0 +1,116 @@ +/** + * Copyright (C) 2018 Tianjin KYLIN Information Technology Co., Ltd. + * + * 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 2, 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 St, Fifth Floor, Boston, MA + * 02110-1301, USA. +**/ +#ifndef X11KEYBOARD_H +#define X11KEYBOARD_H + +#include +#include + +class Modifier : public QObject +{ + Q_OBJECT +public: + Modifier(){} + + enum MOD{ + UNKNOWN = -1, + CTRL, + SHIFT, + ALT, + SUPER + }; + Q_ENUM(MOD) + + static QString getModifierName(int mod) + { + QMetaEnum metaEnum = QMetaEnum::fromType(); + const char* modName = metaEnum.valueToKey(mod); + QString result = QString(modName).toLower(); + return result; + } + static MOD getModifier(const QString &modName) + { + QMetaEnum metaEnum = QMetaEnum::fromType(); + MOD mod = (MOD)metaEnum.keyToValue(modName.toUpper().toLocal8Bit().data()); + return mod; + } +}; + +class FuncKey : public QObject +{ + Q_OBJECT +public: + FuncKey(){} + + enum FUNCKEY { + UNKNOWN = -1, + SPACE = 0, + BACKSPACE, + ENTER, + HOME, + END, + PGUP, + PGDN, + INSERT, + DELETE, + UP, + DOWN, + LEFT, + RIGHT + }; + Q_ENUM(FUNCKEY) + static QString getKeyName(int key) + { + QMetaEnum metaEnum = QMetaEnum::fromType(); + const char* keyName = metaEnum.valueToKey(key); + QString result = QString(keyName).toLower(); + return result; + } + static FUNCKEY getKey(const QString &keyName) + { + QMetaEnum metaEnum = QMetaEnum::fromType(); + FUNCKEY key = (FUNCKEY)metaEnum.keyToValue(keyName.toUpper().toLocal8Bit().data()); + return key; + } +}; + +class X11Keyboard : public QObject +{ + Q_OBJECT +public: + explicit X11Keyboard(QObject *parent = nullptr); + ~X11Keyboard(); + void addModifier(Modifier::MOD mod); + void removeModifier(Modifier::MOD mod); + bool hasModifier(Modifier::MOD mod); + QList getAllModifier(); + void clearModifier(); + +public Q_SLOTS: + void onKeyPressed(QChar c); + void onKeyPressed(FuncKey::FUNCKEY key); + +private: + void sendKey(unsigned int keyCode); + +private: + QList modList; +}; + +#endif // X11KEYBOARD_H