The attached patch attempts to add support for mouse buttons 4 and 5 to Tk for Windows. (These buttons are called XButton1 and XButton2 in the Windows API documentation.) Currently, Tk programs on Windows do not detect these buttons at all, even with <code>&lt;ButtonPress&gt;</code>. I believe that these buttons, if not repurposed by the user, should be available to Tk programs, as they currently are on Aqua (as buttons 4 and 5) and X11 (as buttons 8 and 9). One common binding for these buttons is for back/forward navigation in browsers.

I am not sure to what extent this functionality has been requested in the past, or whether any efforts were made to implement support for them (either in Tk or extensions). I found one discussion from 2011 on comp.lang.tcl: The non-functionality of buttons 4 and 5 on Windows was more recently mentioned in discussions regarding TIP #474.


I believe support for these buttons can be added to 8.6, and not have to wait for 8.7. There is indeed a likelihood that existing programs bind to buttons 4 and 5 to allow scrolling on X11, yet fail to restrict those bindings to when <code>[tk windowingsystem]</code> is <code>"x11"</code>; however, those programs already exhibit this issue on Aqua. (<strike>I informed the author of TIP #474 that their existing implementation would exhibit this issue.</strike> <b>Edit:</b> maybe it doesn't affect Windows…)


There is one detail in the implementation I am not very certain of: whether <code>wparam</code> should only be assigned <code>MK_XBUTTON1</code> or <code>MK_XBUTTON2</code>, rather than <code>MAKEWPARAM(MK_XBUTTON1, XBUTTON1)</code> or <code>MAKEWPARAM(MK_XBUTTON2, XBUTTON2)</code>, in the following:
<pre>
@@ -1783,6 +1787,14 @@ TkWinResendEvent(
        msg = WM_RBUTTONDOWN;
        wparam = MK_RBUTTON;
        break;
+    case Button4:
+       msg = WM_XBUTTONDOWN;
+       wparam = MAKEWPARAM(MK_XBUTTON1, XBUTTON1);
+       break;
+    case Button5:
+       msg = WM_XBUTTONDOWN;
+       wparam = MAKEWPARAM(MK_XBUTTON2, XBUTTON2);
+       break;
     default:
        return 0;
     }
</pre>

I do not know exactly what <code>TkWinResendEvent()</code> is used for, but I imagine that the way I have written this allows whatever processing the event to check which button is pressed from <code>HIWORD(wparam)</code> (e.g. using the <code>GET_XBUTTON_WPARAM(wparam)</code> macro), rather than only by checking for <code>MK_XBUTTON1</code> or <code>MK_XBUTTON2</code>.


One script for manually testing this:

<pre>
package require Tk

label .l -text "Click here" -height 10 -width 30
pack .l
bind .l <4> {puts "Button 4 clicked"}
bind .l <5> {puts "Button 5 clicked"}
</pre>

To test this without an actual 5-button mouse, a tool to emulate the button presses can be used, such as AutoHotKey with a script that maps keypresses to buttons 4 and 5:

<pre>
F6::XButton1

F7::XButton2
</pre>

I have successfully tested this implementation on Windows 10 1903 x64, based on top of recent core-8-6-branch [3e5c0ebb].

<blockquote> I'm a bit unsure about the impact of this improvement on TIP #474, which in its implementation (in the generic code, see [77c390bae2700c72]) turns button-4 and button-5 into a &lt;MouseWheel&gt; event.</blockquote>

Here's the thread with my feedback to the author of TIP #474, for reference:

The issue that I predicted, and observed on Aqua when trying the TIP #474 implementation, was that &lt;4&gt; and &lt;5&gt; would be converted to &lt;MouseWheel&gt;, and no longer seen as &lt;4&gt; or &lt;5&gt; by the program. Essentially, clicking the extra buttons would become equivalent to rotating the scrollwheel by one or more notches on non-X11. I strongly suspected this issue also applied to Windows, but had not confirmed it; and I wasn't yet aware that I wouldn't be able to confirm it, due to support for buttons 4 and 5 not even being implemented on Windows.

However, after properly trying both my patch and the TIP #474 implementation simultaneously, I <b>don't</b> observe the issue on Windows, as I had on Aqua; the program still sees &lt;4&gt; and &lt;5&gt; instead of &lt;MouseWheel&gt;. I guess the Windows code never gets to the part of <code>UpdateButtonEventState()</code> affected by TIP #474. But it's still probably clearer/safer to make sure that any &lt;4&gt; or &lt;5&gt; usage in generic code checks that the windowingsystem is X11 if those buttons are being used for scrolling.