discordとかLINEをCtrl+Enterで送信する1
初めに
皆さん普段からLINEやdiscord、slackといった様々なコミュニケーションツールを使用していると思います。これらのツールで送信するときLINEやdiscordはEnter、slackやtwitterはctrl+enterとツールによってバラバラです。個人的には誤爆を防ぐためにすべてCtrl+Enterで統一したいところですが送信方法を設定できないツールも多く設定できてもAlt+Enterで送信とかいう微妙な設定しかありません。
そこでツールにキー入力(Ctrl+Enter)が入ったときに入力を内部でEnterに変えてツールに送ればCtrl+Enterで送信できるはずです。
キー入力乗っ取り
あるプログラムの中で任意のプログラムを動作させるにはdllインジェクションを行います。プログラムに流れるキー入力を監視しEnterが押されたら破棄し、改行キーを送り直します。Ctrl+Etnerが来ればEnterのみを送信します。
dllインジェクション
dllをプログラムに埋め込むにはSetWindowsHookEx関数を使用します。
HHOOK SetWindowsHookExW( int idHook, //フックタイプ HOOKPROC lpfn, //コールバック関数 HINSTANCE hmod, //dllハンドル DWORD dwThreadId//スレッド識別子 );
今回のフックタイプにはWH_KEYBOARDを指定します。このフックタイプはキーボードの入力があれば指定したコールバック関数が実行されます。 dllのエントリポイントでハンドルを取得しておきます。
BOOL APIENTRY DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { g_hInst = (HINSTANCE)hModule; // DLLモジュールのハンドル取得 } return TRUE; }
そしてフックする関数を以下のように定義しておきます。
DLLEXPORT void HookStart() { g_hHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, g_hInst, 0); if (g_hHook == NULL) { MessageBox(NULL, "フック開始は失敗しました", "HookStart", MB_OK); return; } }
コールバック関数にはとりあえず適当に作っておきます。
DLLEXPORT LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) { MessageBox(NULL, std::to_string(wParam).c_str(), "Hook", MB_OK); return CallNextHookEx(g_hHook, code, wParam, lParam); }
WH_KEYBOARDではwParamに入力されたキー情報が格納されています。
CallNextHookEx(g_hHook, code, wParam, lParam);では受け取った情報をそのまま親プロセスに渡します。NULL等を返せば横取りしたキー入力をそのまま破棄するのでなにも入力できなくなります。
ここまではdllに書くプログラムでしたが最初にこのdllを読み込んでHookStart()を実行しなければdllを流し込めません。 そこで、このdllを流し込むexeを作成していきます。
MSG msg; HINSTANCE hinst = LoadLibrary(TEXT("CTRLSENDLL.dll")); if (hinst) { typedef void (*Install)(); typedef void (*Uninstall)(); Install install = (Install)GetProcAddress(hinst, "HookStart"); install(); while (GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } }
これを実行すれば起動しているあらゆるプログラムにdllが注入されてキー入力するたびにメッセージボックスが出現します。
ここで注意するのはLINEやdiscordは32bitソフトなので流し込むdllも32bitで作成しないとdllインジェクションは失敗します。
続きはまた書きます。dllの全文は以下に置いておきます。
#include "pch.h" #include <string> #pragma comment(lib, "imm32.lib") #include "dllmain.h" #define DLLEXPORT extern "C" __declspec(dllexport) HINSTANCE g_hInst; #pragma data_seg(".shared") HHOOK g_hHook = NULL; #pragma data_seg() #pragma comment(linker, "/SECTION:.shared,RWS") DLLEXPORT LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) { MessageBox(NULL, std::to_string(wParam).c_str(), "Hook", MB_OK); 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) { g_hInst = (HINSTANCE)hModule; // DLLモジュールのハンドル取得 } return TRUE; }