mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Added global autotype support for OSX.
This commit is contained in:
parent
6ef5f34070
commit
b87097a7ab
@ -9,6 +9,10 @@ if(Q_WS_X11)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(Q_WS_MAC)
|
||||||
|
add_subdirectory(mac)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WITH_TESTS)
|
if(WITH_TESTS)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
endif()
|
endif()
|
||||||
|
551
src/autotype/mac/AutoTypeMac.cpp
Normal file
551
src/autotype/mac/AutoTypeMac.cpp
Normal file
@ -0,0 +1,551 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Felix Geyer <debfx@fobos.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, either version 2 or (at your option)
|
||||||
|
* version 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "AutoTypeMac.h"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
static pid_t keepassxPID2;
|
||||||
|
|
||||||
|
#define UNICODE_BUFFER_SIZE 1
|
||||||
|
static UniChar unicodeBuffer[UNICODE_BUFFER_SIZE];
|
||||||
|
static UniCharCount unicodePtr = 0;
|
||||||
|
// reusable events
|
||||||
|
static CGEventRef unicodeEvent = CGEventCreateKeyboardEvent(NULL, 0, true);
|
||||||
|
CGEventRef AutoTypePlatformMac::keyEvent =
|
||||||
|
CGEventCreateKeyboardEvent(NULL, 0, true);
|
||||||
|
|
||||||
|
bool AutoTypePlatformMac::inHotKeyEvent = false;
|
||||||
|
|
||||||
|
static const KeycodeWithMods NoKeycodeWithMods =
|
||||||
|
(KeycodeWithMods){ NoKeycode, 0 };
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
AutoTypePlatformMac::AutoTypePlatformMac() : first(true), keepassxPID(0)
|
||||||
|
{
|
||||||
|
globalKey = 0;
|
||||||
|
globalMod = 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);
|
||||||
|
AutoTypePlatformMac::initUnicodeToKeycodeWithModsMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QStringList AutoTypePlatformMac::windowTitles()
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
return getTargetWindowInfo(&pid, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WId AutoTypePlatformMac::activeWindow()
|
||||||
|
{
|
||||||
|
WId mid;
|
||||||
|
pid_t pid;
|
||||||
|
getTargetWindowInfo(&pid, &mid);
|
||||||
|
AutoTypePlatformMac::processToFront(pid);
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString AutoTypePlatformMac::activeWindowTitle()
|
||||||
|
{
|
||||||
|
QStringList sl = getTargetWindowInfo(NULL, NULL);
|
||||||
|
return sl[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool AutoTypePlatformMac::registerGlobalShortcut(Qt::Key key,
|
||||||
|
Qt::KeyboardModifiers modifiers)
|
||||||
|
{
|
||||||
|
if (key == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//KeycodeWithMods kc = keyToKeycodeWithMods(key);
|
||||||
|
KeycodeWithMods kc = AutoTypePlatformMac::keysymToKeycodeWithMods2(static_cast<KeySym>(key));
|
||||||
|
int code = kc.keycode;
|
||||||
|
uint mod = qtToNativeModifiers(modifiers);
|
||||||
|
|
||||||
|
if (code==globalKey && mod==globalMod)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// need to unregister old before registering new
|
||||||
|
unregisterGlobalShortcut(key, modifiers);
|
||||||
|
OSStatus status = RegisterEventHotKey(code, mod, hotKeyID,
|
||||||
|
GetApplicationEventTarget(), 0, &hotKeyRef);
|
||||||
|
|
||||||
|
if (noErr == status) {
|
||||||
|
globalKey = code;
|
||||||
|
globalMod = mod;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
qWarning("Error registering global shortcut: %d", status);
|
||||||
|
RegisterEventHotKey(globalKey, globalMod, hotKeyID,
|
||||||
|
GetApplicationEventTarget(), 0, &hotKeyRef);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutoTypePlatformMac::unregisterGlobalShortcut(Qt::Key,
|
||||||
|
Qt::KeyboardModifiers)
|
||||||
|
{
|
||||||
|
globalKey = 0;
|
||||||
|
globalMod = 0;
|
||||||
|
UnregisterEventHotKey(hotKeyRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int AutoTypePlatformMac::platformEventFilter(void* event)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int AutoTypePlatformMac::initialTimeout()
|
||||||
|
{
|
||||||
|
first = true;
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AutoTypeExecutor* AutoTypePlatformMac::createExecutor()
|
||||||
|
{
|
||||||
|
return new AutoTypeExecturorMac(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutoTypePlatformMac::sendUnicode(KeySym keysym)
|
||||||
|
{
|
||||||
|
if (onlySendKeycodes) {
|
||||||
|
KeycodeWithMods keycodeWithMods =
|
||||||
|
AutoTypePlatformMac::keysymToKeycodeWithMods2(keysym);
|
||||||
|
if (NoKeycode == keycodeWithMods.keycode) return;
|
||||||
|
sendKeycode(keycodeWithMods);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unicodeBuffer[unicodePtr++] = keysym;
|
||||||
|
if (UNICODE_BUFFER_SIZE == unicodePtr) flushUnicode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutoTypePlatformMac::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, keycode);
|
||||||
|
CGEventSetFlags(AutoTypePlatformMac::keyEvent, flags);
|
||||||
|
keyDownUp(AutoTypePlatformMac::keyEvent);
|
||||||
|
sleepKeyStrokeDelay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KeycodeWithMods AutoTypePlatformMac::keyToKeycodeWithMods(Qt::Key key)
|
||||||
|
{
|
||||||
|
KeycodeWithMods kc;
|
||||||
|
kc.mods = 0;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case Qt::Key_Tab:
|
||||||
|
kc.keycode = kVK_Tab;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Enter:
|
||||||
|
kc.keycode = kVK_Return;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Up:
|
||||||
|
kc.keycode = kVK_UpArrow;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Down:
|
||||||
|
kc.keycode = kVK_DownArrow;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Left:
|
||||||
|
kc.keycode = kVK_LeftArrow;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Right:
|
||||||
|
kc.keycode = kVK_RightArrow;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Insert:
|
||||||
|
kc.keycode = kVK_Help;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Delete:
|
||||||
|
kc.keycode = kVK_ForwardDelete;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Home:
|
||||||
|
kc.keycode = kVK_Home;
|
||||||
|
break;
|
||||||
|
case Qt::Key_End:
|
||||||
|
kc.keycode = kVK_End;
|
||||||
|
break;
|
||||||
|
case Qt::Key_PageUp:
|
||||||
|
kc.keycode = kVK_PageUp;
|
||||||
|
break;
|
||||||
|
case Qt::Key_PageDown:
|
||||||
|
kc.keycode = kVK_PageDown;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Backspace:
|
||||||
|
kc.keycode = kVK_Delete;
|
||||||
|
break;
|
||||||
|
//case Qt::Key_Pause:
|
||||||
|
// return XK_Break;
|
||||||
|
case Qt::Key_CapsLock:
|
||||||
|
kc.keycode = kVK_CapsLock;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Escape:
|
||||||
|
kc.keycode = kVK_Escape;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Help:
|
||||||
|
kc.keycode = kVK_Help;
|
||||||
|
break;
|
||||||
|
case Qt::Key_NumLock:
|
||||||
|
kc.keycode = kVK_ANSI_KeypadClear;
|
||||||
|
break;
|
||||||
|
case Qt::Key_Print:
|
||||||
|
kc.keycode = kVK_F13;
|
||||||
|
break;
|
||||||
|
//case Qt::Key_ScrollLock:
|
||||||
|
// return XK_Scroll_Lock;
|
||||||
|
default:
|
||||||
|
if (key >= Qt::Key_F1 && key <= Qt::Key_F16)
|
||||||
|
kc.keycode = kVK_F1 + key - Qt::Key_F1;
|
||||||
|
else
|
||||||
|
kc.keycode = NoSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private
|
||||||
|
|
||||||
|
QStringList AutoTypePlatformMac::getTargetWindowInfo(pid_t *pidPtr,
|
||||||
|
WId *windowNumberPtr)
|
||||||
|
{
|
||||||
|
QStringList titles;
|
||||||
|
|
||||||
|
const int maxWindowNameSize = 512;
|
||||||
|
char windowName[maxWindowNameSize];
|
||||||
|
|
||||||
|
onlySendKeycodes = false;
|
||||||
|
|
||||||
|
CFArrayRef windowInfo = CGWindowListCopyWindowInfo(
|
||||||
|
kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
|
||||||
|
0);
|
||||||
|
CFIndex windowCount = CFArrayGetCount(windowInfo);
|
||||||
|
|
||||||
|
for (CFIndex i = 0; i < windowCount; i++) {
|
||||||
|
CFDictionaryRef window = static_cast<CFDictionaryRef>
|
||||||
|
(CFArrayGetValueAtIndex(windowInfo, i));
|
||||||
|
|
||||||
|
// only want windows in layer 0
|
||||||
|
CFNumberRef windowLayerRef = static_cast<CFNumberRef>
|
||||||
|
(CFDictionaryGetValue(window, kCGWindowLayer));
|
||||||
|
|
||||||
|
int windowLayer = -1;
|
||||||
|
CFNumberGetValue(windowLayerRef, kCFNumberIntType, &windowLayer);
|
||||||
|
if (0 != windowLayer) continue;
|
||||||
|
|
||||||
|
// get the pid owning this window
|
||||||
|
CFNumberRef pidRef = static_cast<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 = static_cast<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) {
|
||||||
|
CGWindowID wid;
|
||||||
|
CFNumberRef windowNumberRef = static_cast<CFNumberRef>
|
||||||
|
(CFDictionaryGetValue(window, kCGWindowNumber));
|
||||||
|
CFNumberGetValue(windowNumberRef, kCGWindowIDCFNumberType, &wid);
|
||||||
|
*windowNumberPtr = wid;
|
||||||
|
return titles;
|
||||||
|
}
|
||||||
|
titles.append(QString(windowName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return titles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint AutoTypePlatformMac::qtToNativeModifiers(Qt::KeyboardModifiers modifiers)
|
||||||
|
{
|
||||||
|
uint nativeModifiers = 0;
|
||||||
|
|
||||||
|
if (modifiers & Qt::ShiftModifier) {
|
||||||
|
nativeModifiers |= shiftKey;
|
||||||
|
}
|
||||||
|
if (modifiers & Qt::ControlModifier) {
|
||||||
|
nativeModifiers |= controlKey;
|
||||||
|
}
|
||||||
|
if (modifiers & Qt::AltModifier) {
|
||||||
|
nativeModifiers |= optionKey;
|
||||||
|
}
|
||||||
|
if (modifiers & Qt::MetaModifier) {
|
||||||
|
nativeModifiers |= cmdKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nativeModifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutoTypePlatformMac::flushUnicode()
|
||||||
|
{
|
||||||
|
if (0 == unicodePtr) return;
|
||||||
|
CGEventKeyboardSetUnicodeString(unicodeEvent, unicodePtr, unicodeBuffer);
|
||||||
|
keyDownUp(unicodeEvent);
|
||||||
|
unicodePtr = 0;
|
||||||
|
sleepKeyStrokeDelay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutoTypePlatformMac::keyDownUp(CGEventRef theEvent)
|
||||||
|
{
|
||||||
|
// posting Key Down/Up events also annoyingly sets mouse location so mus
|
||||||
|
// 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 AutoTypePlatformMac::sleepTime(int msec)
|
||||||
|
{
|
||||||
|
if (msec == 0) return;
|
||||||
|
|
||||||
|
timespec timeOut, remains;
|
||||||
|
timeOut.tv_sec = msec/1000;
|
||||||
|
timeOut.tv_nsec = (msec%1000)*1000000;
|
||||||
|
nanosleep(&timeOut, &remains);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OSStatus AutoTypePlatformMac::hotKeyHandler(EventHandlerCallRef, EventRef,
|
||||||
|
void *userData)
|
||||||
|
{
|
||||||
|
// ignore nextHandler - should not be called
|
||||||
|
if ((inHotKeyEvent) ||
|
||||||
|
AutoTypePlatformMac::isFrontProcess(AutoTypePlatformMac::getKeepassxPID2())) return noErr;
|
||||||
|
|
||||||
|
AutoTypePlatformMac::inHotKeyEvent = true;
|
||||||
|
Q_EMIT static_cast<AutoTypePlatformMac*>(userData)->globalShortcutTriggered();
|
||||||
|
AutoTypePlatformMac::inHotKeyEvent = false;
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pid_t AutoTypePlatformMac::getKeepassxPID() {
|
||||||
|
|
||||||
|
if (0 == keepassxPID) {
|
||||||
|
ProcessSerialNumber processSerialNumber;
|
||||||
|
GetCurrentProcess(&processSerialNumber);
|
||||||
|
GetProcessPID(&processSerialNumber, &keepassxPID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return keepassxPID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Boolean AutoTypePlatformMac::isFrontProcess(pid_t pid)
|
||||||
|
{
|
||||||
|
Boolean result;
|
||||||
|
ProcessSerialNumber pidPSN;
|
||||||
|
ProcessSerialNumber frontPSN;
|
||||||
|
OSStatus status = GetProcessForPID(pid, &pidPSN);
|
||||||
|
if (noErr != status) {
|
||||||
|
qWarning("AutoTypePlatformMac::isFrontProcess: GetProcessForPID "
|
||||||
|
"error for pid %d: %d", pid, status);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GetFrontProcess(&frontPSN);
|
||||||
|
SameProcess(&pidPSN, &frontPSN, &result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutoTypePlatformMac::initUnicodeToKeycodeWithModsMap()
|
||||||
|
{
|
||||||
|
unicodeToKeycodeWithModsMap.clear();
|
||||||
|
TISInputSourceRef inputSourceRef = TISCopyCurrentKeyboardInputSource();
|
||||||
|
|
||||||
|
if (NULL == inputSourceRef) {
|
||||||
|
qWarning("AutoTypePlatformMac::initUnicodeToKeycodeWithModsMap: "
|
||||||
|
"inputSourceRef is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFDataRef unicodeKeyLayoutDataRef = static_cast<CFDataRef>
|
||||||
|
(TISGetInputSourceProperty(inputSourceRef,
|
||||||
|
kTISPropertyUnicodeKeyLayoutData));
|
||||||
|
|
||||||
|
if (NULL == unicodeKeyLayoutDataRef) {
|
||||||
|
qWarning("AutoTypePlatformMac::initUnicodeToKeycodeWithModsMap: "
|
||||||
|
"unicodeKeyLayoutDataRef is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const UCKeyboardLayout *unicodeKeyLayoutDataPtr =
|
||||||
|
reinterpret_cast<const 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("AutoTypePlatformMac::initUnicodeToKeycodeWithModsMap: "
|
||||||
|
"UCKeyTranslate error: %d keycode 0x%02X modifiers 0x%02X",
|
||||||
|
status, keycode, mods);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store if only one char and not already in store
|
||||||
|
if ((1 != len) ||
|
||||||
|
(0 < unicodeToKeycodeWithModsMap.count(unicodeString[0])))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
KeycodeWithMods kc;
|
||||||
|
kc.keycode = keycode;
|
||||||
|
kc.mods = mods;
|
||||||
|
unicodeToKeycodeWithModsMap[unicodeString[0]] = kc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutoTypePlatformMac::processToFront(pid_t pid)
|
||||||
|
{
|
||||||
|
OSStatus status;
|
||||||
|
ProcessSerialNumber processSerialNumber;
|
||||||
|
status = GetProcessForPID(pid, &processSerialNumber);
|
||||||
|
|
||||||
|
if (noErr != status) {
|
||||||
|
qWarning("AutoTypePlatformMac::processToFront: GetProcessForPID "
|
||||||
|
"error for pid %d: %d", pid, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = SetFrontProcessWithOptions(&processSerialNumber,
|
||||||
|
kSetFrontProcessFrontWindowOnly);
|
||||||
|
|
||||||
|
if (noErr != status) {
|
||||||
|
qWarning("AutoTypePlatformMac::processToFront: "
|
||||||
|
"SetFrontProcessWithOptions for pid %d: %d", pid, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KeycodeWithMods AutoTypePlatformMac::keysymToKeycodeWithMods2(KeySym keysym)
|
||||||
|
{
|
||||||
|
return 0 == unicodeToKeycodeWithModsMap.count(keysym)
|
||||||
|
? NoKeycodeWithMods : unicodeToKeycodeWithModsMap[keysym];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pid_t AutoTypePlatformMac::getKeepassxPID2()
|
||||||
|
{
|
||||||
|
if (0 == keepassxPID2) {
|
||||||
|
ProcessSerialNumber processSerialNumber;
|
||||||
|
GetCurrentProcess(&processSerialNumber);
|
||||||
|
GetProcessPID(&processSerialNumber, &keepassxPID2);
|
||||||
|
}
|
||||||
|
return keepassxPID2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AutoTypeExecturorMac::AutoTypeExecturorMac(AutoTypePlatformMac* platform)
|
||||||
|
: m_platform(platform)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutoTypeExecturorMac::execChar(AutoTypeChar* action)
|
||||||
|
{
|
||||||
|
m_platform->sendUnicode(action->character.unicode());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutoTypeExecturorMac::execKey(AutoTypeKey* action)
|
||||||
|
{
|
||||||
|
m_platform->sendKeycode(m_platform->keyToKeycodeWithMods(action->key));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Q_EXPORT_PLUGIN2(keepassx-autotype-mac, AutoTypePlatformMac)
|
105
src/autotype/mac/AutoTypeMac.h
Normal file
105
src/autotype/mac/AutoTypeMac.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Felix Geyer <debfx@fobos.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, either version 2 or (at your option)
|
||||||
|
* version 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEEPASSX_AUTOTYPEMAC_H
|
||||||
|
#define KEEPASSX_AUTOTYPEMAC_H
|
||||||
|
|
||||||
|
#include <QtCore/QtPlugin>
|
||||||
|
#include <Carbon/Carbon.h>
|
||||||
|
|
||||||
|
#include "autotype/AutoTypePlatformPlugin.h"
|
||||||
|
#include "autotype/AutoTypeAction.h"
|
||||||
|
#include "core/Global.h"
|
||||||
|
|
||||||
|
typedef quint32 KeySym;
|
||||||
|
#define NoSymbol static_cast<KeySym>(0)
|
||||||
|
#define NoKeycode static_cast<uint16>(-1)
|
||||||
|
|
||||||
|
struct KeycodeWithMods {
|
||||||
|
uint16 keycode;
|
||||||
|
uint16 mods;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AutoTypePlatformMac : public QObject, public AutoTypePlatformInterface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(AutoTypePlatformInterface)
|
||||||
|
|
||||||
|
public:
|
||||||
|
AutoTypePlatformMac();
|
||||||
|
|
||||||
|
QStringList windowTitles();
|
||||||
|
WId activeWindow();
|
||||||
|
QString activeWindowTitle();
|
||||||
|
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||||
|
void unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||||
|
int platformEventFilter(void* event);
|
||||||
|
int initialTimeout();
|
||||||
|
AutoTypeExecutor* createExecutor();
|
||||||
|
|
||||||
|
void sendUnicode(KeySym keysym);
|
||||||
|
void sendKeycode(KeycodeWithMods keycodeWithMods);
|
||||||
|
KeycodeWithMods keyToKeycodeWithMods(Qt::Key key);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void globalShortcutTriggered();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList getTargetWindowInfo(pid_t *pidPtr, WId *windowNumberPtr);
|
||||||
|
uint qtToNativeModifiers(Qt::KeyboardModifiers modifiers);
|
||||||
|
void flushUnicode();
|
||||||
|
void keyDownUp(CGEventRef theEvent);
|
||||||
|
void sleepTime(int msec);
|
||||||
|
inline void sleepKeyStrokeDelay(){ sleepTime(5); };
|
||||||
|
static OSStatus hotKeyHandler(EventHandlerCallRef,
|
||||||
|
EventRef, void *userData);
|
||||||
|
pid_t getKeepassxPID();
|
||||||
|
|
||||||
|
bool first;
|
||||||
|
bool onlySendKeycodes;
|
||||||
|
bool inGlobalAutoType;
|
||||||
|
int globalKey;
|
||||||
|
uint globalMod;
|
||||||
|
pid_t keepassxPID;
|
||||||
|
EventHotKeyRef hotKeyRef;
|
||||||
|
EventHotKeyID hotKeyID;
|
||||||
|
|
||||||
|
static bool inHotKeyEvent;
|
||||||
|
static CGEventRef keyEvent;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void initUnicodeToKeycodeWithModsMap();
|
||||||
|
static void processToFront(pid_t pid);
|
||||||
|
static KeycodeWithMods keysymToKeycodeWithMods2(KeySym keysym);
|
||||||
|
static Boolean isFrontProcess(pid_t pid);
|
||||||
|
static pid_t getKeepassxPID2();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AutoTypeExecturorMac : public AutoTypeExecutor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AutoTypeExecturorMac(AutoTypePlatformMac* platform);
|
||||||
|
|
||||||
|
void execChar(AutoTypeChar* action);
|
||||||
|
void execKey(AutoTypeKey* action);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AutoTypePlatformMac* const m_platform;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KEEPASSX_AUTOTYPEMAC_H
|
18
src/autotype/mac/CMakeLists.txt
Normal file
18
src/autotype/mac/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
set(autotype_mac_SOURCES
|
||||||
|
AutoTypeMac.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(autotype_mac_MOC
|
||||||
|
AutoTypeMac.h
|
||||||
|
)
|
||||||
|
|
||||||
|
qt4_wrap_cpp(autotype_mac_SOURCES ${autotype_mac_MOC})
|
||||||
|
|
||||||
|
add_library(keepassx-autotype-mac MODULE ${autotype_mac_SOURCES})
|
||||||
|
if(APPLE)
|
||||||
|
set_target_properties(keepassx-autotype-mac PROPERTIES LINK_FLAGS "-framework Foundation -framework AppKit -framework Carbon")
|
||||||
|
endif()
|
||||||
|
target_link_libraries(keepassx-autotype-mac testautotype ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
|
||||||
|
install(TARGETS keepassx-autotype-mac
|
||||||
|
BUNDLE DESTINATION . COMPONENT Runtime
|
||||||
|
LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime)
|
Loading…
Reference in New Issue
Block a user