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-e51aec6abb33master
parent
c5c10b6220
commit
794a378927
@ -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<IEntryHandle*> validEntries; |
||||||
|
QList<int> entryNumbers; |
||||||
|
QList<IEntryHandle*> entries = mainWin->db->entries(); |
||||||
|
QRegExp lineMatch("Auto-Type-Window(?:-(\\d+)|):([^\\n]+)", Qt::CaseInsensitive, QRegExp::RegExp2); |
||||||
|
QDateTime now = QDateTime::currentDateTime(); |
||||||
|
for (int i=0; i<entries.size(); i++){ |
||||||
|
if ( (entries[i]->expire()!=Date_Never && entries[i]->expire()<now) || |
||||||
|
(getRootGroupName(entries[i]).compare("backup",Qt::CaseInsensitive)==0) |
||||||
|
){ |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
bool hasWindowEntry=false; |
||||||
|
QString comment = entries[i]->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; i<level; i++) |
||||||
|
group = group->parent(); |
||||||
|
|
||||||
|
return group->title(); |
||||||
|
} |
@ -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_
|
@ -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<AutoTypeAction> Keys; |
||||||
|
for(int i=0;i<str.size();i++){ |
||||||
|
if(str[i]=='{'){ |
||||||
|
QString tmpl; |
||||||
|
i++; |
||||||
|
while(str[i]!='}' && i<str.size()){ |
||||||
|
tmpl += str[i]; |
||||||
|
i++; |
||||||
|
} |
||||||
|
if(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;i<Keys.size();i++){ |
||||||
|
int currentWindowNumber; |
||||||
|
if (!HelperMacX::getTargetWindowInfo(NULL, ¤tWindowNumber, NULL, 0) |
||||||
|
|| (windowNumber != currentWindowNumber)) { |
||||||
|
qWarning("Focus window changed, interrupting auto-type"); |
||||||
|
unicodePtr = 0; |
||||||
|
break; |
||||||
|
} |
||||||
|
if (Keys[i].type==SendKeycodeAction){ |
||||||
|
sendKeycode(Keys[i].keycodeWithMods); |
||||||
|
} |
||||||
|
else if (Keys[i].type==SendUnicodeAction){ |
||||||
|
sendUnicode(Keys[i].data); |
||||||
|
} |
||||||
|
else if (Keys[i].type==DelayAction){ |
||||||
|
flushUnicode(); |
||||||
|
QApplication::processEvents(); |
||||||
|
sleepTime(Keys[i].data); |
||||||
|
} |
||||||
|
} |
||||||
|
flushUnicode(); |
||||||
|
|
||||||
|
if (config->lockOnMinimize()){ |
||||||
|
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<AutoTypeAction>& 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<AutoTypeAction>& KeySymList){ |
||||||
|
for(int i=0; i<string.length();i++) |
||||||
|
KeySymList << AutoTypeAction(SendUnicodeAction, string[i].unicode()); |
||||||
|
} |
||||||
|
|
||||||
|
void AutoTypeMacX::keyDownUp(CGEventRef theEvent){ |
||||||
|
// posting Key Down/Up events also annoyingly sets mouse location so must first get
|
||||||
|
// current mouse location and set it in the event
|
||||||
|
CGEventRef eventLocation = CGEventCreate(NULL); |
||||||
|
CGEventSetLocation(theEvent, CGEventGetLocation(eventLocation)); |
||||||
|
CFRelease(eventLocation); |
||||||
|
|
||||||
|
CGEventSetType(theEvent, kCGEventKeyDown); |
||||||
|
CGEventPost(kCGHIDEventTap, theEvent); |
||||||
|
CGEventSetType(theEvent, kCGEventKeyUp); |
||||||
|
CGEventPost(kCGHIDEventTap, theEvent); |
||||||
|
} |
||||||
|
|
||||||
|
void AutoTypeMacX::sendKeycode(KeycodeWithMods keycodeWithMods){ |
||||||
|
flushUnicode(); |
||||||
|
uint keycode = keycodeWithMods.keycode; |
||||||
|
uint mods = keycodeWithMods.mods << 8;
|
||||||
|
uint flags = 0; |
||||||
|
if (0 != ( shiftKey & mods)) flags |= kCGEventFlagMaskShift; |
||||||
|
if (0 != (controlKey & mods)) flags |= kCGEventFlagMaskControl; |
||||||
|
if (0 != ( optionKey & mods)) flags |= kCGEventFlagMaskAlternate; |
||||||
|
if (0 != ( cmdKey & mods)) flags |= kCGEventFlagMaskCommand; |
||||||
|
CGEventSetIntegerValueField(keyEvent, kCGKeyboardEventKeycode, (int64_t)keycode); |
||||||
|
CGEventSetFlags(keyEvent, flags); |
||||||
|
keyDownUp(keyEvent); |
||||||
|
sleepKeyStrokeDelay(); |
||||||
|
} |
||||||
|
|
||||||
|
void AutoTypeMacX::sendUnicode(KeySym keysym){ |
||||||
|
if (onlySendKeycodes) { |
||||||
|
KeycodeWithMods keycodeWithMods = HelperMacX::keysymToKeycodeWithMods(keysym); |
||||||
|
if (NoKeycode == keycodeWithMods.keycode) return; |
||||||
|
sendKeycode(keycodeWithMods); |
||||||
|
return; |
||||||
|
} |
||||||
|
unicodeBuffer[unicodePtr++] = keysym; |
||||||
|
if (UNICODE_BUFFER_SIZE == unicodePtr) flushUnicode(); |
||||||
|
} |
||||||
|
|
||||||
|
void AutoTypeMacX::flushUnicode(){ |
||||||
|
if (0 == unicodePtr) return; |
||||||
|
CGEventKeyboardSetUnicodeString(unicodeEvent, unicodePtr, unicodeBuffer); |
||||||
|
keyDownUp(unicodeEvent); |
||||||
|
unicodePtr = 0; |
||||||
|
sleepKeyStrokeDelay(); |
||||||
|
} |
||||||
|
|
||||||
|
void AutoTypeMacX::checkWindowType(){ |
||||||
|
// sendUnicode does not work with X11 windows so revert to only send keycodes
|
||||||
|
// this can be extended if other types of windows prove to fail for unicode
|
||||||
|
onlySendKeycodes = 'x11a' == appSignature; |
||||||
|
} |
@ -0,0 +1,83 @@ |
|||||||
|
/***************************************************************************
|
||||||
|
* 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. * |
||||||
|
***************************************************************************/ |
||||||
|
|
||||||
|
#ifndef _AUTOTYPEMACX_H_ |
||||||
|
#define _AUTOTYPEMACX_H_ |
||||||
|
|
||||||
|
#include "lib/AutoType.h" |
||||||
|
#include <Carbon/Carbon.h> |
||||||
|
|
||||||
|
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<AutoTypeAction>& KeySymList,IEntryHandle* entry); |
||||||
|
void stringToKeysyms(const QString& string,QList<AutoTypeAction>& 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_
|
@ -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 <map> |
||||||
|
|
||||||
|
static pid_t keepassxPID; |
||||||
|
|
||||||
|
#ifdef GLOBAL_AUTOTYPE |
||||||
|
#include "lib/AutoTypeGlobalMacX.h" |
||||||
|
|
||||||
|
uint HelperMacX::getShortcutModifierMask(const Shortcut& s){ |
||||||
|
AutoTypeGlobalMacX* autoTypeGlobal = static_cast<AutoTypeGlobalMacX*>(autoType); |
||||||
|
|
||||||
|
uint mod = 0; |
||||||
|
if (s.ctrl) mod |= autoTypeGlobal->maskCtrl(); |
||||||
|
if (s.shift) mod |= autoTypeGlobal->maskShift(); |
||||||
|
if (s.alt) mod |= autoTypeGlobal->maskAlt(); |
||||||
|
if (s.altgr) mod |= autoTypeGlobal->maskAltGr(); |
||||||
|
if (s.win) mod |= autoTypeGlobal->maskMeta(); |
||||||
|
|
||||||
|
return mod; |
||||||
|
} |
||||||
|
|
||||||
|
Boolean HelperMacX::isFrontProcess(pid_t pid){ |
||||||
|
Boolean result; |
||||||
|
ProcessSerialNumber pidPSN; |
||||||
|
ProcessSerialNumber frontPSN; |
||||||
|
OSStatus status = GetProcessForPID(pid, &pidPSN); |
||||||
|
if (noErr != status) { |
||||||
|
qWarning("HelperMacX::isFrontProcess: GetProcessForPID error for pid %d: %d", pid, (int)status); |
||||||
|
return false; |
||||||
|
} |
||||||
|
GetFrontProcess(&frontPSN); |
||||||
|
SameProcess(&pidPSN, &frontPSN, &result); |
||||||
|
return result; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
pid_t HelperMacX::getKeepassxPID(){ |
||||||
|
if (0 == keepassxPID) { |
||||||
|
ProcessSerialNumber processSerialNumber; |
||||||
|
GetCurrentProcess(&processSerialNumber); |
||||||
|
GetProcessPID(&processSerialNumber, &keepassxPID); |
||||||
|
} |
||||||
|
return keepassxPID; |
||||||
|
} |
||||||
|
|
||||||
|
Boolean HelperMacX::getTargetWindowInfo(pid_t *pidPtr, int *windowNumberPtr, |
||||||
|
char* windowName, int maxWindowNameSize){ |
||||||
|
char windowNameBuffer[256]; |
||||||
|
if (NULL == windowName) { |
||||||
|
windowName = windowNameBuffer; |
||||||
|
maxWindowNameSize = sizeof(windowNameBuffer); |
||||||
|
} |
||||||
|
// get info for on screen windows (excluding desktop elements) in top to bottom order
|
||||||
|
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 (getKeepassxPID() == 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, maxWindowNameSize, kCFStringEncodingUTF8) || |
||||||
|
(0 == windowName[0])) |
||||||
|
continue; |
||||||
|
if (NULL != pidPtr) *pidPtr = pid; |
||||||
|
if (NULL != windowNumberPtr) { |
||||||
|
CFNumberRef windowNumberRef = (CFNumberRef)CFDictionaryGetValue(window, kCGWindowNumber); |
||||||
|
CFNumberGetValue(windowNumberRef, kCGWindowIDCFNumberType, windowNumberPtr); |
||||||
|
} |
||||||
|
CFRelease(windowInfo); |
||||||
|
return true; |
||||||
|
} |
||||||
|
CFRelease(windowInfo); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
OSType HelperMacX::getProcessSignature(pid_t pid){ |
||||||
|
OSErr err; |
||||||
|
ProcessSerialNumber processSerialNumber; |
||||||
|
ProcessInfoRec processInfoRec; |
||||||
|
processInfoRec.processInfoLength = sizeof(processInfoRec); |
||||||
|
processInfoRec.processAppSpec = NULL; |
||||||
|
processInfoRec.processName = NULL; |
||||||
|
err = GetProcessForPID(pid, &processSerialNumber); |
||||||
|
if (noErr != err) { |
||||||
|
qWarning("HelperMacX::getProcessSignature: GetProcessForPID error for pid %d: %d", pid, err); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
err = GetProcessInformation(&processSerialNumber, &processInfoRec); |
||||||
|
if (noErr != err) { |
||||||
|
qWarning("HelperMacX::getProcessSignature: GetProcessInformation error for pid %d: %d\n", pid, err); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
return processInfoRec.processSignature; |
||||||
|
} |
||||||
|
|
||||||
|
static uint orderedModifiers[] = { |
||||||
|
0, |
||||||
|
( shiftKey ) >> 8, |
||||||
|
(controlKey ) >> 8, |
||||||
|
( optionKey ) >> 8, |
||||||
|
( cmdKey ) >> 8, |
||||||
|
( shiftKey | controlKey ) >> 8, |
||||||
|
( shiftKey | optionKey ) >> 8, |
||||||
|
( shiftKey | cmdKey ) >> 8, |
||||||
|
(controlKey | optionKey ) >> 8, |
||||||
|
(controlKey | cmdKey ) >> 8, |
||||||
|
( optionKey | cmdKey ) >> 8, |
||||||
|
( shiftKey | controlKey | optionKey ) >> 8, |
||||||
|
( shiftKey | controlKey | cmdKey ) >> 8, |
||||||
|
( shiftKey | optionKey | cmdKey ) >> 8, |
||||||
|
(controlKey | optionKey | cmdKey ) >> 8, |
||||||
|
( shiftKey | controlKey | optionKey | cmdKey ) >> 8 |
||||||
|
}; |
||||||
|
|
||||||
|
static std::map<uint,KeycodeWithMods> unicodeToKeycodeWithModsMap; |
||||||
|
|
||||||
|
void HelperMacX::initUnicodeToKeycodeWithModsMap(){ |
||||||
|
unicodeToKeycodeWithModsMap.clear(); |
||||||
|
TISInputSourceRef inputSourceRef = TISCopyCurrentKeyboardInputSource(); |
||||||
|
if (NULL == inputSourceRef) { |
||||||
|
qWarning("HelperMacX::initUnicodeToKeycodeWithModsMap: inputSourceRef is NULL"); |
||||||
|
return; |
||||||
|
} |
||||||
|
CFDataRef unicodeKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef, |
||||||
|
kTISPropertyUnicodeKeyLayoutData); |
||||||
|
if (NULL == unicodeKeyLayoutDataRef) { |
||||||
|
qWarning("HelperMacX::initUnicodeToKeycodeWithModsMap: unicodeKeyLayoutDataRef is NULL"); |
||||||
|
return; |
||||||
|
} |
||||||
|
UCKeyboardLayout *unicodeKeyLayoutDataPtr = (UCKeyboardLayout*)CFDataGetBytePtr(unicodeKeyLayoutDataRef); |
||||||
|
|
||||||
|
UInt32 deadKeyState; |
||||||
|
UniChar unicodeString[8]; |
||||||
|
UniCharCount len; |
||||||
|
for (int m = 0; m < 16; m++) { |
||||||
|
uint mods = orderedModifiers[m]; |
||||||
|
for (uint keycode = 0; keycode < 0x80; keycode++) { |
||||||
|
deadKeyState = 0; |
||||||
|
len = 0; |
||||||
|
OSStatus status = UCKeyTranslate(unicodeKeyLayoutDataPtr, keycode, kUCKeyActionDown, |
||||||
|
mods, LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask, |
||||||
|
&deadKeyState, sizeof(unicodeString), &len, unicodeString); |
||||||
|
if (noErr != status) { |
||||||
|
qWarning("HelperMacX::initUnicodeToKeycodeWithModsMap: UCKeyTranslate error: %d keycode 0x%02X modifiers 0x%02X", |
||||||
|
(int)status, keycode, mods); |
||||||
|
continue; |
||||||
|
} |
||||||
|
// store if only one char and not already in store
|
||||||
|
if ((1 != len) || (0 < unicodeToKeycodeWithModsMap.count(unicodeString[0]))) continue; |
||||||
|
unicodeToKeycodeWithModsMap[unicodeString[0]] = (KeycodeWithMods){ keycode, mods }; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
KeySym HelperMacX::keycodeToKeysym(uint keycode){ |
||||||
|
TISInputSourceRef inputSourceRef = TISCopyCurrentKeyboardInputSource(); |
||||||
|
if (NULL == inputSourceRef) { |
||||||
|
qWarning("HelperMacX::keycodeToKeysym: inputSourceRef is NULL"); |
||||||
|
return NoSymbol; |
||||||
|
} |
||||||
|
CFDataRef unicodeKeyLayoutDataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef, |
||||||
|
kTISPropertyUnicodeKeyLayoutData); |
||||||
|
if (NULL == unicodeKeyLayoutDataRef) { |
||||||
|
CFRelease(inputSourceRef); |
||||||
|
qWarning("HelperMacX::keycodeToKeysym: unicodeKeyLayoutDataRef is NULL"); |
||||||
|
return NoSymbol; |
||||||
|
} |
||||||
|
UCKeyboardLayout *unicodeKeyLayoutDataPtr = (UCKeyboardLayout*)CFDataGetBytePtr(unicodeKeyLayoutDataRef); |
||||||
|
UInt32 deadKeyState = 0; |
||||||
|
UniChar unicodeString[8]; |
||||||
|
UniCharCount len = 0; |
||||||
|
OSStatus status = UCKeyTranslate(unicodeKeyLayoutDataPtr, keycode, kUCKeyActionDown, |
||||||
|
0, LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask, |
||||||
|
&deadKeyState, sizeof(unicodeString), &len, unicodeString); |
||||||
|
CFRelease(inputSourceRef); |
||||||
|
if (noErr != status) { |
||||||
|
qWarning("HelperMacX::keycodeToKeysym: UCKeyTranslate error: %d", (int)status); |
||||||
|
return NoSymbol; |
||||||
|
} |
||||||
|
return 1 != len ? NoSymbol : unicodeString[0]; |
||||||
|
} |
||||||
|
|
||||||
|
uint HelperMacX::keysymToKeycode(KeySym keysym){ |
||||||
|
return keysymToKeycodeWithMods(keysym).keycode; |
||||||
|
} |
||||||
|
|
||||||
|
static const KeycodeWithMods NoKeycodeWithMods = (KeycodeWithMods){ NoKeycode, 0 }; |
||||||
|
|
||||||
|
KeycodeWithMods HelperMacX::keysymToKeycodeWithMods(KeySym keysym){ |
||||||
|
return 0 == unicodeToKeycodeWithModsMap.count(keysym) |
||||||
|
? NoKeycodeWithMods : unicodeToKeycodeWithModsMap[keysym]; |
||||||
|
} |
||||||
|
|
||||||
|
void HelperMacX::processToFront(pid_t pid){ |
||||||
|
OSStatus status; |
||||||
|
ProcessSerialNumber processSerialNumber; |
||||||
|
status = GetProcessForPID(pid, &processSerialNumber); |
||||||
|
if (noErr != status) { |
||||||
|
qWarning("HelperMacX::processToFront: GetProcessForPID error for pid %d: %d", pid, (int)status); |
||||||
|
return; |
||||||
|
} |
||||||
|
status = SetFrontProcessWithOptions(&processSerialNumber, kSetFrontProcessFrontWindowOnly); |
||||||
|
if (noErr != status) { |
||||||
|
qWarning("HelperMacX::processToFront: SetFrontProcessWithOptions for pid %d: %d", pid, (int)status); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
/***************************************************************************
|
||||||
|
* 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. * |
||||||
|
***************************************************************************/ |
||||||
|
|
||||||
|
#ifndef HELPERMACX_H |
||||||
|
#define HELPERMACX_H |
||||||
|
|
||||||
|
#include "lib/AutoTypeMacX.h" |
||||||
|
|
||||||
|
class HelperMacX{ |
||||||
|
public: |
||||||
|
#ifdef GLOBAL_AUTOTYPE |
||||||
|
static uint getShortcutModifierMask(const Shortcut& s); |
||||||
|
static Boolean isFrontProcess(pid_t pid); |
||||||
|
#endif |
||||||
|
static pid_t getKeepassxPID(); |
||||||
|
static Boolean getTargetWindowInfo(pid_t *pidPtr, int *windowNumberPtr, char* windowName, int maxWindowNameSize); |
||||||
|
static OSType getProcessSignature(pid_t pid); |
||||||
|
static void initUnicodeToKeycodeWithModsMap(); |
||||||
|
static KeySym keycodeToKeysym(uint keycode); |
||||||
|
static uint keysymToKeycode(KeySym keysym); |
||||||
|
static KeycodeWithMods keysymToKeycodeWithMods(KeySym keysym); |
||||||
|
static void processToFront(pid_t pid); |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // HELPERMACX_H
|
Reference in new issue