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