👻

[C++] ショートカットキーを自力で拡張してみた

に公開

いつもWindows pcの電源を消すときは、Win + Dでデスクトップに行って、そこでAlt + F4を押してEnterを押さないといけない。そしてスリープや再起動に関しては、Alt + F4の後に上下矢印のキーを押してからEnterを押さないとそれらの操作ができない。それでも操作はキーボードで済んで楽なほうだけど、どうせならキーボード一発でそれらの処理を終わらせたい。
 ということでWindowsのショートカットキーを自力で拡張してみました!C++初心者ですのでコードが稚拙かもしれませんがお許しください!

プロジェクトの作成

  1. Visual StudioのC++で、Windows Desktop Wizardを選択

  1. プロジェクト名を自分で決めてCreateを押す
  2. Empty ProjectにチェックをつけてOKを押す

プロジェクトの設定

  1. プロジェクトのプロパティを開く
  2. 構成プロパティ < リンカー < システムを開く
  3. サブシステムの項目をWindows (/SUBSYSTEM:WINDOWS)に変更

これでプログラムのエントリーポイントがWinMain関数になり、Win32APIを利用したアプリ開発ができます。

コード

#include <Windows.h>
#include <WinUser.h>
#include <powrprof.h>
#pragma comment(lib, "PowrProf.lib")

#define HOTKEY_SHUTDOWN 1
#define HOTKEY_SLEEP 2
#define HOTKEY_RESTART 3

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdLine,
	int nCmdShow
)
{
	HANDLE hMutex = CreateMutex(NULL, TRUE, L"MyUniqueAppMutexName");
	if (GetLastError() == ERROR_ALREADY_EXISTS) return 0;

	TCHAR szAppName[] = TEXT("Win32API_test");
	WNDCLASS wc;
	HWND hwnd;
	MSG msg;

	wc.style = CS_HREDRAW || CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = szAppName;

	if (!RegisterClass(&wc)) return 0;

	hwnd = CreateWindow(
		szAppName,
		TEXT("Win32API_test"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL
	);

	if (!hwnd) return 0;

	UpdateWindow(hwnd);

	RegisterHotKey(hwnd, HOTKEY_SHUTDOWN, MOD_CONTROL, VK_F12);
	RegisterHotKey(hwnd, HOTKEY_SLEEP, MOD_CONTROL | MOD_SHIFT | MOD_ALT, 'S');
	RegisterHotKey(hwnd, HOTKEY_RESTART, MOD_CONTROL | MOD_SHIFT | MOD_ALT, 'R');


	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	ReleaseMutex(hMutex);
	CloseHandle(hMutex);

	return 0;
}

ユーザーのキーボード入力を監視するバックグラウンドアプリなのでGUIは特にありません。
 アプリが複数起動されないようにMutexを利用しています。
 RegisterHotKey関数で以下のショートカットキーを登録しています。

  • Ctrl + F12 (シャットダウン)
  • Ctrl + Shift + Alt + S (スリープ)
  • Ctrl + Shift + Alt + R (再起動)

ショートカットキー入力時の処理を行うコードは以下です。

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_HOTKEY:
		switch (wParam)
		{
		case HOTKEY_SHUTDOWN:
			ShellExecuteW(NULL, L"open", L"cmd.exe", L"/c shutdown /s /t 0", NULL, SW_HIDE);
			break;

		case HOTKEY_SLEEP:
			SetSuspendState(FALSE, FALSE, FALSE);
			break;

		case HOTKEY_RESTART:
			ShellExecuteW(NULL, L"open", L"cmd.exe",L"/c shutdown /r /t 0", NULL, SW_HIDE);
			break;
		}
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	default:
		return DefWindowProc(hwnd, message, wParam, lParam);
	}
}

シャットダウンと再起動もWin32APIの関数を使って処理してもいいのですが、権限の取得が必要で面倒なのでshutdown.exeを使って処理しています。ShellExecuteW関数を利用しているのは、system関数だとcmdのウィンドウが表示されてしまい目に障るからです。

アプリ使用方法

  1. ここからダウンロードする
  2. 自分の好きな場所にMyHotKey.exeを配置する
  3. Win + Rを押して、regeditと入力してEnterを押す
  4. 以下のパスのところに移動する
    HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
  5. 右クリックして文字列の値を新規作成する
  6. 名前をMyHotKeyにして、値を自分が配置したアプリのパスにする
  7. PCを再起動する
  8. 完了

感想

シャットダウン、スリープ、再起動という地味な操作しか実装していないが、よくやる操作であることに変わりないので便利だと思った。ショートカットキーを一発入力すればちゃんと処理が行われるのでとても楽になった。今度は何を作ろうかなぁ。

追記

キー入力の監視かつシャットダウン、再起動などというウイルスによくありそうな挙動のせいでウイルス対策ソフトにアプリがブロックされるっぽいです。ショートカットキー入力だけでいきなりシャットダウンなどをするからウイルスだと疑われてしまうのかな。いつかその問題を解決したいなぁ。

ぽちぽちのつどい

Discussion