概要
OpenSiv3D で、Windows のポップアップメニュー(コンテキストメニュー/ショートカットメニュー)を表示し、クリックされた項目を取得します。
開発環境
- Windows 11
- Visual Studio 2022
- OpenSiv3D 0.6.11
どうやるか
OpenSiv3D には Windows のメニューを扱う機能がないので、Win32API を使います。
メニューを表示する基本的な流れは次のとおりです:
- LoadMenu 関数で、リソースからメニューをロードする
- GetSubMenu 関数でサブメニューを取得する
- TrackPopupMenu 関数でメニューを表示する
ただし、OpenSiv3D アプリは次のようにスレッドが分かれています:
- THREAD #0: ウィンドウプロシージャが実行されるスレッド
- THREAD #1: Main 関数が実行されるスレッド(メインスレッド)
そのためか、メインスレッドからの TrackPopupMenu の実行は失敗してしまいます。
なので、メニューのロード~表示までの一連の流れをウィンドウプロシージャのスレッドで行うことにします。具体的な流れは、次のようになります:
- SetWindowLongPtr 関数で、ウィンドウプロシージャを自前のものに変更する
- メニューを表示したいときは、あらかじめ決めておいたメッセージ(WM_USER + 適当な数値 など)をウィンドウに送る。ウィンドウプロシージャはそのメッセージを受けてメニューのロード~表示を行う
- メニューがクリックされると、ウィンドウプロシージャに WM_COMMAND メッセージが送られる。ウィンドウプロシージャは PostThreadMessage 関数でその内容をメインスレッドに送る
- メインスレッドでは 3. で送られたメッセージを GetMessage 関数で取得する
ソースコード
メニューの編集方法
Visual Studio のリソースビューからメニューリソースを編集する際、OpenSiv3D のプロジェクトにはじめから入っている Resource.rc に対してメニューを追加すると、もともとの内容がぐちゃぐちゃになってしまうので(何かやりかたが悪い?)、メニュー用に Resource2.rc などとして別ファイルを追加して、これを編集するのが良いと思います。