From 794a378927295adcdefb794c1bb92afb5fd23ec2 Mon Sep 17 00:00:00 2001
From: bdmayes
Date: Wed, 19 May 2010 05:57:39 +0000
Subject: [PATCH] Updating quick-start guide and performed svn add for OS X
auto-type files that were previously left out in revision 383.
git-svn-id: https://svn.code.sf.net/p/keepassx/code/trunk@384 b624d157-de02-0410-bad0-e51aec6abb33
---
src/lib/AutoTypeGlobalMacX.cpp | 266 ++++++++++++++++
src/lib/AutoTypeGlobalMacX.h | 52 ++++
src/lib/AutoTypeMacX.cpp | 554 +++++++++++++++++++++++++++++++++
src/lib/AutoTypeMacX.h | 83 +++++
src/lib/HelperMacX.cpp | 238 ++++++++++++++
src/lib/HelperMacX.h | 40 +++
src/res/docs/quickstart.html | 3 +-
7 files changed, 1235 insertions(+), 1 deletion(-)
create mode 100644 src/lib/AutoTypeGlobalMacX.cpp
create mode 100644 src/lib/AutoTypeGlobalMacX.h
create mode 100644 src/lib/AutoTypeMacX.cpp
create mode 100644 src/lib/AutoTypeMacX.h
create mode 100644 src/lib/HelperMacX.cpp
create mode 100644 src/lib/HelperMacX.h
diff --git a/src/lib/AutoTypeGlobalMacX.cpp b/src/lib/AutoTypeGlobalMacX.cpp
new file mode 100644
index 0000000..a821d73
--- /dev/null
+++ b/src/lib/AutoTypeGlobalMacX.cpp
@@ -0,0 +1,266 @@
+/***************************************************************************
+ * Copyright (C) 2009 Jeff Gibbons *
+ * Copyright (C) 2005-2008 by Tarek Saidi, Felix Geyer *
+ * tarek.saidi@arcor.de *
+ * *
+ * 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 *
+ * 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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "lib/AutoTypeGlobalMacX.h"
+#include "mainwindow.h"
+#include "lib/HelperMacX.h"
+#include "dialogs/AutoTypeDlg.h"
+
+AutoTypeGlobal* autoType = NULL;
+
+static bool inHotKeyEvent = false;
+
+static OSStatus hotKeyHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
+
+void initAutoType(KeepassMainWindow* mainWin){
+ autoType = new AutoTypeGlobalMacX(mainWin);
+}
+
+AutoTypeGlobalMacX::AutoTypeGlobalMacX(KeepassMainWindow* mainWin) : AutoTypeMacX(mainWin){
+ shortcut.key = 0;
+ oldCode = 0;
+ oldMod = 0;
+ inGlobalAutoType = false;
+
+ // initialize hot key handling
+ hotKeyRef = NULL;
+ hotKeyID.signature = 'kpsx';
+ hotKeyID.id = 1;
+ EventTypeSpec eventType;
+ eventType.eventClass = kEventClassKeyboard;
+ eventType.eventKind = kEventHotKeyPressed;
+ InstallApplicationEventHandler(&hotKeyHandler, 1, &eventType, this, NULL);
+}
+
+OSStatus hotKeyHandler(EventHandlerCallRef, EventRef, void *userData){
+ // ignore nextHandler - should not be called
+ if ((inHotKeyEvent) || HelperMacX::isFrontProcess(HelperMacX::getKeepassxPID())) return noErr;
+ inHotKeyEvent = true;
+ ((AutoTypeGlobalMacX*)userData)->performGlobal();
+ inHotKeyEvent = false;
+ return noErr;
+}
+
+void AutoTypeGlobalMacX::cancelled(){
+ pid_t pid;
+ if (HelperMacX::getTargetWindowInfo(&pid, NULL, NULL, 0))
+ HelperMacX::processToFront(pid);
+ else HelperMacX::processToFront(targetPID);
+ targetPID = 0;
+}
+
+void AutoTypeGlobalMacX::updateKeymap(){
+ AutoTypeMacX::updateKeymap();
+ registerGlobalShortcut(shortcut);
+}
+
+void AutoTypeGlobalMacX::perform(IEntryHandle* entry, bool hideWindow, int nr, bool wasLocked){
+ if (inGlobalAutoType)
+ return;
+ inGlobalAutoType = true;
+ AutoTypeMacX::perform(entry, hideWindow, nr, wasLocked);
+ inGlobalAutoType = false;
+}
+
+QStringList AutoTypeGlobalMacX::getAllWindowTitles(){
+ QStringList titleList;
+ char windowName[256];
+ pid_t keepassxPID = HelperMacX::getKeepassxPID();
+ CFArrayRef windowInfo = CGWindowListCopyWindowInfo(
+ kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
+ CFIndex windowCount = CFArrayGetCount(windowInfo);
+ for (CFIndex i = 0; i < windowCount; i++){
+ CFDictionaryRef window = (CFDictionaryRef)CFArrayGetValueAtIndex(windowInfo, i);
+ // only want windows in layer 0
+ CFNumberRef windowLayerRef = (CFNumberRef)CFDictionaryGetValue(window, kCGWindowLayer);
+ int windowLayer = -1;
+ CFNumberGetValue(windowLayerRef, kCFNumberIntType, &windowLayer);
+ if (0 != windowLayer) continue;
+ // get the pid owning this window
+ CFNumberRef pidRef = (CFNumberRef)CFDictionaryGetValue(window, kCGWindowOwnerPID);
+ pid_t pid = -1;
+ CFNumberGetValue(pidRef, kCFNumberIntType, &pid);
+ // skip KeePassX windows
+ if (keepassxPID == pid) continue;
+ // get window name; continue if no name
+ CFStringRef windowNameRef = (CFStringRef)CFDictionaryGetValue(window, kCGWindowName);
+ if (!windowNameRef) continue;
+ windowName[0] = 0;
+ if (!CFStringGetCString(windowNameRef, windowName, sizeof(windowName), kCFStringEncodingUTF8) ||
+ (0 == windowName[0]))
+ continue;
+ titleList.append(QString::fromUtf8(windowName));
+ }
+ CFRelease(windowInfo);
+ return titleList;
+}
+
+void AutoTypeGlobalMacX::performGlobal(){
+ if (AutoTypeDlg::isDialogVisible()) {
+ qWarning("Already performing auto-type, ignoring this one");
+ return;
+ }
+ char titleUtf8[256];
+ titleUtf8[0] = 0;
+ if (!HelperMacX::getTargetWindowInfo(&targetPID, &windowNumber, titleUtf8, sizeof(titleUtf8))
+ || (0 == titleUtf8[0])) {
+ targetPID = 0;
+ return;
+ }
+
+ bool wasLocked = mainWin->isLocked();
+ if (wasLocked)
+ mainWin->OnUnLockWorkspace();
+
+ if (!mainWin->isOpened()) {
+ targetPID = 0;
+ return;
+ }
+ QString title = QString::fromUtf8(titleUtf8).toLower();
+
+ QList validEntries;
+ QList entryNumbers;
+ QList entries = mainWin->db->entries();
+ QRegExp lineMatch("Auto-Type-Window(?:-(\\d+)|):([^\\n]+)", Qt::CaseInsensitive, QRegExp::RegExp2);
+ QDateTime now = QDateTime::currentDateTime();
+ for (int i=0; iexpire()!=Date_Never && entries[i]->expire()comment();
+ int offset = 0;
+ while ( (offset=lineMatch.indexIn(comment, offset))!=-1 ){
+ QStringList captured = lineMatch.capturedTexts();
+ offset += captured[0].length();
+ int nr;
+ QString entryWindow;
+ bool valid;
+ if (captured.size()==2){
+ nr = 0;
+ entryWindow = captured[1].trimmed().toLower();
+ }
+ else{
+ nr = captured[1].toInt();
+ entryWindow = captured[2].trimmed().toLower();
+ }
+ if (entryWindow.length()==0) continue;
+
+ hasWindowEntry = true;
+ bool wildStart = (entryWindow[0]=='*');
+ bool wildEnd = (entryWindow[entryWindow.size()-1]=='*');
+ if (wildStart&&wildEnd){
+ entryWindow.remove(0,1);
+ if (entryWindow.length()!=0){
+ entryWindow.remove(entryWindow.size()-1,1);
+ valid = title.contains(entryWindow);
+ }
+ else
+ valid = true;
+ }
+ else if (wildStart){
+ entryWindow.remove(0,1);
+ valid = title.endsWith(entryWindow);
+ }
+ else if (wildEnd){
+ entryWindow.remove(entryWindow.size()-1,1);
+ valid = title.startsWith(entryWindow);
+ }
+ else {
+ valid = (title==entryWindow);
+ }
+
+ if (valid){
+ validEntries << entries[i];
+ entryNumbers << nr;
+ break;
+ }
+ }
+
+ if (!hasWindowEntry && config->entryTitlesMatch()){
+ QString entryTitle = entries[i]->title().toLower();
+ if (!entryTitle.isEmpty() && title.contains(entryTitle)){
+ validEntries << entries[i];
+ entryNumbers << 0;
+ }
+ }
+ }
+
+ if (validEntries.size()==1){
+ perform(validEntries[0],wasLocked,entryNumbers[0],wasLocked);
+ }
+ else if (validEntries.size()>1){
+ AutoTypeDlg* dlg = new AutoTypeDlg(validEntries, entryNumbers, wasLocked);
+ HelperMacX::processToFront(HelperMacX::getKeepassxPID());
+ dlg->show();
+ }
+}
+
+bool AutoTypeGlobalMacX::registerGlobalShortcut(const Shortcut& s){
+
+ if (s.key == 0)
+ return false;
+
+ int code=HelperMacX::keysymToKeycode(s.key);
+ uint mod=HelperMacX::getShortcutModifierMask(s);
+
+ if (s.key==shortcut.key && s.ctrl==shortcut.ctrl && s.shift==shortcut.shift && s.alt==shortcut.alt
+ && s.altgr==shortcut.altgr && s.win==shortcut.win && code==oldCode && mod==oldMod)
+ return true;
+
+ // need to unregister old before registering new
+ unregisterGlobalShortcut();
+ OSStatus status = RegisterEventHotKey(code, mod, hotKeyID, GetApplicationEventTarget(), 0, &hotKeyRef);
+ if (noErr == status) {
+ shortcut = s;
+ oldCode = code;
+ oldMod = mod;
+ return true;
+ } else {
+ qWarning("Error registering global shortcut: %d", (int)status);
+ RegisterEventHotKey(oldCode, oldMod, hotKeyID, GetApplicationEventTarget(), 0, &hotKeyRef);
+ return false;
+ }
+}
+
+void AutoTypeGlobalMacX::unregisterGlobalShortcut(){
+ if (shortcut.key==0) return;
+
+ if (NULL != hotKeyRef) {
+ UnregisterEventHotKey(hotKeyRef);
+ hotKeyRef = NULL;
+ }
+
+ shortcut.key = 0;
+ oldCode = 0;
+ oldMod = 0;
+}
+
+QString AutoTypeGlobalMacX::getRootGroupName(IEntryHandle* entry){
+ IGroupHandle* group = entry->group();
+ int level = group->level();
+ for (int i=0; iparent();
+
+ return group->title();
+}
diff --git a/src/lib/AutoTypeGlobalMacX.h b/src/lib/AutoTypeGlobalMacX.h
new file mode 100644
index 0000000..f2d85fd
--- /dev/null
+++ b/src/lib/AutoTypeGlobalMacX.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * Copyright (C) 2009 Jeff Gibbons *
+ * Copyright (C) 2005-2008 by Tarek Saidi, Felix Geyer *
+ * tarek.saidi@arcor.de *
+ * *
+ * 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 *
+ * 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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef _AUTOTYPEGLOBALMACX_H_
+#define _AUTOTYPEGLOBALMACX_H_
+
+#include "lib/AutoTypeMacX.h"
+
+class AutoTypeGlobalMacX : public AutoTypeMacX, public AutoTypeGlobal{
+ public:
+ AutoTypeGlobalMacX(KeepassMainWindow* mainWin);
+ void perform(IEntryHandle* entry, bool hideWindow=true, int nr=0, bool wasLocked=false);
+ void performGlobal();
+ bool registerGlobalShortcut(const Shortcut& s);
+ void unregisterGlobalShortcut();
+ QStringList getAllWindowTitles();
+ void cancelled();
+ void updateKeymap();
+ inline int maskShift() { return shift_mask; };
+ inline int maskCtrl() { return ctrl_mask; };
+ inline int maskAlt() { return alt_mask; };
+ inline int maskAltGr() { return altgr_mask; };
+ inline int maskMeta() { return meta_mask; };
+
+ private:
+ QString getRootGroupName(IEntryHandle* entry);
+
+ int oldCode;
+ uint oldMod;
+
+ EventHotKeyRef hotKeyRef;
+ EventHotKeyID hotKeyID;
+};
+
+#endif // _AUTOTYPEGLOBALMACX_H_
diff --git a/src/lib/AutoTypeMacX.cpp b/src/lib/AutoTypeMacX.cpp
new file mode 100644
index 0000000..a7050db
--- /dev/null
+++ b/src/lib/AutoTypeMacX.cpp
@@ -0,0 +1,554 @@
+/***************************************************************************
+ * Copyright (C) 2009-2010 Jeff Gibbons *
+ * Copyright (C) 2005-2008 by Tarek Saidi, Felix Geyer *
+ * tarek.saidi@arcor.de *
+ * *
+ * 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 *
+ * 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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "lib/AutoTypeMacX.h"
+#include "lib/HelperMacX.h"
+#include "mainwindow.h"
+
+#ifndef GLOBAL_AUTOTYPE
+AutoType* autoType = NULL;
+
+void initAutoType(KeepassMainWindow* mainWin) {
+ autoType = new AutoTypeMacX(mainWin);
+}
+#endif
+
+// resusable events
+static CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, 0, true);
+static CGEventRef unicodeEvent = CGEventCreateKeyboardEvent(NULL, 0, true);
+
+#define UNICODE_BUFFER_SIZE 20 // max from documentation
+static UniChar unicodeBuffer[UNICODE_BUFFER_SIZE];
+static UniCharCount unicodePtr = 0;
+
+AutoTypeAction::AutoTypeAction(AutoTypeActionType t, quint16 data)
+ : type(t), data(data){}
+AutoTypeAction::AutoTypeAction(AutoTypeActionType t, KeycodeWithMods keycodeWithMods)
+ : type(t), keycodeWithMods(keycodeWithMods){}
+
+AutoTypeMacX::AutoTypeMacX(KeepassMainWindow* mainWin){
+ this->mainWin = mainWin;
+ inAutoType = false;
+ targetPID = 0;
+
+ ctrl_mask = controlKey;
+ shift_mask = shiftKey;
+ alt_mask = optionKey;
+ meta_mask = cmdKey;
+ altgr_mask = 0;
+
+ updateKeymap();
+}
+
+void AutoTypeMacX::updateKeymap(){
+ HelperMacX::initUnicodeToKeycodeWithModsMap();
+}
+
+void AutoTypeMacX::perform(IEntryHandle* entry, bool hideWindow, int nr, bool wasLocked){
+ if (inAutoType)
+ return;
+ if ((0 == targetPID) && !HelperMacX::getTargetWindowInfo(&targetPID, &windowNumber, NULL, 0)) {
+ targetPID = 0;
+ return;
+ }
+ inAutoType = true;
+
+ QString indexStr;
+ if (nr==0)
+ indexStr = "Auto-Type:";
+ else
+ indexStr = QString("Auto-Type-%1:").arg(nr);
+ QString str;
+ QString comment=entry->comment();
+ int c=comment.count(indexStr, Qt::CaseInsensitive);
+ if(c>1) {
+ qWarning("More than one 'Auto-Type:' key sequence found.\nAllowed is only one per entry.");
+ targetPID = 0;
+ inAutoType = false;
+ return;
+ }
+ else if (c==1) {
+ int start = comment.indexOf(indexStr,0,Qt::CaseInsensitive) + indexStr.length();
+ int end = comment.indexOf("\n", start);
+ if (end == -1)
+ end = comment.length();
+
+ str=comment.mid(start,end-start).trimmed();
+ if (str.isEmpty()) {
+ targetPID = 0;
+ inAutoType = false;
+ return;
+ }
+ }
+ else {
+ bool usernameEmpty = entry->username().trimmed().isEmpty();
+ SecString password=entry->password();
+ password.unlock();
+ bool passwordEmpty = password.string().trimmed().isEmpty();
+ if (usernameEmpty && passwordEmpty) {
+ targetPID = 0;
+ inAutoType = false;
+ return;
+ }
+ else if (usernameEmpty)
+ str="{PASSWORD}{ENTER}";
+ else if (passwordEmpty)
+ str="{USERNAME}{ENTER}";
+ else
+ str="{USERNAME}{TAB}{PASSWORD}{ENTER}";
+ }
+
+ HelperMacX::processToFront(targetPID);
+ appSignature = HelperMacX::getProcessSignature(targetPID);
+ checkWindowType();
+ targetPID = 0;
+ if (hideWindow)
+ mainWin->hide();
+
+ QList Keys;
+ for(int i=0;i=str.size()){
+ qWarning("Syntax Error in Auto-Type sequence near character %d\nFound '{' without closing '}'", i+10);
+ break;
+ }
+ templateToKeysyms(tmpl.toLower(),Keys,entry);
+ continue;
+ }
+ else{
+ Keys << AutoTypeAction(SendUnicodeAction, str[i].unicode());
+ }
+ }
+
+ QApplication::processEvents();
+ sleepTime(config->autoTypePreGap());
+
+ QString type;
+ for(int i=0;ilockOnMinimize()){
+ if (hideWindow || wasLocked){
+ if ( !(config->showSysTrayIcon() && config->minimizeTray()) )
+ mainWin->showMinimized();
+ else
+ mainWin->OnUnLockWorkspace();
+ }
+ }
+ else{
+ if (hideWindow && !(config->showSysTrayIcon() && config->minimizeTray()) )
+ mainWin->showMinimized();
+ }
+
+ inAutoType = false;
+}
+
+void AutoTypeMacX::sleepTime(int msec){
+ if (msec==0) return;
+ timespec timeOut, remains;
+ timeOut.tv_sec = msec/1000;
+ timeOut.tv_nsec = (msec%1000)*1000000;
+ nanosleep(&timeOut, &remains);
+}
+
+void AutoTypeMacX::templateToKeysyms(const QString& tmpl, QList& keys,IEntryHandle* entry){
+ //tmpl must be lower case!!!
+ if(!tmpl.compare("title")){
+ stringToKeysyms(entry->title(),keys);
+ return;
+ }
+ if(!tmpl.compare("username")){
+ stringToKeysyms(entry->username(),keys);
+ return;
+ }
+ if(!tmpl.compare("url")){
+ stringToKeysyms(entry->url(),keys);
+ return;
+ }
+ if(!tmpl.compare("password")){
+ SecString password=entry->password();
+ password.unlock();
+ stringToKeysyms(password,keys);
+ return;
+ }
+ if(!tmpl.compare("space")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_Space, 0});
+ return;
+ }
+
+ if(!tmpl.compare("backspace") || !tmpl.compare("bs") || !tmpl.compare("bksp")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_Delete, 0});
+ return;
+ }
+
+// if(!tmpl.compare("break")){
+// keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){?, 0});
+// return;
+// }
+
+ if(!tmpl.compare("capslock")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_CapsLock, 0});
+ return;
+ }
+
+ if(!tmpl.compare("del") || !tmpl.compare("delete")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_ForwardDelete, 0});
+ return;
+ }
+
+ if(!tmpl.compare("end")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_End, 0});
+ return;
+ }
+
+ if(!tmpl.compare("enter")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_Return, 0});
+ return;
+ }
+
+ if(!tmpl.compare("esc")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_Escape, 0});
+ return;
+ }
+
+ if(!tmpl.compare("help")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_Help, 0});
+ return;
+ }
+
+ if(!tmpl.compare("home")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_Home, 0});
+ return;
+ }
+
+ if(!tmpl.compare("insert") || !tmpl.compare("ins")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_Help, 0});
+ return;
+ }
+
+ if(!tmpl.compare("numlock")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_ANSI_KeypadClear, 0});
+ return;
+ }
+
+// if(!tmpl.compare("scroll")){
+// keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){?, 0});
+// return;
+// }
+
+ if(!tmpl.compare("pgdn")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_PageDown, 0});
+ return;
+ }
+
+ if(!tmpl.compare("pgup")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_PageUp, 0});
+ return;
+ }
+
+ if(!tmpl.compare("prtsc")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F13, 0});
+ return;
+ }
+
+ if(!tmpl.compare("up")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_UpArrow, 0});
+ return;
+ }
+
+ if(!tmpl.compare("down")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_DownArrow, 0});
+ return;
+ }
+
+ if(!tmpl.compare("left")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_LeftArrow, 0});
+ return;
+ }
+
+ if(!tmpl.compare("right")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_RightArrow, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f1")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F1, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f2")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F2, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f3")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F3, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f4")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F4, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f5")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F5, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f6")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F6, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f7")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F7, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f8")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F8, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f9")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F9, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f10")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F10, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f11")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F11, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f12")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F12, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f13")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F13, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f14")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F14, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f15")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F15, 0});
+ return;
+ }
+
+ if(!tmpl.compare("f16")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_F16, 0});
+ return;
+ }
+
+ if(!tmpl.compare("add") || !tmpl.compare("plus")){
+ keys << AutoTypeAction(SendUnicodeAction, '+');
+ return;
+ }
+
+ if(!tmpl.compare("subtract")){
+ keys << AutoTypeAction(SendUnicodeAction, '-');
+ return;
+ }
+
+ if(!tmpl.compare("multiply")){
+ keys << AutoTypeAction(SendUnicodeAction, '*');
+ return;
+ }
+
+ if(!tmpl.compare("divide")){
+ keys << AutoTypeAction(SendUnicodeAction, '/');
+ return;
+ }
+
+ if(!tmpl.compare("at")){
+ keys << AutoTypeAction(SendUnicodeAction, '@');
+ return;
+ }
+
+ if(!tmpl.compare("percent")){
+ keys << AutoTypeAction(SendUnicodeAction, '%');
+ return;
+ }
+
+ if(!tmpl.compare("caret")){
+ keys << AutoTypeAction(SendUnicodeAction, '^');
+ return;
+ }
+
+ if(!tmpl.compare("tilde")){
+ keys << AutoTypeAction(SendUnicodeAction, '~');
+ return;
+ }
+
+ if(!tmpl.compare("leftbrace")){
+ keys << AutoTypeAction(SendUnicodeAction, '{');
+ return;
+ }
+
+ if(!tmpl.compare("rightbrace")){
+ keys << AutoTypeAction(SendUnicodeAction, '}');
+ return;
+ }
+
+ if(!tmpl.compare("leftparen")){
+ keys << AutoTypeAction(SendUnicodeAction, '(');
+ return;
+ }
+
+ if(!tmpl.compare("rightparen")){
+ keys << AutoTypeAction(SendUnicodeAction, ')');
+ return;
+ }
+
+ if(!tmpl.compare("tab")){
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_Tab, 0});
+ return;
+ }
+
+ if(tmpl.startsWith("unicode ") && tmpl.length() > 8){
+ char* str = tmpl.right(tmpl.length() - 8).toUtf8().data();
+ int n;
+ uint16 unicode;
+ while (1 == sscanf(str, " %hi%n", &unicode, &n)) {
+ keys << AutoTypeAction(SendUnicodeAction, unicode);
+ str += n;
+ }
+ return;
+ }
+
+ if(!tmpl.compare("clearfield")){
+ if(('x11a' == appSignature) || ('????' == appSignature)){
+ // ^A to beginning of line then ^K kill to end of line for X11 or Terminal.app
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_ANSI_A, controlKey >> 8});
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_ANSI_K, controlKey >> 8});
+ } else {
+ // Cmd-A to select all then delete for everything else
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_ANSI_A, cmdKey >> 8});
+ keys << AutoTypeAction(SendKeycodeAction, (KeycodeWithMods){kVK_ForwardDelete, 0});
+ }
+ return;
+ }
+
+ if(tmpl.startsWith("macsendkeycodes")){
+ onlySendKeycodes = true;
+ }
+
+ if(tmpl.startsWith("delay ") && tmpl.length()>6){
+ bool ok;
+ quint16 delay = tmpl.right(tmpl.length()-6).toInt(&ok);
+ if (ok && delay>0 && delay<=10000)
+ keys << AutoTypeAction(DelayAction, delay);
+ return;
+ }
+}
+
+void AutoTypeMacX::stringToKeysyms(const QString& string,QList& KeySymList){
+ for(int i=0; i
+
+typedef quint32 KeySym;
+#define NoSymbol (KeySym)0
+#define NoKeycode (uint16)-1
+
+struct KeycodeWithMods {
+ uint16 keycode;
+ uint16 mods;
+};
+
+enum AutoTypeActionType{
+ SendUnicodeAction, SendKeycodeAction, DelayAction
+};
+
+struct AutoTypeAction{
+ AutoTypeAction(AutoTypeActionType t, quint16 data);
+ AutoTypeAction(AutoTypeActionType t, KeycodeWithMods keycodeWithMods);
+ AutoTypeActionType type;
+ union {
+ quint16 data;
+ KeycodeWithMods keycodeWithMods;
+ };
+};
+
+class AutoTypeMacX : public AutoType {
+ public:
+ AutoTypeMacX(KeepassMainWindow* mainWin);
+ void perform(IEntryHandle* entry, bool hideWindow=true, int nr=0, bool wasLocked=false);
+ virtual void updateKeymap();
+
+ protected:
+ void sleepTime(int msec);
+ inline void sleepKeyStrokeDelay(){ sleepTime(config->autoTypeKeyStrokeDelay()); };
+ void templateToKeysyms(const QString& Template, QList& KeySymList,IEntryHandle* entry);
+ void stringToKeysyms(const QString& string,QList& KeySymList);
+ void sendKeycode(KeycodeWithMods keycodeWithMods);
+ void sendUnicode(KeySym keysym);
+ void flushUnicode();
+
+ KeepassMainWindow* mainWin;
+
+ int ctrl_mask;
+ int shift_mask;
+ int alt_mask;
+ int meta_mask;
+ int altgr_mask;
+ bool inGlobalAutoType;
+ pid_t targetPID;
+ int windowNumber;
+
+ private:
+ bool inAutoType;
+ OSType appSignature;
+ bool onlySendKeycodes;
+ void checkWindowType();
+ void keyDownUp(CGEventRef theEvent);
+};
+
+#endif // _AUTOTYPEMACX_H_
diff --git a/src/lib/HelperMacX.cpp b/src/lib/HelperMacX.cpp
new file mode 100644
index 0000000..c1d1abe
--- /dev/null
+++ b/src/lib/HelperMacX.cpp
@@ -0,0 +1,238 @@
+/***************************************************************************
+ * Copyright (C) 2009 by Jeff Gibbons *
+ * *
+ * 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 *
+ * 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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "lib/HelperMacX.h"
+#include
Also note that the use of {CLEARFIELD} may require the user to define
- a somewhat larger Key Stroke Delay in Preferences.
+ a somewhat larger Key Stroke Delay in Preferences when specified for a site
+ with flash-based login fields.