Skip to content

Commit

Permalink
Implement Caps Lock warning on Linux (X11) and Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
phoerious committed Oct 21, 2019
1 parent 4cc06f9 commit d274916
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 11 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ include(CLangFormat)

set(QT_COMPONENTS Core Network Concurrent Gui Svg Widgets Test LinguistTools)
if(UNIX AND NOT APPLE)
find_package(Qt5 COMPONENTS ${QT_COMPONENTS} DBus REQUIRED)
find_package(Qt5 COMPONENTS ${QT_COMPONENTS} DBus X11Extras REQUIRED)
elseif(APPLE)
find_package(Qt5 COMPONENTS ${QT_COMPONENTS} REQUIRED HINTS /usr/local/opt/qt/lib/cmake /usr/local/Cellar/qt/*/lib/cmake ENV PATH)
find_package(Qt5 COMPONENTS MacExtras HINTS /usr/local/opt/qt/lib/cmake /usr/local/Cellar/qt/*/lib/cmake ENV PATH)
Expand Down
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ if(HAIKU)
target_link_libraries(keepassx_core network)
endif()
if(UNIX AND NOT APPLE)
target_link_libraries(keepassx_core Qt5::DBus)
target_link_libraries(keepassx_core Qt5::DBus Qt5::X11Extras X11)
endif()
if(MINGW)
target_link_libraries(keepassx_core Wtsapi32.lib Ws2_32.lib)
Expand Down
6 changes: 6 additions & 0 deletions src/gui/DatabaseOpenWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
m_ui->yubikeyProgress->setSizePolicy(sp);

connect(m_ui->buttonRedetectYubikey, SIGNAL(clicked()), SLOT(pollYubikey()));

m_ui->capsLockWarningLabel->setVisible(false);
connect(m_ui->editPassword, &PasswordEdit::capslockToggled, [&](bool state) {
m_ui->capsLockWarningLabel->setVisible(state);
});

#else
m_ui->buttonRedetectYubikey->setVisible(false);
m_ui->comboChallengeResponse->setVisible(false);
Expand Down
32 changes: 23 additions & 9 deletions src/gui/DatabaseOpenWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>592</width>
<height>462</height>
<height>522</height>
</rect>
</property>
<property name="accessibleName">
Expand Down Expand Up @@ -155,14 +155,28 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Enter Password:</string>
</property>
<property name="buddy">
<cstring>editPassword</cstring>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Enter Password:</string>
</property>
<property name="buddy">
<cstring>editPassword</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="capsLockWarningLabel">
<property name="styleSheet">
<string notr="true">QLabel { color: rgb(255, 125, 125); }</string>
</property>
<property name="text">
<string>Warning: Caps Lock enabled</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="passwordLayout">
Expand Down
60 changes: 60 additions & 0 deletions src/gui/PasswordEdit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,30 @@
#include "core/FilePath.h"
#include "gui/Font.h"

#include <QKeyEvent>
#include <QTimer>
#include <QProcessEnvironment>

#if defined(Q_OS_WIN)
#include <windows.h>
#elif defined(Q_OS_MACOS)
// TODO
#elif defined(Q_OS_UNIX)
#include <QtX11Extras/QX11Info>
// namespace required to avoid name clashes with declarations in XKBlib.h
namespace X11
{
#include <X11/XKBlib.h>
}
#endif

const QColor PasswordEdit::CorrectSoFarColor = QColor(255, 205, 15);
const QColor PasswordEdit::ErrorColor = QColor(255, 125, 125);

PasswordEdit::PasswordEdit(QWidget* parent)
: QLineEdit(parent)
, m_basePasswordEdit(nullptr)
, m_capslockPollTimer(new QTimer(this))
{
const QIcon errorIcon = filePath()->icon("status", "dialog-error");
m_errorAction = addAction(errorIcon, QLineEdit::TrailingPosition);
Expand All @@ -46,6 +64,8 @@ PasswordEdit::PasswordEdit(QWidget* parent)
QFont passwordFont = Font::fixedFont();
passwordFont.setLetterSpacing(QFont::PercentageSpacing, 110);
setFont(passwordFont);

connect(m_capslockPollTimer, SIGNAL(timeout()), SLOT(checkCapslockState()));
}

void PasswordEdit::enableVerifyMode(PasswordEdit* basePasswordEdit)
Expand Down Expand Up @@ -119,3 +139,43 @@ void PasswordEdit::autocompletePassword(const QString& password)
setText(password);
}
}

void PasswordEdit::hideEvent(QHideEvent* event)
{
QWidget::hideEvent(event);
m_capslockPollTimer->stop();
}

void PasswordEdit::showEvent(QShowEvent* event)
{
QWidget::showEvent(event);
if (!m_basePasswordEdit) {
// poll caps lock state only for primary password edits
m_capslockPollTimer->start(50);
}
}

void PasswordEdit::checkCapslockState()
{
bool newCapslockState = m_capslockState;

#if defined(Q_OS_WIN)
newCapslockState = (GetKeyState(VK_CAPITAL) == 1);
#elif defined(Q_OS_MACOS)
// TODO
#elif defined(Q_OS_UNIX)
if (QX11Info::isPlatformX11() && QX11Info::display()) {
unsigned state = 0;
// reinterpret cast needed, since we namespaced the XKBlib.h include
if (X11::XkbGetIndicatorState(
reinterpret_cast<X11::Display*>(QX11Info::display()), XkbUseCoreKbd, &state) == Success) {
newCapslockState = ((state & 1u) == 1);
}
}
#endif

if (newCapslockState != m_capslockState) {
m_capslockState = newCapslockState;
emit capslockToggled(m_capslockState);
}
}
10 changes: 10 additions & 0 deletions src/gui/PasswordEdit.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <QLineEdit>
#include <QPointer>

class QTimer;

class PasswordEdit : public QLineEdit
{
Q_OBJECT
Expand All @@ -38,19 +40,27 @@ class PasswordEdit : public QLineEdit
public slots:
void setShowPassword(bool show);

protected:
void showEvent(QShowEvent* event) override;
void hideEvent(QHideEvent* event) override;

signals:
void showPasswordChanged(bool show);
void capslockToggled(bool capslockOn);

private slots:
void updateStylesheet();
void autocompletePassword(const QString& password);
void checkCapslockState();

private:
bool passwordsEqual() const;

bool m_capslockState = false;
QPointer<QAction> m_errorAction;
QPointer<QAction> m_correctAction;
QPointer<PasswordEdit> m_basePasswordEdit;
QPointer<QTimer> m_capslockPollTimer;
};

#endif // KEEPASSX_PASSWORDEDIT_H

0 comments on commit d274916

Please sign in to comment.