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
This commit is contained in:
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
|
|
@ -234,7 +234,8 @@
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Also note that the use of <tt>{CLEARFIELD}</tt> may require the user to define
|
Also note that the use of <tt>{CLEARFIELD}</tt> 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.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
Loading…
Reference in New Issue