<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>ganesiroのブログ</title>
<link>https://ameblo.jp/ganesiro/</link>
<atom:link href="https://rssblog.ameba.jp/ganesiro/rss20.xml" rel="self" type="application/rss+xml" />
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com" />
<description>ブログの説明を入力します。</description>
<language>ja</language>
<item>
<title>キャップス</title>
<description>
<![CDATA[ <pre>PowerShell 5.1 + Windows Forms で作成中の既存アプリに、**Capsキーのダブルタップでフォームを表示／非表示するタスクトレイ常駐機能**を追加してください。この機能は単体テスト用スクリプトですでに動作確認できています。以下の実機確認済み条件を変更せず、既存アプリへ組み込んでください。# 1. 実行環境以下の環境を前提としてください。* Windows PowerShell 5.1* Windows Forms* Windows 10 / 11* `.ps1` / `.psm1` は UTF-8 BOM付きで保存する前提* PowerShell 7専用構文は使用しない* Win32 APIは `Add-Type` 内のC#から使用してよい以下のようなPowerShell 7以降の構文は使用しないでください。```powershell???.# PowerShell 7の三項演算子$condition ? $a : $b```# 2. コード内のコメントは日本語にする重要です。作成するPowerShellコードの、* セクション見出し* 処理説明* 注意事項* 変更理由などのコメントは、**原則として日本語で記述してください。**関数名、クラス名、Win32 API名など、プログラム上英語である必要があるものは英語のままで構いません。例えば、コード内の見出しは次のようにしてください。```powershell# ============================================================# 必要なアセンブリの読み込み# ============================================================# ============================================================# Capsキー ダブルタップ検出# ============================================================# ============================================================# Win32 API# ============================================================# ============================================================# アプリの状態管理# ============================================================# ============================================================# メインフォーム# ============================================================# ============================================================# タスクトレイ# ============================================================# ============================================================# タスクトレイメニュー# ============================================================# ============================================================# ウィンドウを隠す処理# ============================================================# ============================================================# ウィンドウをカーソル横に表示する処理# ============================================================# ============================================================# Capsキー ダブルタップ時の処理# ============================================================# ============================================================# ×ボタンを押したときの処理# ============================================================# ============================================================# タスクトレイ「表示」# ============================================================# ============================================================# タスクトレイ「隠す」# ============================================================# ============================================================# タスクトレイ「終了」# ============================================================# ============================================================# Capsキー ダブルタップ判定時間# ============================================================# ============================================================# キーボードフック開始# ============================================================# ============================================================# アプリ起動# ============================================================# ============================================================# 終了時の後始末# ============================================================```後からコードを見た人が、どの部分が何を担当しているか分かる構成にしてください。# 3. Capsキーについての重要な実機確認結果この環境では、Capsキーを押したときに通常の、```textVK_CAPITAL = 0x14```として取得されません。低レベルキーボードフックで実際に確認したCapsキーの入力は、```textVK       = 0xF0ScanCode = 0x3AFlags    = 0x00DOWN```です。つまりCapsキーの判定条件は、```textVK       = 0xF0ScanCode = 0x3AKEYDOWN```です。この条件は実機で確認済みなので、通常の、```csharpVK_CAPITAL = 0x14```へ勝手に変更しないでください。# 4. CapsキーのUPイベントを使用しないこれも非常に重要です。この環境ではCapsキーのUPイベントが通常の形で取得できませんでした。そのため、```textCaps DOWNCaps UPCaps DOWNCaps UP```をダブルタップとして判定する方式は使用しないでください。実機で正常動作した方式は、```textCaps DOWN↓Caps DOWN↓ダブルタップ成立```です。つまり、```textVK=0xF0ScanCode=0x3ADOWN```が2回発生した時間差だけでダブルCapsを判定してください。# 5. 低レベルキーボードフックを使用するWindows全体でCapsキーを検出するため、```textWH_KEYBOARD_LL```による低レベルキーボードフックを使用してください。最低限、以下のWin32 APIを使用してください。```textSetWindowsHookExCallNextHookExUnhookWindowsHookExGetModuleHandle```C#側では `KBDLLHOOKSTRUCT` を定義し、```textvkCodescanCodeflagstimedwExtraInfo```を正しく取得できるようにしてください。フック用デリゲートはGCで破棄されないよう、staticフィールドとして保持してください。また、フックの二重登録を防止してください。# 6. ダブルCapsの判定時間Capsキーの2回のDOWNイベントの時間差で判定してください。初期値は、```text100ms未満    ↓長押し・キーリピート等として無視100ms以上650ms以下    ↓ダブルCaps成立650ms超    ↓時間切れ    ↓今回のCaps DOWNを新しい1回目として扱う```としてください。C#側で例えば、```csharppublic static int MinimumIntervalMilliseconds = 100;public static int MaximumIntervalMilliseconds = 650;```のように、PowerShell側から後で変更できるようにしてください。# 7. ダブルタップ判定はC#側で行うCapsキーの、```textVK判定ScanCode判定DOWN判定時間差判定ダブルタップ成立判定```は、できるだけ `Add-Type` 内のC#側で完結させてください。ダブルCapsが成立したら、```csharpDoubleCaps```のようなイベントを発生させ、PowerShell側ではフォームの表示／非表示処理だけを担当する構造にしてください。# 8. 現段階ではCaps入力をブロックしない重要です。ダブルCaps検出は、この方式ですでに実機で正常動作しています。現段階ではCaps入力に対して、```csharpreturn (IntPtr)1;```を使用して、入力をWindowsから抑止しないでください。Caps入力についても最終的に、```csharpCallNextHookEx(...)```へ流してください。以前、Caps入力を抑止する実装を試したところ、状態判定が崩れた際に他のキーまで反応しなくなる問題が発生しました。そのため、**まずは現在動作しているダブルCaps検出を壊さないことを最優先**としてください。Caps本来の機能を無効化する処理は、必要になった場合に別工程として追加します。# 9. Capsダブルタップでフォームを表示／非表示するCapsを素早く2回押したら、フォームの表示状態をトグルしてください。## フォーム表示中```textCapsCaps```↓フォームを非表示。最小化ではなく、```powershell$form.Hide()$form.ShowInTaskbar = $false```を使用してください。結果として、```textフォーム    → 消えるタスクバー    → 消えるタスクトレイ    → 常駐継続```となるようにしてください。## フォーム非表示中再び、```textCapsCaps```↓フォームを再表示してください。再表示位置は、**現在のマウスカーソルの右側**です。# 10. カーソル右側への表示カーソル位置取得には、Win32 APIの、```textGetCursorPos```を使用してください。基本表示位置は、```textX = カーソルX + 20pxY = カーソルY```としてください。フォームの移動には必要に応じて、```textSetWindowPos```を使用してください。# 11. マルチモニターと画面外補正マルチモニター環境に対応してください。現在のカーソル位置から、```powershell[System.Windows.Forms.Screen]::FromPoint(...)```を使用して対象モニターを取得してください。そのモニターの、```powershell$screen.WorkingArea```を基準として、フォームが画面外へはみ出さないようにしてください。補正ルールは、```textカーソル右側にフォームが入る    ↓カーソル右側へ表示右側にはみ出す    ↓カーソル左側へ表示左端にはみ出す    ↓WorkingArea.Leftへ補正下端にはみ出す    ↓WorkingArea.Bottom - Form.Height上端にはみ出す    ↓WorkingArea.Top```としてください。# 12. 再表示したフォームを前面へ出すフォーム再表示後は、```textSetForegroundWindow$form.Activate()$form.BringToFront()```などを使用して、可能な範囲でフォームを前面へ出してください。# 13. UIスレッドへ処理を渡す低レベルキーボードフックのコールバックからWindows FormsのUIを直接操作しないでください。ダブルCaps成立後はPowerShell側で、```powershell$form.BeginInvoke(...)```などを使用し、UIスレッドへ処理を渡してください。# 14. フォーム表示状態を管理する必要に応じて、```powershell$script:FormVisible = $true```のような状態変数を使用してください。動作イメージ：```textFormVisible = true↓Capsダブルタップ↓Hide↓FormVisible = falseFormVisible = false↓Capsダブルタップ↓Show↓FormVisible = true```# 15. タスクトレイへ常駐させる`System.Windows.Forms.NotifyIcon` を使用してください。例えば、```powershell$tray = New-Object System.Windows.Forms.NotifyIcon$tray.Icon = [System.Drawing.SystemIcons]::Application$tray.Text = "アプリ名"$tray.Visible = $true```のような構造です。Windows側の仕様で、アイコンが通知領域の「^」内に収納されることは問題ありません。# 16. タスクトレイの右クリックメニュー最低限、```text表示隠す----------------終了```を作成してください。## 「表示」フォームが非表示なら、```text現在のカーソル右側へ表示```してください。すでに表示されている場合は、```powershell$form.Activate()$form.BringToFront()```などで前面へ出してください。## 「隠す」フォームを、```powershell$form.Hide()$form.ShowInTaskbar = $false```で非表示にしてください。## 「終了」本当にアプリを終了してください。終了時には最低限、```textキーボードフック解除↓NotifyIcon.Visible = false↓NotifyIcon.Dispose()↓フォームを閉じる↓Application.Exit()```を確実に実行してください。# 17. ×ボタンではアプリを終了しないフォーム右上の×ボタンを押してもアプリを終了させないでください。`FormClosing` で通常終了をキャンセルし、```powershell$e.Cancel = $true```として、フォームをタスクトレイへ収納してください。つまり、```text×ボタン↓フォーム非表示↓タスクバーから消える↓PowerShellプロセスは生存↓タスクトレイも生存↓キーボードフックも生存```としてください。本当に終了するのは、```textタスクトレイ↓右クリック↓終了```の場合だけです。必要なら、```powershell$script:ReallyExit = $false```のような終了フラグを使用してください。# 18. ShowDialogは使用しないこれは重要です。タスクトレイ常駐版では、```powershell$form.ShowDialog()```を使用しないでください。以前、`ShowDialog()` で表示していたフォームに、```powershell$form.Hide()```を実行したところ、`ShowDialog()` が終了し、そのままPowerShellスクリプト自体が終了してしまいました。そのため、```powershell$form.Show()[System.Windows.Forms.Application]::Run()```または同等の構造を使用してください。フォームが非表示になっても、```textPowerShellプロセスWindows FormsメッセージループNotifyIconキーボードフック```がすべて生存し続けることが必須です。# 19. 終了時の後始末`try / finally` 等を使用して、正常終了時だけでなく可能な範囲で後始末をしてください。最低限、```textUnhookWindowsHookExイベント解除NotifyIcon.Visible = falseNotifyIcon.Dispose()```を実行してください。# 20. 既存アプリへ組み込む場合既存アプリ全体をいきなり書き換えないでください。まず既存コードを確認し、```text現在のフォーム生成方法現在のShowDialog / Application.Runの使用状況現在の終了処理FormClosing処理既存のWin32 API既存のAdd-Type既存のNotifyIcon```との競合がないか確認してください。そのうえで、概ね次の順番で統合してください。```text1. Capsキー ダブルタップ検出クラス2. 必要なWin32 API3. アプリの状態管理4. NotifyIcon5. タスクトレイメニュー6. Hide-MainWindow7. Show-MainWindowAtCursor8. DoubleCapsイベント9. FormClosing10. 終了処理11. Application.Run方式への統合```# 21. 既存アプリがShowDialogを使っている場合既存コードの最後などに、```powershell[void]$form.ShowDialog()```が存在する場合、そのままタスクトレイ常駐機能を追加しないでください。まず常駐方法との競合を確認し、```powershell$form.Show()[System.Windows.Forms.Application]::Run()```を基本とした構造へ適切に変更してください。ただし、既存アプリの処理を壊さないように変更してください。# 22. コードの見出し・説明コメント生成するコードの見出しや説明コメントは、原則日本語にしてください。特に、以下のような日本語見出しを使用してください。```powershell# ============================================================# 必要なアセンブリの読み込み# ============================================================# ============================================================# Capsキー ダブルタップ検出# ============================================================# ============================================================# Win32 API# ============================================================# ============================================================# アプリの状態管理# ============================================================# ============================================================# メインフォーム# ============================================================# ============================================================# タスクトレイ# ============================================================# ============================================================# タスクトレイメニュー# ============================================================# ============================================================# ウィンドウを隠す処理# ============================================================# ============================================================# ウィンドウをカーソル横に表示する処理# ============================================================# ============================================================# Capsキー ダブルタップ時の処理# ============================================================# ============================================================# ×ボタンを押したときの処理# ============================================================# ============================================================# タスクトレイ「表示」# ============================================================# ============================================================# タスクトレイ「隠す」# ============================================================# ============================================================# タスクトレイ「終了」# ============================================================# ============================================================# Capsキー ダブルタップ判定時間# ============================================================# ============================================================# キーボードフック開始# ============================================================# ============================================================# アプリ起動# ============================================================# ============================================================# 終了時の後始末# ============================================================```# 23. 完成後に必要な動作最終的に、以下の動作にしてください。```textアプリ起動↓フォーム表示↓Capsを素早く2回↓フォーム非表示↓タスクバーから消える↓タスクトレイには常駐↓Capsをもう一度素早く2回↓現在のマウスカーソル右側へフォーム表示```さらに、```text×ボタン    → 終了せず非表示タスクトレイ「表示」    → フォーム表示タスクトレイ「隠す」    → フォーム非表示タスクトレイ「終了」    → 完全終了```としてください。# 24. 将来的なCaps＋キーのショートカット将来的にはCapsキーを独自ショートカットレイヤーとして使用する予定です。例えば、```textCaps + ACaps + SCaps + DCaps + 1Caps + 2```などです。そのため、将来的に、```textCapsダブルタップ    → フォーム表示／非表示Caps + 任意キー    → 個別ショートカット```を共存させられる設計にしてください。ただし、**現段階ではCaps＋キーのショートカット機能を無理に実装しないでください。**まず、```textVK       = 0xF0ScanCode = 0x3ADOWN```の2回検出による、現在正常動作しているダブルCaps機能を維持することを優先してください。# 25. 特に変更してはいけないポイント以下は実機テストによって判明した重要事項です。勝手に一般的なCapsLock実装へ変更しないでください。```text× VK_CAPITAL = 0x14 のみで判定× Caps DOWN → Caps UP を1タップとして判定× UPイベントを待ってダブルタップ判定× Caps入力を最初から return (IntPtr)1 で抑止```現在動作確認済みなのは、```textVK       = 0xF0ScanCode = 0x3ADOWN```を検出し、```text1回目のDOWN↓100～650ms↓2回目のDOWN↓ダブルCaps成立```とする方式です。**この動作確認済み部分を維持してください。**# 26. 出力してほしいもの既存アプリのコードを渡した場合は、まずコードを確認してください。そのうえで、```text・どこへ追加するのか・どこを変更するのか・どこを削除／置換するのか・既存処理と競合する部分はないか・ShowDialogを変更する必要があるか```を説明してください。その後、**PowerShell 5.1でそのまま実行できる完全な修正版コードを全文で提示してください。**差分だけではなく、可能であれば完成した全文を提示してください。また、コード内のセクション見出しと説明コメントは原則として日本語にしてください。</pre>
]]>
</description>
<link>https://ameblo.jp/ganesiro/entry-12975927012.html</link>
<pubDate>Sun, 16 Aug 2026 19:30:30 +0900</pubDate>
</item>
</channel>
</rss>
