diff --git a/src/autotype/AutoTypeAction.cpp b/src/autotype/AutoTypeAction.cpp index 090ca8234..64dae7962 100644 --- a/src/autotype/AutoTypeAction.cpp +++ b/src/autotype/AutoTypeAction.cpp @@ -90,6 +90,4 @@ void AutoTypeExecutor::execDelay(AutoTypeDelay* action) void AutoTypeExecutor::execClearField(AutoTypeClearField* action) { Q_UNUSED(action); - - // TODO: implement } diff --git a/src/autotype/mac/AutoTypeMac.cpp b/src/autotype/mac/AutoTypeMac.cpp index 08df6310e..89435c263 100644 --- a/src/autotype/mac/AutoTypeMac.cpp +++ b/src/autotype/mac/AutoTypeMac.cpp @@ -120,7 +120,7 @@ bool AutoTypePlatformMac::registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifi qWarning("Invalid key code"); return false; } - uint16 nativeModifiers = qtToNativeModifiers(modifiers); + CGEventFlags nativeModifiers = qtToNativeModifiers(modifiers, false); if (::RegisterEventHotKey(nativeKeyCode, nativeModifiers, m_hotkeyId, GetApplicationEventTarget(), 0, &m_hotkeyRef) != noErr) { qWarning("Register hotkey failed"); return false; @@ -201,7 +201,7 @@ void AutoTypePlatformMac::sendChar(const QChar& ch, bool isKeyDown) // Send key code to active window // see: Quartz Event Services // -void AutoTypePlatformMac::sendKey(Qt::Key key, bool isKeyDown) +void AutoTypePlatformMac::sendKey(Qt::Key key, bool isKeyDown, Qt::KeyboardModifiers modifiers = 0) { uint16 keyCode = qtToNativeKeyCode(key); if (keyCode == INVALID_KEYCODE) { @@ -209,7 +209,9 @@ void AutoTypePlatformMac::sendKey(Qt::Key key, bool isKeyDown) } CGEventRef keyEvent = ::CGEventCreateKeyboardEvent(nullptr, keyCode, isKeyDown); + CGEventFlags nativeModifiers = qtToNativeModifiers(modifiers, true); if (keyEvent != nullptr) { + ::CGEventSetFlags(keyEvent, nativeModifiers); ::CGEventPost(kCGSessionEventTap, keyEvent); ::CFRelease(keyEvent); } @@ -317,6 +319,10 @@ uint16 AutoTypePlatformMac::qtToNativeKeyCode(Qt::Key key) case Qt::Key_Period: return kVK_ANSI_Period; + case Qt::Key_Shift: + return kVK_Shift; + case Qt::Key_Control: + return kVK_Command; case Qt::Key_Backspace: return kVK_Delete; case Qt::Key_Tab: @@ -395,21 +401,34 @@ uint16 AutoTypePlatformMac::qtToNativeKeyCode(Qt::Key key) // Translate qt key modifiers to mac os modifiers // see: https://doc.qt.io/qt-5/osx-issues.html#special-keys // -uint16 AutoTypePlatformMac::qtToNativeModifiers(Qt::KeyboardModifiers modifiers) +CGEventFlags AutoTypePlatformMac::qtToNativeModifiers(Qt::KeyboardModifiers modifiers, bool native) { - uint16 nativeModifiers = 0; + CGEventFlags nativeModifiers = 0; + + CGEventFlags shiftMod = shiftKey; + CGEventFlags cmdMod = cmdKey; + CGEventFlags optionMod = optionKey; + CGEventFlags controlMod = controlKey; + + if (native) { + shiftMod = kCGEventFlagMaskShift; + cmdMod = kCGEventFlagMaskCommand; + optionMod = kCGEventFlagMaskAlternate; + controlMod = kCGEventFlagMaskControl; + } + if (modifiers & Qt::ShiftModifier) { - nativeModifiers |= shiftKey; + nativeModifiers |= shiftMod; } if (modifiers & Qt::ControlModifier) { - nativeModifiers |= cmdKey; + nativeModifiers |= cmdMod; } if (modifiers & Qt::AltModifier) { - nativeModifiers |= optionKey; + nativeModifiers |= optionMod; } if (modifiers & Qt::MetaModifier) { - nativeModifiers |= controlKey; + nativeModifiers |= controlMod; } return nativeModifiers; @@ -488,3 +507,25 @@ void AutoTypeExecutorMac::execKey(AutoTypeKey* action) m_platform->sendKey(action->key, false); usleep(25 * 1000); } + +void AutoTypeExecutorMac::execClearField(AutoTypeClearField* action = nullptr) +{ + Q_UNUSED(action); + + m_platform->sendKey(Qt::Key_Control, true, Qt::ControlModifier); + m_platform->sendKey(Qt::Key_Up, true, Qt::ControlModifier); + m_platform->sendKey(Qt::Key_Up, false, Qt::ControlModifier); + m_platform->sendKey(Qt::Key_Control, false); + usleep(25 * 1000); + m_platform->sendKey(Qt::Key_Shift, true, Qt::ShiftModifier); + m_platform->sendKey(Qt::Key_Control, true, Qt::ShiftModifier | Qt::ControlModifier); + m_platform->sendKey(Qt::Key_Down, true, Qt::ShiftModifier | Qt::ControlModifier); + m_platform->sendKey(Qt::Key_Down, false, Qt::ShiftModifier | Qt::ControlModifier); + m_platform->sendKey(Qt::Key_Control, false, Qt::ShiftModifier); + m_platform->sendKey(Qt::Key_Shift, false); + usleep(25 * 1000); + m_platform->sendKey(Qt::Key_Backspace, true); + m_platform->sendKey(Qt::Key_Backspace, false); + + usleep(25 * 1000); +} diff --git a/src/autotype/mac/AutoTypeMac.h b/src/autotype/mac/AutoTypeMac.h index 5fbbf763b..82f8b0eb6 100644 --- a/src/autotype/mac/AutoTypeMac.h +++ b/src/autotype/mac/AutoTypeMac.h @@ -49,7 +49,7 @@ public: bool raiseOwnWindow() override; void sendChar(const QChar& ch, bool isKeyDown); - void sendKey(Qt::Key key, bool isKeyDown); + void sendKey(Qt::Key key, bool isKeyDown, Qt::KeyboardModifiers modifiers); signals: void globalShortcutTriggered(); @@ -60,7 +60,7 @@ private: EventHotKeyID m_hotkeyId; static uint16 qtToNativeKeyCode(Qt::Key key); - static uint16 qtToNativeModifiers(Qt::KeyboardModifiers modifiers); + static CGEventFlags qtToNativeModifiers(Qt::KeyboardModifiers modifiers, bool native); static int windowLayer(CFDictionaryRef window); static QString windowTitle(CFDictionaryRef window); static OSStatus hotkeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData); @@ -73,6 +73,7 @@ public: void execChar(AutoTypeChar* action) override; void execKey(AutoTypeKey* action) override; + void execClearField(AutoTypeClearField* action) override; private: AutoTypePlatformMac* const m_platform; diff --git a/src/autotype/windows/AutoTypeWindows.cpp b/src/autotype/windows/AutoTypeWindows.cpp index 0818a37bc..81baeefac 100644 --- a/src/autotype/windows/AutoTypeWindows.cpp +++ b/src/autotype/windows/AutoTypeWindows.cpp @@ -189,6 +189,10 @@ DWORD AutoTypePlatformWin::qtToNativeKeyCode(Qt::Key key) case Qt::Key_Enter: case Qt::Key_Return: return VK_RETURN; // 0x0D + case Qt::Key_Shift: + return VK_SHIFT; // 0x10 + case Qt::Key_Control: + return VK_CONTROL; // 0x11 case Qt::Key_Pause: return VK_PAUSE; // 0x13 case Qt::Key_CapsLock: @@ -527,3 +531,24 @@ void AutoTypeExecutorWin::execKey(AutoTypeKey* action) ::Sleep(25); } +void AutoTypeExecutorWin::execClearField(AutoTypeClearField* action = nullptr) +{ + Q_UNUSED(action); + + m_platform->sendKey(Qt::Key_Control, true); + m_platform->sendKey(Qt::Key_Home, true); + m_platform->sendKey(Qt::Key_Home, false); + m_platform->sendKey(Qt::Key_Control, false); + ::Sleep(25); + m_platform->sendKey(Qt::Key_Control, true); + m_platform->sendKey(Qt::Key_Shift, true); + m_platform->sendKey(Qt::Key_End, true); + m_platform->sendKey(Qt::Key_End, false); + m_platform->sendKey(Qt::Key_Shift, false); + m_platform->sendKey(Qt::Key_Control, false); + ::Sleep(25); + m_platform->sendKey(Qt::Key_Backspace, true); + m_platform->sendKey(Qt::Key_Backspace, false); + + ::Sleep(25); +} diff --git a/src/autotype/windows/AutoTypeWindows.h b/src/autotype/windows/AutoTypeWindows.h index f8b213cb0..6ffae4d1e 100644 --- a/src/autotype/windows/AutoTypeWindows.h +++ b/src/autotype/windows/AutoTypeWindows.h @@ -64,6 +64,7 @@ public: void execChar(AutoTypeChar* action) override; void execKey(AutoTypeKey* action) override; + void execClearField(AutoTypeClearField* action) override; private: AutoTypePlatformWin* const m_platform; diff --git a/src/autotype/xcb/AutoTypeXCB.cpp b/src/autotype/xcb/AutoTypeXCB.cpp index e6ac74bbf..9290639f2 100644 --- a/src/autotype/xcb/AutoTypeXCB.cpp +++ b/src/autotype/xcb/AutoTypeXCB.cpp @@ -473,6 +473,12 @@ KeySym AutoTypePlatformX11::keyToKeySym(Qt::Key key) return XK_Print; case Qt::Key_ScrollLock: return XK_Scroll_Lock; + case Qt::Key_Shift: + return XK_Shift_L; + case Qt::Key_Control: + return XK_Control_L; + case Qt::Key_Alt: + return XK_Alt_L; default: if (key >= Qt::Key_F1 && key <= Qt::Key_F16) { return XK_F1 + (key - Qt::Key_F1); @@ -723,6 +729,12 @@ bool AutoTypePlatformX11::keysymModifiers(KeySym keysym, int keycode, unsigned i * are set ON, many events will be sent. */ void AutoTypePlatformX11::SendKeyPressedEvent(KeySym keysym) +{ + SendKey(keysym,true); + SendKey(keysym,false); +} + +void AutoTypePlatformX11::SendKey(KeySym keysym, bool isKeyDown) { Window cur_focus; int revert_to; @@ -802,8 +814,11 @@ void AutoTypePlatformX11::SendKeyPressedEvent(KeySym keysym) /* press and release key */ event.keycode = keycode; - SendEvent(&event, KeyPress); - SendEvent(&event, KeyRelease); + if (isKeyDown) { + SendEvent(&event, KeyPress); + } else { + SendEvent(&event, KeyRelease); + } /* release the modifiers */ SendModifier(&event, press_mask, KeyRelease); @@ -840,6 +855,31 @@ void AutoTypeExecutorX11::execKey(AutoTypeKey* action) m_platform->SendKeyPressedEvent(m_platform->keyToKeySym(action->key)); } +void AutoTypeExecutorX11::execClearField(AutoTypeClearField* action = nullptr) +{ + Q_UNUSED(action); + + timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 25 * 1000 * 1000; + + m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Control), true); + m_platform->SendKeyPressedEvent(m_platform->keyToKeySym(Qt::Key_Home)); + m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Control), false); + nanosleep(&ts, nullptr); + + m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Control), true); + m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Shift), true); + m_platform->SendKeyPressedEvent(m_platform->keyToKeySym(Qt::Key_End)); + m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Shift), false); + m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Control), false); + nanosleep(&ts, nullptr); + + m_platform->SendKeyPressedEvent(m_platform->keyToKeySym(Qt::Key_Backspace)); + nanosleep(&ts, nullptr); +} + + int AutoTypePlatformX11::initialTimeout() { return 500; diff --git a/src/autotype/xcb/AutoTypeXCB.h b/src/autotype/xcb/AutoTypeXCB.h index dc251e3f9..186d0eb8b 100644 --- a/src/autotype/xcb/AutoTypeXCB.h +++ b/src/autotype/xcb/AutoTypeXCB.h @@ -58,6 +58,7 @@ public: KeySym keyToKeySym(Qt::Key key); void SendKeyPressedEvent(KeySym keysym); + void SendKey(KeySym keysym, bool isKeyDown); signals: void globalShortcutTriggered(); @@ -126,6 +127,7 @@ public: void execChar(AutoTypeChar* action) override; void execKey(AutoTypeKey* action) override; + void execClearField(AutoTypeClearField* action) override; private: AutoTypePlatformX11* const m_platform;