wxWidgets / wxWidgets

Cross-Platform C++ GUI Library
https://www.wxwidgets.org/
5.84k stars 1.71k forks source link

Freeze with Microsoft IME input (japanese/chinese character input) #22473

Open SteveDaulton opened 2 years ago

SteveDaulton commented 2 years ago

Describe the bug Application freezes with Microsoft IME Chinese / Japanese. Issue can be worked around by using IME compatibility mode, or using an old enough version of IME.

Expected vs observed behaviour Not freezing

Patch or snippet allowing to reproduce the problem

Steps to reproduce in KiCad: https://gitlab.com/kicad/code/kicad/-/issues/11502#note_934148979 Steps to reproduce in Audacity: https://github.com/audacity/audacity/issues/805

Platform and version information

vadz commented 2 years ago

Thanks for reporting this, it's probably indeed a problem in wxWidgets, but it's going to be difficult to debug it if it can't be reproduced in simpler examples -- has anybody tried doing it? I.e. just build e.g. text wxWidgets sample and try using it with CJK IME, does it hang too?

SteveDaulton commented 2 years ago

I.e. just build e.g. text wxWidgets sample and try using it with CJK IME,

Sorry but I don't use Windows, otherwise I'd have done exactly that ;-) Hopefully it will be easily reproducible with a minimal example. Note that the KiCad bug report provides very useful steps for reproducing the bug without having to be able to read Chinese.

marekr commented 1 year ago

To note on that kicad bug report, I've spent alot of time hunting down the freeze.

Since I switched to 3.1.6 and above, the ease of causing the freeze has gone down with IME but it still happens.

I don't know if I can blame wx entirely for the bug because debugging, the message pump is still running but no longer seems to receive any messages from windows on actions.

I theorize in kicad it's because we aggressively change focus to a control so we can listen to hotkeys for cad interaction as much as possible. The focus stealing event may interrupt the IME control that Microsoft tries to display. Audacity could have a similar issue

vadz commented 1 year ago

I've followed the instructions in the KiCad bug report for installing Chinese IME, but I can't reproduce the problem. It probably doesn't help that I have no idea what to do with it, i.e. how to actually use IME, but it could also be that KiCad (and Audacity?) do something special triggering it.

@marekr Does it hang when a key (which one? any?) is pressed while the mouse is captured or am I misunderstanding this?

marekr commented 1 year ago

Well it's been awhile and since wx 3.1.6 it actually got harder for me to reproduce it but CJK users still say it happens.

I had it happen even in text boxes and not during our mouse capture of the canvas if that's what you mean. When I was debugging it, the event loop was still running but it seemed to have stopped receiving most but one weird event that I didn't figure out what it was.

The only thought I've had on trigger, is that it relates to our mouse focus capture. We aggressively try and ensure the canvas has focus when you are over it in order to ensure keys are going to the canvas for hotkey processing (Audacity may do something similar if they have hotkeys). It could be a Focus() call breaks the Microsoft IME somehow. I really have no idea how the IME interacts with an application's event message pump.

vadz commented 1 year ago

So would be the sequence of events here be something like this

  1. Focus wxTextCtrl.
  2. Start inputting an IME sequence into it.
  3. Focus another window (do you do it on mouse move message or something like that?).
  4. Press another key.
  5. Freeze

?

ebadger commented 1 year ago

Freeze is likely caused by nested message loop that can only be existed by keyboard event. The nested message loop is filtering messages required to process keyboard input and thus is unable to exit the state. Please try adjusting the message filter to allow dispatch of the message 0x60.

Maybe here?

int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)

marekr commented 1 year ago

It appears 0x0060 (fun undocumented message that Eric apparently knows being a MS employee ;) ) is getting thrown out due to this check in wxGUIEventLoop::PreProcessMessage

(I set a conditional breakpoint on the message id)

This is returning "true", so the DispatchMessage call never occurs one level up in wxGUIEventLoop::ProcessMessage

        if ( !wndThis )
        {
            // this may happen if the event occurred in a standard modeless dialog (the
            // only example of which I know of is the find/replace dialog) - then call
            // IsDialogMessage() to make TAB navigation in it work

            // NOTE: IsDialogMessage() just eats all the messages (i.e. returns true for
            // them) if we call it for the control itself
            return hwnd && ::IsDialogMessage(hwnd, msg) != 0;
        }

It can be confirmed sniffing win32 api calls that no Dispatch is ever issued for a peek of 0x0060

image

marekr commented 1 year ago

However, it appears the IsDialogMessage usage not continuing to DispatchMessage is correct?

The Microsoft document says:

Because the IsDialogMessage function performs all necessary translating and dispatching of messages, a message processed by IsDialogMessage must not be passed to the TranslateMessage or DispatchMessage function.

:S

vadz commented 1 year ago

Thanks for the hint about the message 0x0060 (judging from the lack of answers to this question nobody is willing to explain what it means in public, so I won't ask...).

Of course, IsDialogMessage() is supposed to only return true if it actually did handle the message, but it wouldn't be the first time this function behaves weirdly. We probably should restrict its use in wxGUIEventLoop::PreProcessMessage() to HWND corresponding to wxFindReplaceDialog but perhaps for now just this

diff --git a/src/msw/evtloop.cpp b/src/msw/evtloop.cpp
index 34018e8bee..dc4859e6cb 100644
--- a/src/msw/evtloop.cpp
+++ b/src/msw/evtloop.cpp
@@ -84,6 +84,12 @@ bool wxGUIEventLoop::PreProcessMessage(WXMSG *msg)
             // only example of which I know of is the find/replace dialog) - then call
             // IsDialogMessage() to make TAB navigation in it work

+            // Except that we shouldn't call it for an undocumented message
+            // generated when using IME that it would consume, but that we must
+            // not actually process.
+            if ( msg->message == 0x0060 )
+                return false;
+
             // NOTE: IsDialogMessage() just eats all the messages (i.e. returns true for
             // them) if we call it for the control itself
             return hwnd && ::IsDialogMessage(hwnd, msg) != 0;

would be enough to fix the bug?

ebadger commented 1 year ago

apologies for the latency on response - I'm checking my assumptions again and working to repro

vadz commented 1 year ago

Could anybody please check if my patch above helps with avoiding the problem? Would be nice to fix this before the bug's first anniversary...

marekr commented 1 year ago

Could anybody please check if my patch above helps with avoiding the problem? Would be nice to fix this before the bug's first anniversary...

Unfortunately, at least for me, reproducing the problem in KiCad is actually really hard on my dev setup. Some of our users apparently constantly encounter lockups in consistent manners but it doesn't on other machines.

The most I did recently was break the IME editor system wide on windows such that "Chinese mode" was permanent acting like English mode until I restarted :/

MunoLike commented 11 months ago

I cope with this problem by turning on compatible mode of the IME. After turning on, I can use KICAD with no freeze. According to microsoft's webpage, Microsoft Japanese IME has been replaced to new one when Windows10 2020-10 (version.2004) update happened. https://support.microsoft.com/ja-jp/windows/microsoft-%E6%97%A5%E6%9C%AC%E8%AA%9E-ime-da40471d-6b91-4042-ae8b-713a96476916

After I've finished designing my board, I'll test above patch.


2023-7-3 edited

Add english version of Microsoft Japanese IME document page. https://support.microsoft.com/en-us/windows/microsoft-japanese-ime-da40471d-6b91-4042-ae8b-713a96476916

vadz commented 11 months ago

I cope with this problem by turning on compatible mode of the IME. After turning on, I can use KICAD with no freeze. According to microsoft's webpage, Microsoft Japanese IME has been replaced to new one when Windows10 2020-10 (version.2004) update happened. https://support.microsoft.com/ja-jp/windows/microsoft-%E6%97%A5%E6%9C%AC%E8%AA%9E-ime-da40471d-6b91-4042-ae8b-713a96476916

Unfortunately the link is not very useful for those who don't read Japanese...

After I've finished designing my board, I'll test above patch.

Please us let us know about the result, whether it's positive or negative. Thanks in advance!

MunoLike commented 11 months ago

I tried applying above patch but sadly, the KiCAD freeze problem was not fixed. Then I installed windbg and got the call stack when it happened. Here is the log.

0:038> ~0 kp
 # Child-SP          RetAddr               Call Site
00 0000001b`f48ff348 00007fff`cf9907fe     win32u!NtUserMsgWaitForMultipleObjectsEx+0x14
01 0000001b`f48ff350 00007fff`1a0ad9ba     USER32!RealMsgWaitForMultipleObjectsEx+0x1e
02 0000001b`f48ff390 00007fff`1a0ad92f     wxbase32u_vc_custom!wxMSWEventLoopBase::GetNextMessageTimeout(struct tagMSG * msg = 0x0000001b`f48ff530 {msg=0xc045fc0 wp=0x0 lp=0x0}, unsigned long timeout = 0xffffffff)+0x7a [D:\DevTools\vcpkg\buildtrees\wxwidgets\src\9092315d13-8240b4b5b6.clean\src\msw\evtloopconsole.cpp @ 109] 
03 0000001b`f48ff4d0 00007fff`101fe068     wxbase32u_vc_custom!wxMSWEventLoopBase::GetNextMessage(struct tagMSG * msg = <Value unavailable error>)+0xf [D:\DevTools\vcpkg\buildtrees\wxwidgets\src\9092315d13-8240b4b5b6.clean\src\msw\evtloopconsole.cpp @ 99] 
04 0000001b`f48ff500 00007fff`19fd6ef3     wxmsw32u_core_vc_custom!wxGUIEventLoop::Dispatch(void)+0x18 [D:\DevTools\vcpkg\buildtrees\wxwidgets\src\9092315d13-8240b4b5b6.clean\src\msw\evtloop.cpp @ 173] 
05 (Inline Function) --------`--------     wxbase32u_vc_custom!wxEventLoopManual::ProcessEvents(void)+0x24 [D:\DevTools\vcpkg\buildtrees\wxwidgets\src\9092315d13-8240b4b5b6.clean\src\common\evtloopcmn.cpp @ 234] 
06 0000001b`f48ff570 00007fff`19fd717a     wxbase32u_vc_custom!wxEventLoopManual::DoRun(void)+0x83 [D:\DevTools\vcpkg\buildtrees\wxwidgets\src\9092315d13-8240b4b5b6.clean\src\common\evtloopcmn.cpp @ 288] 
07 0000001b`f48ff5a0 00007fff`19fa7e67     wxbase32u_vc_custom!wxEventLoopBase::Run(void)+0x6a [D:\DevTools\vcpkg\buildtrees\wxwidgets\src\9092315d13-8240b4b5b6.clean\src\common\evtloopcmn.cpp @ 87] 
08 0000001b`f48ff600 00007ff6`8d1d568a     wxbase32u_vc_custom!wxAppConsoleBase::MainLoop(void)+0x67 [D:\DevTools\vcpkg\buildtrees\wxwidgets\src\9092315d13-8240b4b5b6.clean\src\common\appbase.cpp @ 381] 
09 0000001b`f48ff650 00007fff`1a02301c     kicad!pybind11::error_already_set::clear+0x115a
0a 0000001b`f48ff690 00007fff`1a0f63c8     wxbase32u_vc_custom!wxEntryReal(int * argc = 0x00000131`09b55750, wchar_t ** argv = 0x00000000`00000000)+0x9c [D:\DevTools\vcpkg\buildtrees\wxwidgets\src\9092315d13-8240b4b5b6.clean\src\common\init.cpp @ 508] 
0b 0000001b`f48ff6d0 00007ff6`8d3cac8a     wxbase32u_vc_custom!wxEntry(int * argc = 0x00007fff`1a1f39f8, wchar_t ** argv = 0x00000131`09b55750)+0x28 [D:\DevTools\vcpkg\buildtrees\wxwidgets\src\9092315d13-8240b4b5b6.clean\src\msw\main.cpp @ 175] 
0c 0000001b`f48ff700 00007fff`d03b7614     kicad!make_fcontext+0xf50aa
0d 0000001b`f48ff740 00007fff`d19626f1     KERNEL32!BaseThreadInitThunk+0x14
0e 0000001b`f48ff770 00000000`00000000     ntdll!RtlUserThreadStart+0x21

I can reproduce this by do like https://gitlab.com/kicad/code/kicad/-/issues/9882 .

  1. Opening a kicad project.
  2. Opening a kicad_pcb file.
  3. Placing a part and trying to move.
  4. If the kicad doesn't freeze, closing it and repeating from the first step.

I feel like as quickly as possible key pressed when start up a kicad_pcb (pcbnew), the problem is more likely to be occured. In my case, it freezed with in 5 attempts. I'm not sure if I should post here, but just in case.

MunoLike commented 11 months ago

I also post the screenshot of the local variable from windbg. image

It seems KiCAD runs all programs in one process when it's used with a project. There is no problem when I execute pcbnew separately.

vadz commented 11 months ago

Thanks for testing this, I'll try reproducing this again but, just to be sure I do things correctly: when the bug report says

Make sure you're using Microsoft Pinyin and the compatibility switch is turned off

How do I make sure this is the case, i.e. how to verify that compatibility switch is off? Edit: Please ignore this, I've found the compatibility option in the IME settings myself, sorry.

Also, a question more for @marekr: do you have any idea what could be the difference between the hanging case and "executing pcbnew separately"?

marekr commented 11 months ago

Thanks for testing this, I'll try reproducing this again but, just to be sure I do things correctly: when the bug report says

Make sure you're using Microsoft Pinyin and the compatibility switch is turned off

How do I make sure this is the case, i.e. how to verify that compatibility switch is off? Edit: Please ignore this, I've found the compatibility option in the IME settings myself, sorry.

Also, a question more for @marekr: do you have any idea what could be the difference between the hanging case and "executing pcbnew separately"?

KiCad's main application window becomes a "project manager" instead of the "pcbnew" window.

Mmmm, I can repro it now but I don't have a lick of what to do given the IME editor is one blackbox mystery.

vadz commented 11 months ago

KiCad's main application window becomes a "project manager" instead of the "pcbnew" window.

I don't understand at all what could it do for the purposes of input handling/event dispatching :-(

Mmmm, I can repro it now

Just to confirm, you can reproduce it with the patch from the previous comment too?

but I don't have a lick of what to do given the IME editor is one blackbox mystery.

If I could reproduce it (but I still don't even know how to build KiCad myself and I still can't reproduce it in a wx sample), I'd start by looking at IME Windows messages in Spy++ or equivalent tool. If this doesn't help, I'd also put a conditional breakpoint on the code dispatching the message when the message is WM_KEYDOWN and check whether it's getting dispatched at all and, if so, what happens to it.

But I don't know much about IME myself neither, unfortunately...

marekr commented 11 months ago

Well, I just found new behavior. It appears only Keyboard and mouse messages get completely dropped from being received by the application.

apimonitor-x64_JYqkPeBwGQ

Here's an exciting Gif of PeekMessages flying by with False as I try and keyboard and mouse it

But, I attached a CAD device known as a SpaceMouse. The driver for it also uses Peek/Post message but generates its own message IDs

image

Using the SpaceMouse I can still interact with the PCB Editor, so this has something to do with the more stock window events purely

Unforunately, I can't apply that patch atm due to how kicad builds against wx not being very flexible for patching wx randomly. But I doubt it'll work.

marekr commented 11 months ago

If I could reproduce it (but I still don't even know how to build KiCad myself and I still can't reproduce it in a wx sample)

https://dev-docs.kicad.org/en/build/

Pick your poison if you want ^

marekr commented 11 months ago

Playing around, this is the win32 api activity that occurs before it locks up.

MSCTF.dll is part of the Microsoft Text Services Framework and involved with the IME in some form, there's also IMM32.dll.

I wonder if this has anything to do with void wxWindowMSW::SetFocusFromKbd() fighting with the IME system

image

# Time of Day Thread Module API Return Value Duration
537040 9:04:00.881 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x00000000000a0f7e, WM_GETDLGCODE, 0, 0 ) 0 0.0000102
537041 9:04:00.881 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749536752 ) 0 0.0000000
537042 9:04:00.881 PM 1 MSCTF.dll DefWindowProcW ( 0x00000000000a0f7e, WM_GETDLGCODE, 0, 0 ) 0 0.0000002
537043 9:04:00.881 PM 1 wxmsw32ud_core_vc_custom.dll GetWindow ( 0x00000000000a0f7e, GW_OWNER ) 0x000000000006116a 0.0000004
537044 9:04:00.881 PM 1 wxmsw32ud_core_vc_custom.dll GetWindowLongW ( 0x00000000000a0f7e, GWL_STYLE ) -1946157056 0.0000001
537045 9:04:00.881 PM 1 wxmsw32ud_core_vc_custom.dll IsDialogMessageW ( 0x00000000000a0f7e, 0x00000085d1bdf7e8 ) TRUE 0.0000083
537046 9:04:00.882 PM 1 MSCTF.dll KillTimer ( 0x00000000000a0f7e, 1 ) TRUE 0.0000026
537047 9:04:00.882 PM 1 MSCTF.dll IsWindow ( NULL ) FALSE 0.0000002
537048 9:04:00.882 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf888, NULL, 0, 0, PM_NOREMOVE ) FALSE 0.0000004
537049 9:04:00.882 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x000000000004163c, CB_GETCURSEL, 0, 0 ) 0 0.0000449
537050 9:04:00.882 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749534160 ) 0 0.0000001
537051 9:04:00.882 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x000000000004163c, CB_GETCURSEL, 0, 0 ) 0 0.0000155
537052 9:04:00.882 PM 1 COMCTL32.dll SendMessageW ( 0x000000000006162e, LB_GETCURSEL, 0, 0 ) 0 0.0000148
537053 9:04:00.882 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749530496 ) 0 0.0000001
537054 9:04:00.882 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000031630, CB_GETCURSEL, 0, 0 ) 0 0.0000098
537055 9:04:00.883 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749534160 ) 0 0.0000001
537056 9:04:00.883 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000031630, CB_GETCURSEL, 0, 0 ) 0 0.0000042
537057 9:04:00.883 PM 1 COMCTL32.dll SendMessageW ( 0x0000000000031632, LB_GETCURSEL, 0, 0 ) 0 0.0000038
537058 9:04:00.883 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749530496 ) 0 0.0000000
537059 9:04:00.883 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000041634, CB_GETCURSEL, 0, 0 ) 8 0.0000090
537060 9:04:00.883 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749534048 ) 0 0.0000000
537061 9:04:00.883 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000041634, CB_GETCURSEL, 0, 0 ) 8 0.0000042
537062 9:04:00.883 PM 1 COMCTL32.dll SendMessageW ( 0x0000000000061626, LB_GETCURSEL, 0, 0 ) 8 0.0000039
537063 9:04:00.883 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749529872 ) 0 0.0000000
537064 9:04:00.883 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000041634, CB_GETCURSEL, 0, 0 ) 8 0.0000072
537065 9:04:00.883 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749534048 ) 0 0.0000000
537066 9:04:00.883 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000041634, CB_GETCURSEL, 0, 0 ) 8 0.0000035
537067 9:04:00.883 PM 1 COMCTL32.dll SendMessageW ( 0x0000000000061626, LB_GETCURSEL, 0, 0 ) 8 0.0000033
537068 9:04:00.883 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749529872 ) 0 0.0000000
537069 9:04:00.883 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000041634, CB_GETCOUNT, 0, 0 ) 22 0.0000072
537070 9:04:00.883 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533984 ) 0 0.0000000
537071 9:04:00.883 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000041634, CB_GETCOUNT, 0, 0 ) 22 0.0000035
537072 9:04:00.883 PM 1 COMCTL32.dll SendMessageW ( 0x0000000000061626, LB_GETCOUNT, 0, 0 ) 22 0.0000033
537073 9:04:00.883 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749529808 ) 0 0.0000000
537074 9:04:00.883 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000041634, CB_GETITEMDATA, 8, 0 ) 37 0.0000089
537075 9:04:00.883 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533600 ) 0 0.0000000
537076 9:04:00.883 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000041634, CB_GETITEMDATA, 8, 0 ) 37 0.0000047
537077 9:04:00.884 PM 1 COMCTL32.dll SendMessageW ( 0x0000000000061626, LB_GETITEMDATA, 8, 0 ) 37 0.0000046
537078 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749529424 ) 0 0.0000000
537079 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000031628, CB_GETCOUNT, 0, 0 ) 25 0.0000088
537080 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749534208 ) 0 0.0000000
537081 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000031628, CB_GETCOUNT, 0, 0 ) 25 0.0000039
537082 9:04:00.884 PM 1 COMCTL32.dll SendMessageW ( 0x000000000005162a, LB_GETCOUNT, 0, 0 ) 25 0.0000036
537083 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749530544 ) 0 0.0000000
537084 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000031628, CB_GETCURSEL, 0, 0 ) 4 0.0000077
537085 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749534144 ) 0 0.0000000
537086 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000031628, CB_GETCURSEL, 0, 0 ) 4 0.0000039
537087 9:04:00.884 PM 1 COMCTL32.dll SendMessageW ( 0x000000000005162a, LB_GETCURSEL, 0, 0 ) 4 0.0000037
537088 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749530480 ) 0 0.0000000
537089 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x000000000004162c, CB_GETCURSEL, 0, 0 ) 7 0.0000085
537090 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749534112 ) 0 0.0000001
537091 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x000000000004162c, CB_GETCURSEL, 0, 0 ) 7 0.0000041
537092 9:04:00.884 PM 1 COMCTL32.dll SendMessageW ( 0x000000000005161e, LB_GETCURSEL, 0, 0 ) 7 0.0000038
537093 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749530448 ) 0 0.0000000
537094 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x000000000004163c, CB_GETCURSEL, 0, 0 ) 0 0.0000083
537095 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533888 ) 0 0.0000001
537096 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x000000000004163c, CB_GETCURSEL, 0, 0 ) 0 0.0000038
537097 9:04:00.884 PM 1 COMCTL32.dll SendMessageW ( 0x000000000006162e, LB_GETCURSEL, 0, 0 ) 0 0.0000035
537098 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749530224 ) 0 0.0000000
537099 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000031630, CB_GETCURSEL, 0, 0 ) 0 0.0000084
537100 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533888 ) 0 0.0000000
537101 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000031630, CB_GETCURSEL, 0, 0 ) 0 0.0000043
537102 9:04:00.884 PM 1 COMCTL32.dll SendMessageW ( 0x0000000000031632, LB_GETCURSEL, 0, 0 ) 0 0.0000037
537103 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749530224 ) 0 0.0000001
537104 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000041634, CB_GETCURSEL, 0, 0 ) 8 0.0000080
537105 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533776 ) 0 0.0000000
537106 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000041634, CB_GETCURSEL, 0, 0 ) 8 0.0000036
537107 9:04:00.884 PM 1 COMCTL32.dll SendMessageW ( 0x0000000000061626, LB_GETCURSEL, 0, 0 ) 8 0.0000034
537108 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749529600 ) 0 0.0000000
537109 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000041634, CB_GETCURSEL, 0, 0 ) 8 0.0000075
537110 9:04:00.884 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533776 ) 0 0.0000000
537111 9:04:00.884 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000041634, CB_GETCURSEL, 0, 0 ) 8 0.0000037
537112 9:04:00.885 PM 1 COMCTL32.dll SendMessageW ( 0x0000000000061626, LB_GETCURSEL, 0, 0 ) 8 0.0000034
537113 9:04:00.885 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749529600 ) 0 0.0000000
537114 9:04:00.885 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000041634, CB_GETCOUNT, 0, 0 ) 22 0.0000075
537115 9:04:00.885 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533712 ) 0 0.0000000
537116 9:04:00.885 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000041634, CB_GETCOUNT, 0, 0 ) 22 0.0000036
537117 9:04:00.885 PM 1 COMCTL32.dll SendMessageW ( 0x0000000000061626, LB_GETCOUNT, 0, 0 ) 22 0.0000034
537118 9:04:00.885 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749529536 ) 0 0.0000000
537119 9:04:00.885 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000041634, CB_GETITEMDATA, 8, 0 ) 37 0.0000072
537120 9:04:00.885 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533328 ) 0 0.0000000
537121 9:04:00.885 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000041634, CB_GETITEMDATA, 8, 0 ) 37 0.0000036
537122 9:04:00.885 PM 1 COMCTL32.dll SendMessageW ( 0x0000000000061626, LB_GETITEMDATA, 8, 0 ) 37 0.0000035
537123 9:04:00.885 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749529152 ) 0 0.0000001
537124 9:04:00.885 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000031628, CB_GETCOUNT, 0, 0 ) 25 0.0000080
537125 9:04:00.885 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533936 ) 0 0.0000000
537126 9:04:00.885 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000031628, CB_GETCOUNT, 0, 0 ) 25 0.0000038
537127 9:04:00.885 PM 1 COMCTL32.dll SendMessageW ( 0x000000000005162a, LB_GETCOUNT, 0, 0 ) 25 0.0000035
537128 9:04:00.885 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749530272 ) 0 0.0000001
537129 9:04:00.885 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x0000000000031628, CB_GETCURSEL, 0, 0 ) 4 0.0000072
537130 9:04:00.885 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533872 ) 0 0.0000000
537131 9:04:00.885 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x0000000000031628, CB_GETCURSEL, 0, 0 ) 4 0.0000036
537132 9:04:00.885 PM 1 COMCTL32.dll SendMessageW ( 0x000000000005162a, LB_GETCURSEL, 0, 0 ) 4 0.0000034
537133 9:04:00.885 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749530208 ) 0 0.0000000
537134 9:04:00.885 PM 1 wxmsw32ud_core_vc_custom.dll SendMessageW ( 0x000000000004162c, CB_GETCURSEL, 0, 0 ) 7 0.0000078
537135 9:04:00.886 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749533840 ) 0 0.0000000
537136 9:04:00.886 PM 1 wxmsw32ud_core_vc_custom.dll CallWindowProcW ( 0x00007ff96f6bf280, 0x000000000004162c, CB_GETCURSEL, 0, 0 ) 7 0.0000036
537137 9:04:00.886 PM 1 COMCTL32.dll SendMessageW ( 0x000000000005161e, LB_GETCURSEL, 0, 0 ) 7 0.0000034
537138 9:04:00.886 PM 1 atio6axx.dll CallNextHookEx ( NULL, 0, 0, 574749530176 ) 0 0.0000000
537139 9:04:00.887 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000008
537140 9:04:03.469 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000111
537141 9:04:03.469 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000012
537142 9:04:03.470 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000058
537143 9:04:03.470 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000017
537144 9:04:03.471 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000038
537145 9:04:03.471 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000012
537146 9:04:03.472 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000032
537147 9:04:03.472 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000011
537148 9:04:03.473 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000034
537149 9:04:03.473 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000012
537150 9:04:03.474 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000031
537151 9:04:03.474 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000011
537152 9:04:03.475 PM 1 wxbase32ud_vc_custom.dll PeekMessageW ( 0x00000085d1bdf7e8, NULL, 0, 0, PM_REMOVE ) FALSE 0.0000051
marekr commented 11 months ago

Hah, this made me realize I accidentally broke a earlier change in KiCad I made. A user pointed out and complained the IME input on the canvas made zero sense and was annoying.

ImmAssociateContext( aWindow->GetHWND(), NULL ); on our canvas control seems to work and avoid getting this bug easily.

vadz commented 11 months ago

It's still not clear to me if anybody (@MunoLike?) has reproduced the problem with the patch and I don't understand why do you doubt that it'll work. I'm far from sure that it works, but I do have some hope that it does because it's my understanding that the IME doesn't leave the "waiting for something to happen" state unless we let it have this special message, and while it remains in this state it intercepts all keyboard (and apparently mouse too) events. So it seems at least plausible to me that by not passing all messages for the "unknown" windows to ::IsDialogMessage() we could prevent this from happening.

Thanks for the instructions for building KiCad, but it's not obvious to me how can I build it with a custom/patched wx version and seeing that you think it's difficult to do so makes me wonder if I'm going to be able to do it in a reasonable amount of time... Does anybody know if vcpkg be convinced to use a locally built version somehow?

Finally, disabling IME completely by calling ImmAssociateContext() might well avoid the problem, but at the cost of preventing people who need IME from using it, which doesn't look great neither.

marekr commented 11 months ago

Finally, disabling IME completely by calling ImmAssociateContext() might well avoid the problem, but at the cost of preventing people who need IME from using it, which doesn't look great neither.

Ah I was only remarking on the fact that the problem is exacerbated on KiCad because I intended to disable the IME on the canvas because the canvas is meant to accept keycodes only for hotkeys, users have to constantly toggle the IME off to use hotkeys. They can still use the IME on all the real text inputs.

Does anybody know if vcpkg be convinced to use a locally built version somehow?

KiCad would have to be switched to non-manifest mode vcpkg as per the kicad build instructions at the bottom. In non-manifest mode you can then build wxwidgets using --editable mode.

Anyway, I've only being lazy since well I'm very spread out trying to handle a few things at the same time in kicad so I'll try and patch it tonight.

My understanding btw, is IsDialogMessage does dispatch the message which is why I have my doubts.

vadz commented 11 months ago

My understanding btw, is IsDialogMessage does dispatch the message which is why I have my doubts.

Maybe you're right because I still have no idea what does it do exactly (if you search for comments about it in wxMSW sources, you can find quite a few traces of my struggles with it since 25+ years...), but I'm pretty sure that it's buggy or at least only works correctly in very controlled conditions, so I wouldn't be surprised at all if it dropped this message just because it doesn't expect it.

Anyhow, thanks in advance for testing this!

marekr commented 11 months ago

I applied the patch, it still locks up.

I can confirm the behavior of the 0x0060 special case is running too, so it just doesn't fix anything here heh

image

image

vadz commented 11 months ago

Oh well. Sorry for insisting on testing this, I really hoped it would work.

marekr commented 11 months ago

The only other observation I have made is that if i hit any keyboard key while the pcbnew (pcb editor) window is still loading (so the window has shown but it's still mostly the control background color), it will then finish loading/painting the window to the expected view and then be locked up to keyboard/mouse input.

Theorycrafting in the air, I think it's the Windows IME breaking down internally and somehow consuming all keyboard/mouse input to itself in a failed state. KiCad does attempt to suck-in every key press coming in as possible because we are trying to detect hot-keys. We do it by aggressively setting focus on our canvas when possible to take in those key events. I wonder if there's some out of order events where by pressing a key, the IME started to process the key events but kicad proceeds to steal focus and consume the key instead and the end result is the IME process is now stuck because it lacks any timeout/recovery logic.

vadz commented 9 months ago

Always an optimist, I've created #23824 which avoids calling IsDialogMessage() for unknown windows -- not only for the mysterious 0x0060 message, but for all of them.

I'm more than ready to believe that this doesn't fix this bug neither (I'm not much of an optimist...), but it just might help, so if you could please test this PR (or master when it's merged into it, as I think it's worth merging anyhow), it would be appreciated. Thanks again!

MunoLike commented 9 months ago

I tested above PR for KiCAD 7.0.7, but sadly it's still freeze when I start kicad's pcbnew and mash a button like m key.

vadz commented 9 months ago

Oh well. Thanks for testing!

Unfortunately I'm all out of ideas again now. I thought about our keyboard hook, but even if we do something wrong there, it can't explain the fact that mouse events are not shown neither.

konstantinbo commented 9 months ago

I just stumbled upon this problem when using wxPython 4.1.2 and got it reproduced in the following minimal example:

import wx

class MainFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, wx.ID_ANY, "wxPython Dialog Example", size=(400, 300))
        self.Bind(wx.EVT_CHAR_HOOK, self.on_char_hook)

        self.panel = wx.Panel(self)
        self.panel.Bind(wx.EVT_CHAR_HOOK, self.on_char_hook)

        self.dialog = None
        self.textctrl_dialog = None

    def on_char_hook(self, event):
        keycode = event.GetKeyCode()
        if event.ControlDown() and keycode == wx.WXK_SPACE:
            self.show_empty_dialog()

        event.Skip()

    def show_empty_dialog(self):
        self.dialog = wx.Dialog(self, title="Empty Dialog")
        self.dialog.Bind(wx.EVT_CHAR_HOOK, self.on_empty_dialog_char_hook)

        self.dialog.ShowModal()

    def on_empty_dialog_char_hook(self, event):
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_RETURN or keycode == wx.WXK_NUMPAD_ENTER:
            wx.CallAfter(self.show_textctrl_dialog)
            self.dialog.Close()

        # Skipping the KeyEvent prevents the freeze
        # event.Skip()

    def show_textctrl_dialog(self):
        self.textctrl_dialog = wx.Dialog(self, title="TextCtrl Dialog")
        text_ctrl = wx.TextCtrl(self.textctrl_dialog, wx.ID_ANY, "", style=wx.TE_MULTILINE)
        ok_button = wx.Button(self.textctrl_dialog, wx.ID_OK, "OK")
        cancel_button = wx.Button(self.textctrl_dialog, wx.ID_CANCEL, "Cancel")

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(text_ctrl, 1, wx.EXPAND | wx.ALL, 10)
        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
        btn_sizer.Add(ok_button, 0, wx.ALL, 10)
        btn_sizer.Add(cancel_button, 0, wx.ALL, 10)
        sizer.Add(btn_sizer, 0, wx.ALIGN_RIGHT)

        self.textctrl_dialog.SetSizer(sizer)

        if self.textctrl_dialog.ShowModal() == wx.ID_OK:
            text = text_ctrl.GetValue()
            print("Entered Text:", text)

        self.textctrl_dialog.Destroy()

if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    frame.Show()
    app.MainLoop()

So the chain of events is:

  1. Select e.g. Japanese Keyboard in Windows Settings
  2. Start the script
  3. Press Ctrl+Space - a modal dialog pops up
  4. Press Enter - the modal dialog closes and another modal dialog with a TextCtrl pops up instead.
  5. Neither the TextCtrl nor the Ok/Cancel Buttons can be interacted with. Task Manager doesn't report the application as "not responding"

The most interesting part appears to be the wx.CallAfter call in on_empty_dialog_char_hook() in combination with the missing event.Skip. By using the workaround with the IME compatibility mode (Microsoft: Revert to a previous version of an IME ), the problem disappears indeed.

vadz commented 8 months ago

Thanks, I can indeed reproduce the problem 100% reliably with this example. Here is my (free, notably I've changed Ctrl+Space to F5 because the former is used by the Chinese IME and we never get it when it's active) translation of it to C++ for reference.

C++ test case ```cpp #include "wx/app.h" #include "wx/dialog.h" #include "wx/frame.h" #include "wx/textdlg.h" struct MyFrame : wxFrame { MyFrame() { Create(nullptr, wxID_ABOUT, "wx IME test frame", wxDefaultPosition, wxSize(400, 300)); Bind(wxEVT_CHAR_HOOK, &MyFrame::on_char_hook, this); auto p = new wxPanel(this); p->Bind(wxEVT_CHAR_HOOK, &MyFrame::on_char_hook, this); Show(); } void on_char_hook(wxKeyEvent& event) { if ( event.GetKeyCode() == WXK_F5 ) show_empty_dialog(); event.Skip(); } void show_empty_dialog() { m_dialog = new wxDialog(this, wxID_ABOUT, "Empty Dialog"); m_dialog->Bind(wxEVT_CHAR_HOOK, &MyFrame::on_empty_dialog_char_hook, this); m_dialog->ShowModal(); m_dialog->Destroy(); } void on_empty_dialog_char_hook(wxKeyEvent& event) { auto keycode = event.GetKeyCode(); if ( keycode == WXK_RETURN || keycode == WXK_NUMPAD_ENTER ) { CallAfter([this]() { show_textctrl_dialog(); }); m_dialog->Close(); } // Skipping the KeyEvent prevents the freeze //event.Skip(); } void show_textctrl_dialog() { wxGetTextFromUser("Text:", "TextCtrl Dialog", {}, this); } wxDialog* m_dialog = nullptr; }; struct MyApp : wxApp { bool OnInit() override { new MyFrame(); return true; } }; wxIMPLEMENT_APP(MyApp); ```

So now should be able to debug this, but the immediate question is whether there are any wxEVT_CHAR_HOOK handlers in KiCad code that don't skip the event because it's reasonable to expect that doing this would break IME. So maybe the fix is as simple as adding a missing event.Skip()?

Looking at KiCad sources, there are quite a few of wxEVT_CHAR_HOOK handlers, but a simple way to check if any of them forgets to call Skip() (or DoAllowNextEvent()) is to run the program and put a breakpoint on the return here:

https://github.com/wxWidgets/wxWidgets/blob/e570d85164af9a2bb1bf6ebb9a061cda97f1ae56/src/msw/window.cpp#L7182-L7186

Could you please check if it is hit in your case and, if so, if skipping the event fixes the problem?

reitowo commented 3 months ago

Seems exactly same problem with Chromium and all Chromium based apps (CEF, Electron)

Anyone interested? https://issues.chromium.org/issues/328859185

vadz commented 3 months ago

Not sure what do you mean by "interested": I'd very much like to fix this bug, of course, but I still have no idea how to do it, unfortunately, and seeing a similar bug in Chromium doesn't really change anything.

reitowo commented 3 months ago

I debugged it for a long time. The only suspicious thing I found is, when the DPI changed, the TSF will call GetStatus and RequestLock, and it might make it run into a bad state.

I can only create a workaround for this, re-initializing the IME and TSF bridge everytime it gets a focus

https://chromium-review.googlesource.com/c/chromium/src/+/5365680

vadz commented 3 months ago

Interesting, thanks! But at least in our case the bug can be reproduced without changing DPI, so it looks like it's due to something else.

We also can't try your workaround easily, as we have no equivalent of TSFBridge, unfortunately...

reitowo commented 3 months ago

Interesting, thanks! But at least in our case the bug can be reproduced without changing DPI, so it looks like it's due to something else.

We also can't try your workaround easily, as we have no equivalent of TSFBridge, unfortunately...

So, it must have some other path to trigger the tsf or the ime into a bad state.

I'm not familiar with wxWidget, how does it integrate with TSF? Maybe you can try to shutdown the same thing here, like a ITfThreadMgr or something created like here https://source.chromium.org/chromium/chromium/src/+/main:ui/base/ime/win/tsf_bridge.cc

reitowo commented 3 months ago

I went through the chatting history again, and find out it seems the wxWidget seems using Imm32 and doesn't involve TSF at all?

vadz commented 3 months ago

No, we don't have any real IME support and don't use TSF explicitly at all (I don't know if it's still being used under the hood?). The idea always was that native controls, such as wxTextCtrl, should work correctly without doing anything special.

reitowo commented 3 months ago

Ah, so the actual code is src/msw/textctrl.cpp? It seems rather historical and directly use the native control. So, might be a new windows internal bug, just have same apperance of eating inpit events.

vadz commented 3 months ago

It seems rather historical and directly use the native control.

Yes, wxWidgets is all about wrapping native controls.

So, might be a new windows internal bug, just have same apperance of eating inpit events.

Right, so it would be really great to find some workaround for this bug. As the reproducer in the comment above shows, it's related to not letting the native control (and hence IMM32, I guess) have all keyboard events, but I still don't know how exactly nor how to work around it.

marekr commented 1 month ago

Looking at KiCad sources, there are quite a few of wxEVT_CHAR_HOOK handlers, but a simple way to check if any of them forgets to call Skip() (or DoAllowNextEvent()) is to run the program and put a breakpoint on the return here:

I've been staring at this but I just can't find anywhere it doesn't get skipped. I even remove all the wxEVT_CHAR and wxEVT_CHAR_HOOK and can still get the lock up :/

vadz commented 1 month ago

I can reproduce the issue relatively reliably with the example from this comment but not without the EVT_CHAR hooks handlers or even if I uncomment the marked line there. Do you still see the problem with that line uncommented?

Also, have you tried putting the breakpoint as written there? If you see the issue without any EVT_CHAR handlers at all, it shouldn't be triggered, but maybe there is a forgotten/hidden one remaining somewhere...

Sorry, no other ideas for now :-(

marekr commented 1 month ago

I haven't tried the sample yet. I just did the logical thing of Ctrl-F for CHAR_HOOK and CHAR and deleting all the Connect/Binds.

The way I've found to reproduce it reliably in kicad is in debug, which slows things down, I switch to Chinese and I go to load a PCB from the main window, this triggers a wxProgressDialog we update with status, I spam the "M" key on this dialog and so when it finishes loading and a new frame opens, that frame/the entire application are now frozen.

Edit: Generally that's how I've always managed to trigger it even in other spots. i.e. spamming keys while opening a new dialog.

I will need to somehow instrument wxWidgets with a metric ton of logging on everything relating to messaging in the event loop....one of these days....

vadz commented 1 month ago

The dialogs sample has a progress dialog (and it can be shown on startup if you use --progress=<style> option, which is handy when running it multiple times in a row), can you reproduce it there?

vadz commented 1 month ago

I will need to somehow instrument wxWidgets with a metric ton of logging on everything relating to messaging in the event loop....one of these days....

Oh, forgot to answer this: this already exists, at least partially, but you need to set wxDEBUG_LEVEL to 2 when building and then set WXTRACE environment variable to include "winmsg" when running to enable it, as it has quite noticeable overhead.

P.S. Or you could just use Spy++ to monitor all messages too.

marekr commented 2 weeks ago

Playing around because it was noted by another dev that QT had a workaround of sorts https://gitlab.com/kicad/code/kicad/-/issues/9882#note_1887837589

I tried a hackfix in one large canvas control that causes problems for us, I instruct it to reset the ime composition anytime SetFocus is called, and it seems to fix to prevent it from reproing. However the issue occurs with other wx controls of course so I'll need to try patching this inside wxWidgets.

void KIPLATFORM::UI::ImeNotifyCancelComposition( wxWindow* aWindow )
{
    const HIMC himc = ImmGetContext( aWindow->GetHWND() );
    ImmNotifyIME( himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0 );
    ImmReleaseContext( aWindow->GetHWND(), himc );
}

void EDA_DRAW_PANEL_GAL::SetFocus()
{
    KIPLATFORM::UI::ImeNotifyCancelComposition( this );
}

I still need test it with the repro cases here.