一、问题背景
忙碌的夜晚,我喝着拿铁,坐在电脑旁,在指尖且飞快的敲着键盘的时候,键盘突然打不了字,window窗口栏变灰,应该是窗口失焦了,此时只需要动动鼠标,点击窗口恢复焦点,就可以继续愉悦的敲键盘了。
此起彼伏,窗口又失去了焦点,双手已然在键盘位只能再去移动鼠标..点击窗口…..
周而复始几次后,我终于忍不住了。。
二、问题确认
问题具有随机性、可复现,在排除了“可能不小心按错键导致失焦”的可能性后。
我就把问题的关键词确认在 “window11”
“窗口失焦”
。
三、SFW(Seach in Fxxking Web)方法
得到了的关键词,开始了从互联网找答案。
通过一番操作后,仍然得不到任何有用的信息。
四、问题重新分析、猜测
互联网找不到答案,从问题根源入手。
由我目前的前置知识得知:
Force Window to Always Be in Focus
// window必然会有一个窗口焦点
但从我的现象来看,失焦的时刻并没有其他页面弹出,所以猜测焦点可能被后台程序获取了?传说中的"焦点窃取"
?
经过重新分析后,我确定下一步方向:找到窃取焦点的进程。
去Web查询窗口焦点的资料,发现了一个软件ViewWizard
,不仅可以捕捉到窗口的句柄,还能捕捉到窗口的pid。
但是使用起来没有那么理想:失去焦点时并没有捕捉到。
所以我找到了一篇博客:用亲切的C#实现的window api 获取 当前焦点窗口的信息,根据博客提供的思路和window API ,写出获取窗口句柄的代码。
https://www.cnblogs.com/mq0036/p/12575627.html
代码完成后,执行程序,尝试复现问题。果不其然,窗口被一个叫TscShellContainerClass的窗口捕捉了。
再用回软件ViewWizard
根据句柄查询PID。
知道了PID后,再通过命令查询线程的信息:
taskList|findstr XXXX
?这不是远程桌面的应用程序吗?他捕捉我焦点干嘛捏?
五、问题怎么产生、根源
通过process Manage,定位问题发生瞬间的调用信息
从mstu.exe的调用树已经几乎可以确认是WSL的锅了。
自己平时也不会去用远程桌面,这个功能也是我前段时间为了能使用WSLg才打开的。
并且问题发生的时刻,我没有主动去开启远程桌面程序,不过我WSLg默认是启动的,还是不明白问题的原因。
于是在确定了导致问题发生的mstsc,开始SFW
。
六、问题追溯
线索一:mstsc.exe
mstsc.exe stealing focus(mstsc.exe窃取了焦点)
https://answers.microsoft.com/en-us/windows/forum/all/mstscexe-stealing-focus/f9acb6fd-3c95-4e22-8f40-dc41dffbb178
帖子最终结果为官方也不知道。。当事人自己删除了wslg才临时解决问题。。
不过通过这一线索,基本可以确认问题出现在window 和 SubSystem linux 之间
线索二:Windows Subsystem for Linux GUI和mstsc.exe之间的联系
通过搜索得知,微软在WSLg System Distro
里加了远程桌面服务套件——FreeRDP
,一个支持Windows远程桌面协议(RDP)的服务端.
整个
WSLg System Distro
、Windows远程桌面客户端(mstsc.exe)的窗口都是对用户隐藏的,猜测是用户开启WSL或者敲完Linux GUI程序名的时候,这些隐藏的组件就已经在后台运行了。具体来说就是上图的WSLGd
,微软解释说一个类似守护进程的程序,负责启动Weston
、建立RDP通信等工作,如果它们挂了的话还要负责重启它们。
线索三、问题在于window通过RDP向WSL通信时
通过这一线索和开源的信息得知,当一些内容到shot(剪切板)时,负责RDP的线程发生崩溃。
最后发现了这个问题的issue:
官方解释和结论
由于从 FreeRDP 线程到 wayland 显示循环线程的多线程切换而导致事件源为 NULL,导致崩溃。
- 提供了临时解决的方案—关闭WSLg :)