0

On my Windows 8 system running Java 1.7 I found that key events are interfering with mouse events. Here's an example. This is a silly thing to do, but it illustrates the problem that has shown up in more complicated settings. I find that once I have pressed a key, I can't move the mouse until I release the key. I don't know of any reason why this shouldn't work.

In fact, a bit more experimenting shows that this doesn't seem to be a Java issue at all - so I'm not sure what I should do about this question in the forum.

As MadProgrammer stated below, it's a keyboard autorepeat issue. In fact, if you press a key and then quickly move the mouse (before the autorepeat kicks in) you can draw a short line. So, the key events from the autorepeat seem to block the mouse movement on the screen. This appears to happen throughout the Windows interface. For instance, I used the Accessibility settings to turn off autorepeat - so in NotePad, say, keys no longer repeat when held. However, if you hold a key, the mouse still locks up. It locks even if it isn't in the NotePad window.

Clearly this is not a Java issue - I just happened to notice it here.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

// Demo key/mouse event interference
// Pressing and holding any key, moving the mouse
// and releasing the key should draw a line.
// written by mcslattery - april 2015
public class KeyMouse extends JPanel {
    public static final int WID = 500;
    public static final int HT = 400;

    int x1,y1,x2,y2;
    boolean drawn = false;
    int mx,my;

    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new KeyMouse()); f.pack();
        f.setVisible(true);
    }

    public KeyMouse() {
        super();
        setPreferredSize(new Dimension(WID, HT));
        addMouseMotionListener(new MseL());
        addKeyListener(new KeyL());
        setFocusable(true); requestFocus();
    }

    public void paintComponent(Graphics g) {
        g.setColor(Color.white);
        g.fillRect(0,0,WID,HT);
        if (drawn) {
            g.setColor(Color.black);
            g.drawLine(x1, y1, x2, y2);
        }   
    }

    class MseL extends MouseMotionAdapter {
        public void mouseMoved(MouseEvent e) {
            mx = e.getX(); my = e.getY();   
        }
    }

    class KeyL extends KeyAdapter {
        public void keyPressed(KeyEvent e) {
            x1 = mx; y1 = my;
            drawn = false;
            repaint();
        }

        public void keyReleased(KeyEvent e) {
            x2 = mx; y2 = my;
            drawn = true;
            repaint();
        }
    }
}

1 Answer 1

1

The problem isn't with the OS or Java, it's with you assumption about how keyPressed works.

When pressed, a key will trigger a keyPressed event, after a OS specific delay, it will trigger repeated events until the key is released, when keyReleased is called.

This means that...

public void keyPressed(KeyEvent e) {
    x1 = mx;
    y1 = my;
    drawn = false;
    repaint();
}

is constently updating the x1 and y1 values to be the same as the current mouse position...

Instead, add a flag which can be used to determine if the key has already been pressed, if it hasn't set the start values. When released, reset the flag, for example...

private boolean pressed = false;

public void keyPressed(KeyEvent e) {
    if (!pressed) {
        pressed = true;
        x1 = mx;
        y1 = my;
        drawn = false;
        repaint();
    }
}

public void keyReleased(KeyEvent e) {
    pressed = false;

Side note:

I'm not particular conformatable with your paintComponent method...

public void paintComponent(Graphics g) {
    g.setColor(Color.white);
    g.fillRect(0,0,WID,HT);

Three main reasons...

  1. The component might not be WID wide or HT heigh
  2. You can use setBackground(Color.WHITE) in the constructor and super.paintComponent(g) to get the same results, which would generally be safer if paintComponent changes for some reason
  3. There's no need for the method to be public, you never want anyone to call it
Sign up to request clarification or add additional context in comments.

10 Comments

And yes, it's dumb that keyPressed isn't just called when the key is pressed, but it's too late for AWT's creators to fix it now.
@immibis I don't think that's so much an issue with AWT as that's how the OS messaging works, and probably should, what happens if you press the down arrow key on multi-line editor? Do you want to have to continuously keep pressing it? Seems weird, but that's the way it works :P
Win32 would have had the same problem. There's a WM_KEYDOWN event, a WM_KEYUP event, and a WM_CHAR event. Obviously it should send a WM_KEYDOWN event when the key is pressed, a WM_KEYUP event when the key is released, and as many WM_CHAR events as it wants in the middle. But instead, they chose to repeat the WM_KEYDOWN... and now they can't fix it because too much relies on it.
Of course! I know that. It's not a Java design issue (as immibis mentions)
[I'm new at this and somehow just cut off my previous comment] It's that the OS provides a keyboard strobe when the key is held down. You can also overcome this by turning off the OS feature - of course then keys won't autorepeat in editors, ... Thanks!! I also appreciate the comments on paintComponent(). This problem arose in a game where most everything is hand-drawn, but I'll definitely think about your suggestions!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.