From c5c10b6220a3b1c302b6cd8affe4c8b8e38de335 Mon Sep 17 00:00:00 2001 From: bdmayes Date: Tue, 18 May 2010 12:12:13 +0000 Subject: [PATCH] Adds auto-type and global auto-type functionality for OS X. Also fixes a small bug (2992282). git-svn-id: https://svn.code.sf.net/p/keepassx/code/trunk@383 b624d157-de02-0410-bad0-e51aec6abb33 --- src/Kdb3Database.cpp | 1 + src/dialogs/AutoTypeDlg.cpp | 13 +++++++- src/dialogs/AutoTypeDlg.h | 1 + src/dialogs/TargetWindowDlg.cpp | 3 ++ src/lib/ShortcutWidget.cpp | 56 +++++++++++++++++++++++++++------ src/lib/ShortcutWidget.h | 5 ++- src/mainwindow.cpp | 21 +++++++++++++ src/res/docs/faq.html | 4 +-- src/res/docs/quickstart.html | 21 +++++++++++-- src/src.pro | 17 +++++++++- 10 files changed, 123 insertions(+), 19 deletions(-) diff --git a/src/Kdb3Database.cpp b/src/Kdb3Database.cpp index 86913bc..e7c1e8b 100644 --- a/src/Kdb3Database.cpp +++ b/src/Kdb3Database.cpp @@ -976,6 +976,7 @@ bool Kdb3Database::setFileKey(const QString& filename){ RawMasterKey.lock(); return true; } + file.seek(0); } SHA256 sha; unsigned char* buffer[2048]; diff --git a/src/dialogs/AutoTypeDlg.cpp b/src/dialogs/AutoTypeDlg.cpp index 72904a1..7856958 100644 --- a/src/dialogs/AutoTypeDlg.cpp +++ b/src/dialogs/AutoTypeDlg.cpp @@ -18,6 +18,10 @@ #include #include "AutoTypeDlg.h" +#ifdef Q_WS_MAC +#include "lib/AutoTypeGlobalMacX.h" +#include "lib/HelperMacX.h" +#endif bool AutoTypeDlg::dialogVisible = false; @@ -67,7 +71,7 @@ AutoTypeDlg::AutoTypeDlg(QList entries, QList numbers, bool if (!hideUsernames) entryList->setColumnWidth(1, entryList->columnWidth(1)+10); - connect(ButtonBox, SIGNAL(rejected()), SLOT(close())); + connect(ButtonBox, SIGNAL(rejected()), SLOT(cancelled())); connect(entryList, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SLOT(itemSelected(QTreeWidgetItem*))); connect(entryList, SIGNAL(returnPressed(QTreeWidgetItem*)), SLOT(itemSelected(QTreeWidgetItem*))); } @@ -113,3 +117,10 @@ void AutoTypeDlg::itemSelected(QTreeWidgetItem* item){ close(); autoType->perform(itemToEntry[item].dbHandle, pWasLocked, itemToEntry[item].nr, pWasLocked); } + +void AutoTypeDlg::cancelled(){ + close(); +#ifdef Q_WS_MAC + static_cast(autoType)->cancelled(); +#endif +} diff --git a/src/dialogs/AutoTypeDlg.h b/src/dialogs/AutoTypeDlg.h index dc293c3..a0dbf35 100644 --- a/src/dialogs/AutoTypeDlg.h +++ b/src/dialogs/AutoTypeDlg.h @@ -35,6 +35,7 @@ class AutoTypeDlg : public QWidget, private Ui::AutoTypeDlg private slots: void itemSelected(QTreeWidgetItem* item); + void cancelled(); private: struct AutoTypeEntry { diff --git a/src/dialogs/TargetWindowDlg.cpp b/src/dialogs/TargetWindowDlg.cpp index 245162f..1bc31de 100644 --- a/src/dialogs/TargetWindowDlg.cpp +++ b/src/dialogs/TargetWindowDlg.cpp @@ -23,7 +23,10 @@ TargetWindowDlg::TargetWindowDlg(QWidget* parent) : QDialog(parent){ setupUi(this); QStringList windowTitles = autoType->getAllWindowTitles(); +#ifndef Q_WS_MAC + // on MacX, titles are in top to bottom order which is better than alpha order so no sort windowTitles.sort(); +#endif for (QStringList::const_iterator i = windowTitles.constBegin(); i != windowTitles.constEnd(); ++i) comboWindow->addItem(*i); diff --git a/src/lib/ShortcutWidget.cpp b/src/lib/ShortcutWidget.cpp index 8a260c7..b8c96c1 100644 --- a/src/lib/ShortcutWidget.cpp +++ b/src/lib/ShortcutWidget.cpp @@ -1,10 +1,10 @@ /*************************************************************************** + * Copyright (C) 2009 by Jeff Gibbons * * Copyright (C) 2005-2008 by Felix Geyer * * * * 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; version 2 of the License. * - * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * @@ -19,13 +19,19 @@ #include "ShortcutWidget.h" -#if defined(GLOBAL_AUTOTYPE) && defined(Q_WS_X11) +#if defined(GLOBAL_AUTOTYPE) && (defined(Q_WS_X11) || defined(Q_WS_MAC)) #include -#include #include +#ifdef Q_WS_X11 +#include #include "HelperX11.h" #include "AutoTypeGlobalX11.h" +#endif +#ifdef Q_WS_MAC +#include "lib/HelperMacX.h" +#include "lib/AutoTypeGlobalMacX.h" +#endif ShortcutWidget::ShortcutWidget(QWidget* parent) : QLineEdit(parent), lock(false), failed(false){ } @@ -55,18 +61,36 @@ void ShortcutWidget::keyReleaseEvent(QKeyEvent* event){ void ShortcutWidget::keyEvent(QKeyEvent* event, bool release){ if (release && lock) return; - + +#ifdef Q_WS_X11 AutoTypeGlobalX11* autoTypeGlobal = static_cast(autoType); unsigned int mods = HelperX11::keyboardModifiers(QX11Info::display()); displayShortcut(event->nativeVirtualKey(), release, mods & ControlMask, mods & ShiftMask, mods & autoTypeGlobal->maskAlt(), mods & autoTypeGlobal->maskAltGr(), mods & autoTypeGlobal->maskMeta()); +#endif +#ifdef Q_WS_MAC + AutoTypeGlobalMacX* autoTypeGlobal = static_cast(autoType); + quint32 mods = event->nativeModifiers(); + // mods >> 16 bits denote outside main keyboard eg keypad, arrow keys, home, end, etc + if ((0 != (mods >> 16)) || (0 == mods)) return; + quint32 key = event->nativeVirtualKey(); + // prohibited keys + switch (key) { + case kVK_Delete: case kVK_Escape: case kVK_Return: case kVK_Tab: case kVK_ANSI_KeypadEnter: return; + } + displayShortcut(HelperMacX::keycodeToKeysym(key), release, + mods & autoTypeGlobal->maskCtrl(), mods & autoTypeGlobal->maskShift(), + mods & autoTypeGlobal->maskAlt(), mods & autoTypeGlobal->maskAltGr(), + mods & autoTypeGlobal->maskMeta()); +#endif } void ShortcutWidget::displayShortcut(quint32 key, bool release, bool ctrl, bool shift, bool alt, bool altgr, bool win){ QString text; +#ifdef Q_WS_X11 if (ctrl) text.append(tr("Ctrl")).append(" + "); if (shift) @@ -87,6 +111,20 @@ void ShortcutWidget::displayShortcut(quint32 key, bool release, bool ctrl, bool else{ text.append(static_cast(keysym)); } +#endif +#ifdef Q_WS_MAC + if (ctrl) + text.append(kControlUnicode); + if (shift) + text.append(kShiftUnicode); + if (alt) + text.append(kOptionUnicode); + if (win) + text.append(kCommandUnicode); + KeySym keysym = key; + if (!release && (NoSymbol != keysym)){ + text.append(QChar(keysym).toUpper()); +#endif lock = ctrl || shift || alt || altgr || win; if (lock){ @@ -96,11 +134,13 @@ void ShortcutWidget::displayShortcut(quint32 key, bool release, bool ctrl, bool pShortcut.alt = alt; pShortcut.altgr = altgr; pShortcut.win = win; - failed = autoType->registerGlobalShortcut(pShortcut); - if (!failed) + failed = !autoType->registerGlobalShortcut(pShortcut); + if (failed) setBackgroundColor(QColor(255, 150, 150)); - else + else { setBackgroundColor(Qt::white); + setText(text); + } } } else { @@ -108,8 +148,6 @@ void ShortcutWidget::displayShortcut(quint32 key, bool release, bool ctrl, bool if (failed) setBackgroundColor(Qt::white); } - - setText(text); } void ShortcutWidget::setBackgroundColor(const QColor& c){ diff --git a/src/lib/ShortcutWidget.h b/src/lib/ShortcutWidget.h index 581d7ef..de0a5f8 100644 --- a/src/lib/ShortcutWidget.h +++ b/src/lib/ShortcutWidget.h @@ -4,7 +4,6 @@ * 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; version 2 of the License. * - * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * @@ -21,7 +20,7 @@ #define SHORTCUT_WIDGET_H -#if defined(GLOBAL_AUTOTYPE) && defined(Q_WS_X11) +#if defined(GLOBAL_AUTOTYPE) && (defined(Q_WS_X11) || defined(Q_WS_MAC)) #include "lib/AutoType.h" #endif @@ -30,7 +29,7 @@ class ShortcutWidget : public QLineEdit{ public: ShortcutWidget(QWidget* parent = 0); -#if defined(GLOBAL_AUTOTYPE) && defined(Q_WS_X11) +#if defined(GLOBAL_AUTOTYPE) && (defined(Q_WS_X11) || defined(Q_WS_MAC)) Shortcut shortcut(); void setShortcut(const Shortcut& s); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 556ee3a..91859fd 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -43,6 +43,10 @@ #include "dialogs/ManageBookmarksDlg.h" #include "dialogs/HelpDlg.h" +#if defined(GLOBAL_AUTOTYPE) && defined(Q_WS_MAC) +#include "lib/HelperMacX.h" +#endif + Import_KeePassX_Xml import_KeePassX_Xml; Import_PwManager import_PwManager; Import_KWalletXml import_KWalletXml; @@ -433,6 +437,10 @@ bool KeepassMainWindow::openDatabase(QString filename,bool IsAuto){ QPushButton* readOnlyButton = new QPushButton(tr("Open read-only"), &msgBox); msgBox.addButton(readOnlyButton, QMessageBox::AcceptRole); msgBox.setDefaultButton(readOnlyButton); +#if defined(GLOBAL_AUTOTYPE) && defined(Q_WS_MAC) + // On MacX, QMessageBox is not brought to foreground on exec() when app not already there + HelperMacX::processToFront(HelperMacX::getKeepassxPID()); +#endif msgBox.exec(); if (!msgBox.clickedButton() || msgBox.clickedButton() == msgBox.button(QMessageBox::No)) @@ -454,6 +462,10 @@ bool KeepassMainWindow::openDatabase(QString filename,bool IsAuto){ dlg.setWindowModality(Qt::WindowModal); unlockDlg = &dlg; } +#if defined(GLOBAL_AUTOTYPE) && defined(Q_WS_MAC) + // On MacX, QMessageBox is not brought to foreground on exec() when app not already there + HelperMacX::processToFront(HelperMacX::getKeepassxPID()); +#endif bool rejected = (dlg.exec()==PasswordDialog::Exit_Cancel); if (InUnLock) unlockDlg = NULL; @@ -578,6 +590,10 @@ void KeepassMainWindow::OnFileNewKdb(){ IDatabase* db_new=dynamic_cast(new Kdb3Database()); db_new->create(); PasswordDialog dlg(this,PasswordDialog::Mode_Set,PasswordDialog::Flag_None,"New Database"); +#if defined(GLOBAL_AUTOTYPE) && defined(Q_WS_MAC) + // On MacX, QMessageBox is not brought to foreground on exec() + HelperMacX::processToFront(HelperMacX::getKeepassxPID()); +#endif if(dlg.exec()==PasswordDialog::Exit_Ok){ if(FileOpen) if(!closeDatabase())return; @@ -1323,6 +1339,11 @@ void KeepassMainWindow::OnUnLockWorkspace(){ if(IsLocked){ if (InUnLock) return; InUnLock = true; +#if defined(GLOBAL_AUTOTYPE) && defined(Q_WS_MAC) + // show in case minimized, especially in another Space + // only needed if invoked from global autotype + show(); +#endif if ( openDatabase(currentFilePath,true) ){ QTreeWidgetItem* item = GroupView->invisibleRootItem(); if (lockGroup.size()>0){ diff --git a/src/res/docs/faq.html b/src/res/docs/faq.html index d098029..782bf99 100644 --- a/src/res/docs/faq.html +++ b/src/res/docs/faq.html @@ -9,9 +9,9 @@

KeePassX Frequently Asked Questions

-

Q: Is Auto-Type supported on Mac OS X or Windows?

+

Q: On what platforms is Auto-Type supported?

- A: No, Auto-Type is currently supported on Linux only. + A: Auto-Type is currently supported on Linux and Mac OS X. It is not supported on Windows.

diff --git a/src/res/docs/quickstart.html b/src/res/docs/quickstart.html index 442c668..338210e 100644 --- a/src/res/docs/quickstart.html +++ b/src/res/docs/quickstart.html @@ -147,7 +147,7 @@

-

Setup Auto-Type (currently Linux only)

+

Setup Auto-Type (currently Linux and OS X only)

Auto-Type is a feature that allows you to e.g. log in to web page by hitting only one key combination. @@ -158,7 +158,7 @@ database, it executes a predefined key sequence (by default your username, TAB, password, ENTER) in the active window. This feature is currently available - in the Linux version only. + in the Linux and OS X versions only.

To enable Auto-Type, first go to @@ -221,6 +221,21 @@ By modifing the Auto-Type key sequence you can tailor Auto-Type to suit almost every web login page you'll enter.

+

+ For OS X, there are two additional Auto-Type elements: {CLEARFIELD} and + {MACSENDKEYCODES}. {CLEARFIELD} clears the typing target to ensure + it is empty before typing into it. {MACSENDKEYCODES} should be put at the + beginning of and Auto-Type string to force the use of a more primitive typing + mechanism when the normal mechanism fails. A known case where this is required + is a web site where the login dialog is implemented in flash. The following + is an example:

+ + {MACSENDKEYCODES}{USERNAME}{TAB}{PASSWORD}{ENTER} +

+

+ Also note that the use of {CLEARFIELD} may require the user to define + a somewhat larger Key Stroke Delay in Preferences. +

- \ No newline at end of file + diff --git a/src/src.pro b/src/src.pro index 881a8df..240d261 100644 --- a/src/src.pro +++ b/src/src.pro @@ -80,12 +80,19 @@ unix : !macx : !isEqual(QMAKE_WIN32,1){ #------------------------------------------------------------------------------- macx { isEmpty(PREFIX): PREFIX = /Applications + !isEqual(AUTOTYPE,0){ + DEFINES += AUTOTYPE + !isEqual(GLOBAL_AUTOTYPE,0){ + DEFINES += GLOBAL_AUTOTYPE + } + } TARGET = ../bin/KeePassX target.path = $${PREFIX} data.files += ../share/keepassx data.path = Contents/Resources INSTALLS += data LIBS += -framework CoreFoundation + LIBS += -framework Carbon isEqual(LINK,DYNAMIC){ isEmpty(QT_FRAMEWORK_DIR): QT_FRAMEWORK_DIR = /Library/Frameworks private_frameworks.files += $${QT_FRAMEWORK_DIR}/QtCore.framework @@ -95,7 +102,7 @@ macx { QMAKE_BUNDLE_DATA += private_frameworks } isEqual(LINK,STATIC){ - LIBS += -framework Carbon -framework AppKit -lz + LIBS += -framework AppKit -lz } QMAKE_BUNDLE_DATA += data QMAKE_INFO_PLIST= ../share/macx_bundle/Info.plist @@ -106,6 +113,14 @@ macx { } isEqual(ARCH,INTEL): CONFIG += x86 isEqual(ARCH,PPC): CONFIG += ppc + contains(DEFINES,AUTOTYPE){ + SOURCES += lib/HelperMacX.cpp lib/AutoTypeMacX.cpp + HEADERS += lib/HelperMacX.h lib/AutoTypeMacX.h + } + contains(DEFINES,GLOBAL_AUTOTYPE){ + SOURCES += lib/AutoTypeGlobalMacX.cpp + HEADERS += lib/AutoTypeGlobalMacX.h + } # SOURCES += main_macx.cpp }