<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[C# Windows Forms tab navigation broken when form registered with NPPM_MODELESSDIALOG]]></title><description><![CDATA[<p dir="auto">Since the changes in Npp 8.6.1 that changed Ctrl+X and Ctrl+C into menu commands, I’ve been trying to figure out a decent solution that makes Ctrl+C and Ctrl+X work again in my C# plugins.</p>
<p dir="auto">The “correct” solution to this problem is to register and unregister each of my forms with <code>NPPM_MODELESSDIALOG</code>, and I understand how to do this. Doing so does indeed restore the functionality of Ctrl+C and Ctrl+X in Npp 8.6.1 and 8.6.2, but it also causes tab navigation to break, which is …unexpected.</p>
<p dir="auto">To be brief, in C# Windows Forms, controls have a <code>TabIndex</code> property that controls their position in the tab order. It is my understanding that things work differently in C++ (like I think you can choose either a top-to-bottom-then-left-to-right or left-to-right-then-top-to-bottom algorithm?), and I would be willing to use NPPM_MODELESSDIALOG if the new order of tab navigation made any sense at all, but it really doesn’t. I will show a diagram of the before and after for one of my forms (it’s a representative example; all my forms get messed up like this).</p>
<p dir="auto"><strong>This is the order of the controls by tab index</strong> (I chose a left-to-right-then-top-to-bottom order, more or less)</p>
<p dir="auto"><img src="/assets/uploads/files/1707079769371-3af4a543-0ee5-408e-ac87-1bb0c1af6b7c-image.png" alt="3af4a543-0ee5-408e-ac87-1bb0c1af6b7c-image.png" class=" img-fluid img-markdown" /></p>
<p dir="auto"><strong>And this is the order that I get when I register my form with <code>NPPM_MODELESSDIALOG</code></strong>:<br />
<img src="/assets/uploads/files/1707079821160-876893bf-bc3c-4226-ab14-e1dd776541d2-image.png" alt="876893bf-bc3c-4226-ab14-e1dd776541d2-image.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">Do you see a pattern in the second one? Because I sure don’t. And before you ask, the weird order you see there is not the order in which the controls are declared or initialized, as far as I can tell.</p>
<p dir="auto">My current thinking (very vague and speculative and most likely wrong somehow, because I’m not really experienced with C++) is that <a href="https://github.com/notepad-plus-plus/notepad-plus-plus/blob/5e6df259423680f82e98e42af31c996690a06e26/PowerEditor/src/winmain.cpp#L722" rel="nofollow ugc">in winmain.cpp in the message loop</a> there’s a call to <code>TranslateMessage</code> and <code>DispatchMessageW</code> after an earlier call (<a href="https://github.com/notepad-plus-plus/notepad-plus-plus/blob/5e6df259423680f82e98e42af31c996690a06e26/PowerEditor/src/Notepad_plus_Window.cpp#L423" rel="nofollow ugc">in <code>Notepad_plus_Window::isDlgsMsg</code></a>) to <code>IsDialogMessageW</code>, but the <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-isdialogmessagew" rel="nofollow ugc">standard documentation for <code>IsDialogMessageW</code></a> specifically says that:</p>
<pre><code class="language-txt">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.
</code></pre>
]]></description><link>https://community.notepad-plus-plus.org/topic/25449/c-windows-forms-tab-navigation-broken-when-form-registered-with-nppm_modelessdialog</link><generator>RSS for Node</generator><lastBuildDate>Thu, 21 May 2026 04:07:10 GMT</lastBuildDate><atom:link href="https://community.notepad-plus-plus.org/topic/25449.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 04 Feb 2024 20:58:35 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to C# Windows Forms tab navigation broken when form registered with NPPM_MODELESSDIALOG on Tue, 06 Feb 2024 01:36:15 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/coises" aria-label="Profile: Coises">@<bdi>Coises</bdi></a><br />
<a class="plugin-mentions-user plugin-mentions-a" href="/user/rdipardo" aria-label="Profile: rdipardo">@<bdi>rdipardo</bdi></a></p>
<p dir="auto">Thank you both for your suggestions! I meant to respond sooner, but there was a power outage.</p>
<p dir="auto">In any case, Coises’ original suggestion worked! Thank you so much! I already knew that I had to disable <code>GenericTabNavigationHandler</code>, so all I did was go into the <code>Designer.cs</code> files for all of my forms and rearrange the order in which they were added to their parent and it just worked.</p>
<p dir="auto">Hand-editing <code>Designer.cs</code> files is kind of a no-no, because they’re automatically generated by Visual Studio when you edit a form in the designer, but I’ll happily take this solution over whatever lousy alternative I was going to use.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/92697</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/92697</guid><dc:creator><![CDATA[Mark Olson]]></dc:creator><pubDate>Tue, 06 Feb 2024 01:36:15 GMT</pubDate></item><item><title><![CDATA[Reply to C# Windows Forms tab navigation broken when form registered with NPPM_MODELESSDIALOG on Mon, 05 Feb 2024 18:39:50 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/rdipardo" aria-label="Profile: rdipardo">@<bdi>rdipardo</bdi></a> said in <a href="/post/92633">C# Windows Forms tab navigation broken when form registered with NPPM_MODELESSDIALOG</a>:</p>
<blockquote>
<p dir="auto">As for why NPPM_MODELESSDIALOG appears to change the component hierarchy, it could be another case of the WS_EX_CONTROLPARENT flag needing to be set on the parent form’s window attributes to make the OS aware that it is, in fact, a parent control.</p>
</blockquote>
<p dir="auto">Based on <a class="plugin-mentions-user plugin-mentions-a" href="/user/mark-olson" aria-label="Profile: Mark-Olson">@<bdi>Mark-Olson</bdi></a>’s second image, nothing is being changed; it’s exactly the order in which components are added <a href="https://github.com/molsonkiko/JsonToolsNppPlugin/blob/929188b0b9cfd9231ea6a2323921ba026a371786/JsonToolsNppPlugin/Forms/FindReplaceForm.Designer.cs#L284" rel="nofollow ugc">here</a> and <a href="https://github.com/molsonkiko/JsonToolsNppPlugin/blob/929188b0b9cfd9231ea6a2323921ba026a371786/JsonToolsNppPlugin/Forms/FindReplaceForm.Designer.cs#L219" rel="nofollow ugc">here</a>.</p>
<p dir="auto">I don’t even know how to set up a C# project, but by analogy to what I would say for a C++ project: has anyone tried making the order in which controls are added in FindReplaceForm.Designer.cs reflect the intended tab order, then letting the default dialog procedure (or whatever is the C# equivalent of that) handle navigation and not interfering by using keyboard event handlers? (Perhaps the keyboard event handlers were added in the first place <em>because</em> <a href="https://devblogs.microsoft.com/oldnewthing/20120416-00/?p=7853" rel="nofollow ugc">navigation in a non-modal dialog doesn’t work normally unless the message loop calls IsDialogMessage</a>, which for a Notepad++ plugin requires using NPPM_MODELESSDIALOG.)</p>
]]></description><link>https://community.notepad-plus-plus.org/post/92664</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/92664</guid><dc:creator><![CDATA[Coises]]></dc:creator><pubDate>Mon, 05 Feb 2024 18:39:50 GMT</pubDate></item><item><title><![CDATA[Reply to C# Windows Forms tab navigation broken when form registered with NPPM_MODELESSDIALOG on Mon, 05 Feb 2024 17:41:05 GMT]]></title><description><![CDATA[<p dir="auto">After a closer look there seems to be more going on here.</p>
<p dir="auto">Without NPPM_MODELESSDIALOG, every control on the form receives its own key events. When a <code>TextBox</code> has focus, the sender object passed to <code>GenericTabNavigationHandler</code> is that <code>TextBox</code>, and the next tab stop is relative to that <code>TextBox</code>, and so on for every focusable control.</p>
<p dir="auto">The <a href="https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.keypress?view=netframework-4.8.1#remarks" rel="nofollow ugc">normal sequence</a> of a key event should be WM_KEYDOWN (handled by .NET’s <code>KeyDown</code>) -&gt; WM_CHAR (i.e. <code>KeyPress</code>) -&gt; WM_KEYUP (i.e. <code>KeyUP</code>), but that assumes the receiver is some kind of edit control. An instance of <code>Form</code> doesn’t know about a key event until a child component broadcasts its own WM_KEYUP message to its parent; I don’t know how or if a parent can stop a child from processing it.</p>
<p dir="auto">After sending NPPM_MODELESSDIALOG, only the main form instance receives messages, and it’s only receptive to WM_KEYUP, so while the .NET <code>KeyUp</code> handler still works, all the others are dormant. Since the only events are coming from the main form, the next tab stop is always relative to it. There’s a loop in <code>GenericTabNavigationHandler</code> that will find a valid component in any case, but what it lands on will have nothing in common with the design-time tab order. You can even block the <code>KeyUp</code> handler’s code path, and focus will still jump around, suggesting some controls are silently processing tab keys.</p>
<p dir="auto">To see for yourself, first use the <code>System.Diagnostics</code> namespace and set up debug logging inside a static constructor, e.g.,</p>
<pre><code class="language-cs">static FindReplaceForm()
{
    Debug.Listeners.Add(new TextWriterTraceListener(System.Console.Out));
    Debug.AutoFlush = true;
}
</code></pre>
<p dir="auto">Then override <a href="https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.processkeypreview" rel="nofollow ugc"><code>ProcessKeyPreview</code></a>, like this:</p>
<pre><code class="language-cs">protected override bool ProcessKeyPreview(ref Message msg)
{
  var keyCode = (Keys)(byte)msg.WParam;
  switch (msg.Msg)
  {
    case /*WM_KEYDOWN*/ 0x100:
      Debug.WriteLine("WM_KEYDOWN");
      break;
    case /*WM_KEYUP*/ 0x101:
      Debug.WriteLine("WM_KEYUP");
      if (keyCode == Keys.Tab)
      {
        Debug.WriteLine("Handling TAB . . .");
        // 1. send NPPM_MODELESSDIALOG, and:
        //     a. WM_KEYUP is the only message ever received
        //     b. TAB still moves focus around the form despite returning `true` here
        // 2. don't send NPPM_MODELESSDIALOG, and:
        //     a. we receive all of WM_KEYDOWN, WM_CHAR (handled by KeyPress), and WM_KEYUP, in that order
        //     b. all key processing ends here if we return `true`
        return true;
      }
      break;
    case /*WM_CHAR*/ 0x102:
      Debug.WriteLine("WM_CHAR");
      break;
    case /*WM_SYSKEYDOWN*/ 0x104:
      Debug.WriteLine("WM_SYSKEYDOWN");
      break;
    case /*WM_SYSKEYUP*/ 0x105:
      Debug.WriteLine("WM_SYSKEYUP");
      break;
    default:
      break;
  }
  return base.ProcessKeyPreview(ref msg);
}
</code></pre>
]]></description><link>https://community.notepad-plus-plus.org/post/92662</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/92662</guid><dc:creator><![CDATA[rdipardo]]></dc:creator><pubDate>Mon, 05 Feb 2024 17:41:05 GMT</pubDate></item><item><title><![CDATA[Reply to C# Windows Forms tab navigation broken when form registered with NPPM_MODELESSDIALOG on Mon, 05 Feb 2024 04:19:50 GMT]]></title><description><![CDATA[<p dir="auto">Had a quick look and the issue seems to be the <code>KeyUp</code> handler, specifically <a href="https://github.com/molsonkiko/JsonToolsNppPlugin/blob/929188b0b9cfd9231ea6a2323921ba026a371786/JsonToolsNppPlugin/Forms/NppFormHelper.cs#L36" rel="nofollow ugc">the <code>GenericTabNavigationHandler</code> method</a> which it calls in response to a <code>TAB</code>.</p>
<p dir="auto">When you register the form by sending <code>NPPM_MODELESSDIALOG</code>, the return value of <code>form.GetNextControl()</code> is a reference to the form itself, and the “next” control to get focus is the “Replace all” button.</p>
<p dir="auto">When it’s not registered, <code>form.GetNextControl()</code> returns a reference to the form’s next child component, currently the “Swap” button, and so on, as illustrated in the first screen capture above.</p>
<p dir="auto">You could maybe try iterating the form’s <code>Controls</code> collection instead of depending on tab order, as suggested by <a href="https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.getnextcontrol#remarks" rel="nofollow ugc">the docs</a>.</p>
<p dir="auto">As for why <code>NPPM_MODELESSDIALOG</code> appears to change the component hierarchy, it could be <a href="https://community.notepad-plus-plus.org/post/92268">another case</a> of the <code>WS_EX_CONTROLPARENT</code> flag needing to be set on the parent form’s window attributes to make the OS aware that it is, in fact, a parent control.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/92633</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/92633</guid><dc:creator><![CDATA[rdipardo]]></dc:creator><pubDate>Mon, 05 Feb 2024 04:19:50 GMT</pubDate></item><item><title><![CDATA[Reply to C# Windows Forms tab navigation broken when form registered with NPPM_MODELESSDIALOG on Mon, 05 Feb 2024 00:03:13 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/mark-olson" aria-label="Profile: Mark-Olson">@<bdi>Mark-Olson</bdi></a> said in <a href="/post/92623">C# Windows Forms tab navigation broken when form registered with NPPM_MODELESSDIALOG</a>:</p>
<blockquote>
<p dir="auto">Do you see a pattern in the second one?</p>
</blockquote>
<p dir="auto">Looks like the order here:</p>
<p dir="auto"><a href="https://github.com/molsonkiko/JsonToolsNppPlugin/blob/929188b0b9cfd9231ea6a2323921ba026a371786/JsonToolsNppPlugin/Forms/FindReplaceForm.Designer.cs#L284" rel="nofollow ugc">https://github.com/molsonkiko/JsonToolsNppPlugin/blob/929188b0b9cfd9231ea6a2323921ba026a371786/JsonToolsNppPlugin/Forms/FindReplaceForm.Designer.cs#L284</a><br />
and here:<br />
<a href="https://github.com/molsonkiko/JsonToolsNppPlugin/blob/929188b0b9cfd9231ea6a2323921ba026a371786/JsonToolsNppPlugin/Forms/FindReplaceForm.Designer.cs#L219" rel="nofollow ugc">https://github.com/molsonkiko/JsonToolsNppPlugin/blob/929188b0b9cfd9231ea6a2323921ba026a371786/JsonToolsNppPlugin/Forms/FindReplaceForm.Designer.cs#L219</a></p>
<p dir="auto">considering that you start with focus on FindTextBox, loop, and “call into” the second set of adds when you hit AdvancedGroupBox.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/92628</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/92628</guid><dc:creator><![CDATA[Coises]]></dc:creator><pubDate>Mon, 05 Feb 2024 00:03:13 GMT</pubDate></item><item><title><![CDATA[Reply to C# Windows Forms tab navigation broken when form registered with NPPM_MODELESSDIALOG on Sun, 04 Feb 2024 23:40:36 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/mark-olson" aria-label="Profile: Mark-Olson">@<bdi>Mark-Olson</bdi></a> said in <a href="/post/92623">C# Windows Forms tab navigation broken when form registered with NPPM_MODELESSDIALOG</a>:</p>
<blockquote>
<p dir="auto">To be brief, in C# Windows Forms, controls have a <code>TabIndex</code> property that controls their position in the tab order. It is my understanding that things work differently in C++</p>
</blockquote>
<p dir="auto">Not really. There is a tab order; when building a dialog using the resource editor in Visual Studio, you can set the order to be any sequence you like. What that does is control the order in which the controls are defined in the resource file (which is compiled to produce, among other things, dialog templates), which determines the tab order.</p>
<blockquote>
<p dir="auto">My current thinking (very vague and speculative and most likely wrong somehow, because I’m not really experienced with C++) is that <a href="https://github.com/notepad-plus-plus/notepad-plus-plus/blob/5e6df259423680f82e98e42af31c996690a06e26/PowerEditor/src/winmain.cpp#L722" rel="nofollow ugc">in winmain.cpp in the message loop</a> there’s a call to <code>TranslateMessage</code> and <code>DispatchMessageW</code> after an earlier call (<a href="https://github.com/notepad-plus-plus/notepad-plus-plus/blob/5e6df259423680f82e98e42af31c996690a06e26/PowerEditor/src/Notepad_plus_Window.cpp#L423" rel="nofollow ugc">in <code>Notepad_plus_Window::isDlgsMsg</code></a>) to <code>IsDialogMessageW</code>, but the <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-isdialogmessagew" rel="nofollow ugc">standard documentation for <code>IsDialogMessageW</code></a> specifically says that:</p>
<pre><code class="language-txt">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.
</code></pre>
</blockquote>
<p dir="auto">The further processing only happens <a href="https://github.com/notepad-plus-plus/notepad-plus-plus/blob/5e6df259423680f82e98e42af31c996690a06e26/PowerEditor/src/winmain.cpp#L718" rel="nofollow ugc">when IsDlgsMsg returns false</a>; when IsDialogMessageW returns true, so does IsDlgsMsg.</p>
<p dir="auto">It’s not clear to me what could cause this sort of behavior, but I don’t know C# and don’t how it integrates with “plain old Windows.” I noticed that your modal dialog “JSON to CSV” has some odd tabbing behavior — it appears to tab once on key down or repeat and again on key up — and as a modal dialog, it is unaffected by the Notepad++ message loop. Just a long shot: perhaps whatever is causing that odd behavior is somehow related to the unexpected behavior in non-modal dialogs.</p>
]]></description><link>https://community.notepad-plus-plus.org/post/92627</link><guid isPermaLink="true">https://community.notepad-plus-plus.org/post/92627</guid><dc:creator><![CDATA[Coises]]></dc:creator><pubDate>Sun, 04 Feb 2024 23:40:36 GMT</pubDate></item></channel></rss>