WSLg が入力フォーカスを奪う話 – msrdc.exe
TL;DR
Windows でテキストを入力中に突然フォーカスが外れる現象に悩んでいた。
犯人は自作アプリではなく WSLg(Windows Subsystem for Linux GUI)だった。
.wslconfig に1行追記して解決。
症状
Rust(Tauri)製のスタンドアロンアプリを開発中、入力フォーカスが突然外れる現象が断続的に発生した。とてもじゃないが作業ができたものではないレベルの頻度。
1. 仮説: 自作アプリが原因では?
開発中のアプリは Windows のファイルシステムを監視する機能を持っており、バックグラウンドで ReadDirectoryChangesW を使って常時ファイルイベントを拾っている。これが怪しいのでは?
まずはカーソルを奪われたときに何のプロセスが走っているか見てみます。
# Windows APIの定義(最前面のウインドウハンドルとプロセスIDを取得するため)
$Signature = @'
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
'@
$User32 = Add-Type -MemberDefinition $Signature -Name "User32Utils" -PassThru
Write-Host "--- ウインドウフォーカス監視 ---"
Write-Host "フォーカスが外れた瞬間にここに表示されるプロセス名を確認 `n"
$LastProcessId = 0
while ($true) {
# 現在最前面にあるウインドウのハンドルを取得
$Hwnd = $User32::GetForegroundWindow()
if ($Hwnd -ne [IntPtr]::Zero) {
$ProcessId = 0
# ウインドウハンドルからプロセスIDを取得
$null = $User32::GetWindowThreadProcessId($Hwnd, [ref]$ProcessId)
# 前回チェック時とプロセスIDが変わった場合のみ出力
if ($ProcessId -ne $LastProcessId) {
$Process = Get-Process -Id $ProcessId -ErrorAction SilentlyContinue
if ($Process) {
$Timestamp = Get-Date -Format "HH:mm:ss.fff"
$ProcessName = $Process.ProcessName
$WindowTitle = $Process.MainWindowTitle
# 画面に出力
Write-Host "[${Timestamp}] プロセス名: ${ProcessName} | ウインドウタイトル: ${WindowTitle}" -ForegroundColor Cyan
$LastProcessId = $ProcessId
}
}
}
# 0.1秒待機してループ(負荷軽減)
Start-Sleep -Milliseconds 100
}
で、通常通りすぐにカーソルを奪われました。その瞬間返ってきた値は…
出力:
[11:03:25.735] プロセス名: msrdc | ウインドウタイトル:
誰だよ!!!
とは言っても調べるしかない。調べるときは取り敢えずGemini君に聞いてみます。
msrdc(Microsoft Remote Desktop Client)は、Windowsの「リモートデスクトップ(またはAzure Virtual Desktop / Windows 365など)」に関連するマイクロソフト純正のバックグラウンドプロセスです。
…ははーん、 そういうことね?(わかってない)
msrdc は「WSL2のGUIアプリ(WSLg)をWindows側で表示・制御するためのバックグラウンド通信」を行っている可能性が極めて高いです。
ホントかあ?と思いつつタスクマネージャーの詳細タブで msrdc とやらを確認します。
「そんなタスクは…無…!?」 一瞬出てきて消えた。カーソルは?「奪われて…いる!!」
「見つけた!この監視が msrdc.exe と何らかのハンドル競合を起こしているに違いない!」と疑い、ファイル監視を無効化してビルドし直した。
結果:フォーカス強奪は継続。
自作アプリは無関係でした。
2. msrdc.exe 本体を調べる
msrdc.exe はリモートデスクトップのバックグラウンドプロセスであることは先程確認した。しかしリモート接続などしていないのになぜ起動しているのか。
PowerShell で親プロセスを確認します。
Get-CimInstance Win32_Process -Filter "Name='msrdc.exe'" |
Select-Object ProcessId, ParentProcessId,
@{n='ParentName';e={(Get-Process -Id $_.ParentProcessId -EA 0).Name}},
CommandLine |
Format-List
出力:
ParentName : wslhost
CommandLine : msrdc.exe /wslg /silent /plugin:WSLDVC_PACKAGE ... "wslg.rdp"
/wslg というフラグ。親プロセスは wslhost。
Oh…
根本原因:WSLg だった
WSLg(Windows Subsystem for Linux GUI) は、Linux の GUI アプリを Windows 上に表示するための仕組みで、内部的に msrdc.exe を仮想ディスプレイ転送として使っている。
WSL セッションの開始・再接続のたびに msrdc.exe が起動し、その瞬間にフォアグラウンドを奪う。私の環境の場合は WSL2 を bash 専用で使っており、Linux GUI アプリは一切使っていない。つまり WSLg は完全に不要。
解決
%USERPROFILE%\.wslconfig に1行追記する(ファイルがなければ新規作成)。
[wsl2]
guiApplications=false
その後 WSL を再起動。
wsl --shutdown
以降、WSLg は起動しなくなり、フォーカス強奪は完全に止まった。
補足
guiApplications=falseは Linux GUI アプリの Windows 表示機能のみを無効化する。bash などの CLI 操作には一切影響しない。- 「
msrdc.exeがフォーカスを奪う」で検索してもリモートデスクトップ関連の情報しか出てこず、WSLg が原因だと辿り着くのに時間がかかった。同じ症状で悩んでいる人の参考になれば。