0

I use KVM switch (KVM-221 D-Link) for two PCs.
The hotkey to switch is double "CapsLock" press. If I push keyboard button mechanically it works perfect.
So I wrote simple programs to auto switch when mouse on edges of the screen.
Linux version work good. When mouse positioned, it press "CapsLock" twice and switch is work.
Sample:

#include <iostream>
#include <chrono>
#include <thread>
#include <X11/Xlib.h>
#include <X11/extensions/XTest.h>
#include <X11/keysym.h>

void PrintError(const char *msg, bool pause = false, bool shutdown = true);

void Sleep(int ms);

class KBManager {
private:
    Display *display;
    ulong rootWindow;

    //Mouse position fields
    Window windowReturned;
    int win_x, win_y;
    uint mask;

public:
    Screen *pScreen;
    int MouseX, MouseY;

public:
    KBManager();

    ~KBManager();

    void MoveMouse(int x, int y);

    void GetMousePosition();

    void PressCapsLockTwice();
};

int main() {
    KBManager manager;
    int halfHeight = manager.pScreen->height / 2;
    int height = manager.pScreen->height - 100;
    while (true) {
        manager.GetMousePosition();
        if (manager.MouseX == 0 && manager.MouseY > halfHeight && manager.MouseY < height) {
            manager.PressCapsLockTwice();
            manager.MoveMouse(500, 500);
            Sleep(10 * 1000);
        }
        Sleep(500);
    }
}

void PrintError(const char *msg, bool pause, bool shutdown) {
    fprintf(stdout, "%s\n", msg);
    if (pause)
        std::cin.get();
    if (shutdown)
        exit(EXIT_FAILURE);
}

void Sleep(int ms) {
    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}

KBManager::KBManager() {
    display = XOpenDisplay(nullptr);
    if (!display)
        PrintError("Cannot get display");
    rootWindow = XDefaultRootWindow(display);
    if (rootWindow == 0)
        PrintError("Cannot get window");
    pScreen = ScreenOfDisplay(display, 0);
    if (pScreen == nullptr)
        PrintError("Cannot get pScreen");
}

KBManager::~KBManager() {
    XCloseDisplay(display);
}

void KBManager::MoveMouse(int x, int y) {
    XWarpPointer(display, None, rootWindow, 0, 0, 0, 0, x, y);
    XFlush(display);
}

void KBManager::GetMousePosition() {
    XQueryPointer(display, rootWindow, &windowReturned, &windowReturned, &MouseX,
                  &MouseY, &win_x, &win_y,
                  &mask);
}

void KBManager::PressCapsLockTwice() {
    auto keycode = XKeysymToKeycode(display, XK_Caps_Lock);
    for (int count = 2; count > 0; --count) {
        XTestFakeKeyEvent(display, keycode, True, CurrentTime);
        Sleep(50);
        XFlush(display);
        XTestFakeKeyEvent(display, keycode, False, CurrentTime);
        Sleep(50);
        XFlush(display);
    }
}  

On the other hand, I can not get the version for windows to work. It just toggles "CapsLock" but don't trigger switch. I don't understand why.
Sample:

#include <iostream>
#include <thread>
#include <chrono>
#include <windows.h>

void PrintError(const char *msg, bool pause = false, bool shutdown = true);

void Sleep(int ms);

void PressKey(WORD key, int times = 1);

int main() {
    auto hConsole = GetConsoleWindow();
    ShowWindow(hConsole, SW_HIDE);
    int width, halfWidth, height, halfHeight;
    {
        RECT d;
        auto hD = GetDesktopWindow();
        GetWindowRect(hD, &d);
        width = d.right;
        height = d.bottom;
    }
    //align
    halfWidth = width / 2;
    width -= 4;
    halfHeight = height / 2;
    height -= 100;
    //align

    POINT point;
    while (true) {
        if (!GetCursorPos(&point))
            PrintError("Cannot get cursor pos");
        if (point.x >= width && point.y >= halfHeight && point.y <= height) {
            PressKey(VK_CAPITAL, 2);
            SetCursorPos(halfWidth, halfHeight);
            Sleep(10 * 1000);
        }
        Sleep(500);
    }
}

void PrintError(const char *msg, bool pause, bool shutdown) {
    fprintf(stdout, "%s\n", msg);
    if (pause)
        std::cin.get();
    if (shutdown)
        exit(EXIT_FAILURE);
}

void Sleep(int ms) {
    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}

void PressKey(WORD key, int times) {
    for (int i = 0; i < times; ++i) {

        //type 1
        INPUT input[2];
        ZeroMemory(input, sizeof(input));
        input[0].type = input[1].type = INPUT_KEYBOARD;
        input[0].ki.wVk = input[1].ki.wVk = key;
        input[1].ki.dwFlags = KEYEVENTF_KEYUP;
        SendInput(1, input, sizeof(INPUT));
        Sleep(50);
        SendInput(1, input + 1, sizeof(INPUT));
        Sleep(50);

        /*
        //type 2
        keybd_event(key, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
        Sleep(50);
        keybd_event(key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
        Sleep(50);
         */
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.