なんともいえないプログラム

仕事じゃ役に立たない何とも言えないプログラムについて書いています。

discordとかLINEをCtrl+Enterで送信する2

前回の続きです

LINEだけに限定する

SetWindowsHookExは1スレッドか全スレッドのどちらかにしかフックできません。 このままではLINEと関係ないプロセスにもフックが入ってしまうのでLINEだけに限定します。

void SetMyKeyboardProcTarget()
{
    HWND targetWnd;
    unsigned long processID = 0;
    targetWnd = FindWindow("Qt5QWindowIcon", NULL);
    GetWindowThreadProcessId(targetWnd, &processID);
    dwTargetProcessId = processID;
}

LINEのウィンドウタイトル"Qt5QWindowIcon"を探してウィンドウハンドルからプロセスIDを保存しておきます。この関数はDLL_PROCESS_ATTACHのところで実行させます。 あとはsendInput関数を使用して改行なり送信なりを入力させればよいのですがこのままだとsendInputで送信したキーをフックしてまた送信と無限ループになってしまうためキーボードからなのかsendInputなのかを判定する機能を付けます。

キーボードかSendInputなのかを判定する

INPUT temp;
    temp.type = INPUT_KEYBOARD;
    temp.ki.wVk = key;
    temp.ki.wScan = MapVirtualKey(0, 0);
    temp.ki.dwFlags = iskeyUp;
DLLEXPORT LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
    if (code < 0) {
        return CallNextHookEx(g_hHook, code, wParam, lParam);
    }

    DWORD dwPid = GetCurrentProcessId();
    if (dwTargetProcessId == dwPid) {
        if (wParam == VK_RETURN && ((lParam & maskScan))) {
            if (GetKeyState(VK_CONTROL) & 0x8000) {
                SendInput(sendInput.size(), sendInput.data(), sizeof(INPUT));
                return 0;
            }
            if (SendInput(returnInput.size(), returnInput.data(), sizeof(INPUT)))
                return 0;
        }
        return CallNextHookEx(g_hHook, code, wParam, lParam);
    }

}

wScanを0にすることでキーボードかsendInputなのかを判定しています。これだけでLINEは完成です。
DiscordのほうはIMEに若干の癖がありますがほぼ同じです。ここまま完成でもよいですがexeが消えるとフックが外れて元に戻ってしまいます。
exeを常駐させればよいのですがやはりスタンドアロンのほうが夢があるので次はその説明に入ります。(完全なスタンドアロンではないですが..) dllのコードを載せておきます。

#include "pch.h"
#include <string>
#include <iostream>
#include <tchar.h>
#include "dllmain.h"
#include <vector>
#define DLLEXPORT extern "C" __declspec(dllexport)

HINSTANCE g_hInst;
#pragma data_seg(".shared")
HHOOK g_hHook = NULL;
std::vector<INPUT> returnInput;
std::vector<INPUT> sendInput;
static DWORD dwTargetProcessId = 0;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.shared,RWS")
DLLEXPORT void HookEnd();
const long maskScan = ((long)pow(2, 8) - 1) << 16;
void SetMyKeyboardProcTarget()
{
    HWND targetWnd;
    unsigned long processID = 0;
    targetWnd = FindWindow("Qt5QWindowIcon", NULL);
    GetWindowThreadProcessId(targetWnd, &processID);

    dwTargetProcessId = processID;
}

void pushKey(std::vector<INPUT>& in, WORD key, int iskeyUp) {
    INPUT temp;
    temp.type = INPUT_KEYBOARD;
    temp.ki.wVk = key;
    temp.ki.wScan = MapVirtualKey(0, 0);
    temp.ki.dwFlags = iskeyUp;
    in.push_back(temp);
}

DLLEXPORT LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
    if (code < 0) {
        return CallNextHookEx(g_hHook, code, wParam, lParam);
    }

    DWORD dwPid = GetCurrentProcessId();
    if (dwTargetProcessId == dwPid) {
        if (wParam == VK_RETURN && ((lParam & maskScan))) {
            if (GetKeyState(VK_CONTROL) & 0x8000) {
                SendInput(sendInput.size(), sendInput.data(), sizeof(INPUT));
                return 0;
            }
            if (SendInput(returnInput.size(), returnInput.data(), sizeof(INPUT)))
                return 0;
        }
        return CallNextHookEx(g_hHook, code, wParam, lParam);
    }

}
DLLEXPORT void HookStart()
{

    g_hHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, g_hInst, 0);
    if (g_hHook == NULL) {
        MessageBox(NULL, "フック開始は失敗しました", "HookStart", MB_OK);
        return;
    }
}

DLLEXPORT void HookEnd()
{
    UnhookWindowsHookEx(g_hHook);
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        SetMyKeyboardProcTarget();
        if (sendInput.empty()) {
            pushKey(returnInput, VK_SHIFT, 0);
            pushKey(returnInput, VK_RETURN, 0);
            pushKey(returnInput, VK_RETURN, KEYEVENTF_KEYUP);
            pushKey(returnInput, VK_SHIFT, KEYEVENTF_KEYUP);
            pushKey(sendInput, VK_CONTROL, KEYEVENTF_KEYUP);
            pushKey(sendInput, VK_RETURN, 0);
            pushKey(sendInput, VK_RETURN, KEYEVENTF_KEYUP);
        }
        g_hInst = (HINSTANCE)hModule;   // DLLモジュールのハンドル取得
    }
    return TRUE;
}