|
Description
|
Pressing mouse buttons in a certain way on java.awt.Buttons can cause two ActionEvents to be fired, instead of just one. Consider this simple test case:
// Test of double ActionEvents
import java.awt.*;
import java.awt.event.*;
public class ActionTest extends Frame implements ActionListener {
Button b;
public ActionTest() {
super("ActionTest");
b = new Button("Action Listening Button");
b.addActionListener(this);
add(b);
setSize(200, 200);
}
static int i = 0;
public void actionPerformed(ActionEvent e) {
System.out.println("actionPerformed() called - " + (i++));
}
public static void main(String[] args) {
ActionTest at = new ActionTest();
at.show();
}
}
---
Press both the left and right mouse buttons while over the Action Listening Button. Next, release the left mouse button. You will see that actionPerformed() is called twice. This is a regression since 1.3.1, and does not happen on Solaris. See also bug 4530087.
|
|
Evaluation
|
Regression - commit to hopper.
xxxxx@xxxxx 2001-11-27
Here is another test case which fires two action events when a Window is Activated with a Button press:
import java.awt.*;
import java.awt.event.*;
public class ButtonActionEventTest extends Frame
implements ActionListener
{
int actionCount = 0;
public ButtonActionEventTest() {
super("button ActionEvent test");
Button b = new Button("Press Me");
b.addActionListener(this);
b.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent me) {
System.out.println("mouseClicked");
}
public void mousePressed(MouseEvent me) {
System.out.println("mousePressed");
}
public void mouseReleased(MouseEvent me) {
System.out.println("mouseReleased");
}
});
add(b);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
ButtonActionEventTest.this.dispose();
System.exit(0);
}
public void windowActivated(WindowEvent we) {
//System.out.println(we);
try {
System.out.println(we);
Thread.sleep(1000);
} catch (InterruptedException ie) {
}
}
});
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
System.out.println("action performed " + actionCount++);
}
public static void main(String[] args) {
new ButtonActionEventTest();
}
}
I did notice that without the sleep(), the problem disappears. Timing issue?
xxxxx@xxxxx 2001-11-28
The cause of this bug is the fix for 4327679, which was putback with fixes for similar bugs 4327618, 4327623, 4327639, 4327654, 4327664, 4327676. This could be confirmed by running the test cases with Merlin builds 30 and 31 - it would be introduced in b31.
MOUSE_DRAGGED and MOUSE_RELEASED events were fixed by capturing the mouse on all
button presses. Several regressions were found and fixed before the putback,
but this one was missed.
Before the mouse capturing, ActionEvents were sent to Buttons in response to
WM_COMMAND messages (via WmNotify()). This covered the case of mouse clicks as well as pressing the space bar. The MSDN docs for SetCapture() state, "When the mouse is captured, menu hotkeys and other keyboard accelerators do not work." This is true in that when we capture the mouse, no WM_COMMAND message are received.
With mouse capturing, space bar still sent WM_COMMAND messages, but mouse clicks didn't, so WM_LBUTTONUP handling was changed to also call WmNotify(), sending ActionEvents as appropriate.
This bug is due in part to bugs/underspecification in the Win32 APIs. Clearly,
there is some relationship between WM_COMMAND events and mouse capture, but it
is not well specified.
It appears that Windows treats left and right mouse buttons differently with respect to capture. Using Spy++, I observed that clicking on a Button w/ the left mouse button results in two WM_CAPTURECHANGED events. But w/ the right mouse button, we see a WM_CAPTURECHANGED only on the release. If both buttons are held down and only the left button is released, we appear to lose mouse capture (we see a WM_CAPTURECHANGED event) though we don't call ReleaseCapture(), and the attempt to release capture on the right button release fails because we don't have capture. It is these capture-related behaviors of Windows that cause our problems. For some reason, Windows sees fit to release our mouse capture AND send a WM_COMMAND message if we left click on a Button while the right mouse button is also down. This is where our two ActionEvents come from: one through WmMouseUp->WmNotify(), and one through WmCommand()->WmNotify().
There a couple possible solutions, which I'm now investigating.
xxxxx@xxxxx 2002-08-26
|