Kennwortmanager KeePassX Weiterentwicklung der Version 1
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 
 
keepassx1/src/lib/AutoTypeGlobalMacX.cpp

266 lines
8.5 KiB

/***************************************************************************
* 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();
}