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>
|
||||
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>
|
||||
|
||||
<!--
|
||||
|
|
Loading…
Reference in New Issue