Detecting mouse movement on screen
Asked Answered
H

2

6

I created a MouseMotionDetection class which role is just to detect that the user has moved the mouse anywhere on screen.

For this purpose I created a new JFrame inside my class constructor with the screen size which is invisible, so basically I am observing mouse motion all over the screen.

But, I have a weird bug:

In the code's current form, once this class is activated I only detect ONE mouse motion and nothing else, it stops working right after that. But, if I put the line which sets the frame backfround to 0f,0f,0f,0f (transparent) in comments and then activate, the whole screen becomes grey and I keep tracking all the mouse motions just as I desired (I just can't see anything).

I really do not understand why this happens, haven't seen related issues around, nor in this related javadoc, which discusses MouseMotion events.

This is the code:

public class MouseMotionDetection extends JPanel
                implements MouseMotionListener{

public MouseMotionDetection(Region tableRegion, Observer observer){
    addMouseMotionListener(this);
    setBackground(new Color(0f,0f,0f,0f));
    JFrame frame = new JFrame();         
    frame.setUndecorated(true);
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    frame.setSize(screenSize);
    frame.setBackground(new Color(0f,0f,0f,0f));
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.setAlwaysOnTop(true);
    JComponent contentPane = this;
    contentPane.setOpaque(true);
    frame.getContentPane().add(contentPane, BorderLayout.CENTER);
    frame.setVisible(true);
}

@Override
public void mouseDragged(MouseEvent arg0) {

}

@Override
public void mouseMoved(MouseEvent arg0) {
    System.out.println("mouse movement detected");
}
Hf answered 24/8, 2014 at 1:49 Comment(1)
I wouldn't use Java for this sort of program, but rather would either write a utility in C or C++ to hook onto the OS's mouse events, or use a utility language such as AutoIt (if for Windows) to do this.Rollicking
G
11

A completely transparent frame does not receive mouse events.

Here is an alternative using the MouseInfo. This works if the components of the app. are invisible (transparent), unfocused or minimized.

enter image description here

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class MouseMoveOnScreen {

    Robot robot;
    JLabel label;
    GeneralPath gp;
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();

    MouseMoveOnScreen() throws AWTException {
        robot = new Robot();

        label = new JLabel();
        gp = new GeneralPath();
        Point p = MouseInfo.getPointerInfo().getLocation();
        gp.moveTo(p.x, p.y);
        drawLatestMouseMovement();
        ActionListener al = new ActionListener() {

            Point lastPoint;

            @Override
            public void actionPerformed(ActionEvent e) {
                Point p = MouseInfo.getPointerInfo().getLocation();
                if (!p.equals(lastPoint)) {
                    gp.lineTo(p.x, p.y);
                    drawLatestMouseMovement();
                }
                lastPoint = p;
            }
        };
        Timer timer = new Timer(40, al);
        timer.start();
    }

    public void drawLatestMouseMovement() {
        BufferedImage biOrig = robot.createScreenCapture(
                new Rectangle(0, 0, d.width, d.height));
        BufferedImage small = new BufferedImage(
                biOrig.getWidth() / 4,
                biOrig.getHeight() / 4,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g = small.createGraphics();
        g.scale(.25, .25);
        g.drawImage(biOrig, 0, 0, label);

        g.setStroke(new BasicStroke(8));
        g.setColor(Color.RED);
        g.draw(gp);
        g.dispose();

        label.setIcon(new ImageIcon(small));
    }

    public JComponent getUI() {
        return label;
    }

    public static void main(String[] args) throws Exception {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                JPanel ui = new JPanel(new BorderLayout(2, 2));
                ui.setBorder(new EmptyBorder(4, 4, 4, 4));

                try {
                    MouseMoveOnScreen mmos = new MouseMoveOnScreen();
                    ui.add(mmos.getUI());
                } catch (AWTException ex) {
                    ex.printStackTrace();
                }

                JFrame f = new JFrame("Track Mouse On Screen");
                // quick hack to end the frame and timer
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setContentPane(ui);
                f.pack();
                f.setLocationByPlatform(true);
                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
Garlinda answered 24/8, 2014 at 3:24 Comment(2)
This is amazing, I didn't know Java could be so powerful. Where'd you learn about the robot class?Perfective
@SomeGuy It was so long ago, I cannot recall. Top possibilities are the Java Tutorial, the Java Docs or participation in usenet newsgroups.Garlinda
S
3

I believe that MouseEvents are not generated for transparent pixels. That is the MouseEvent is dispatched to the "visible" component under the frame.

So to receive the event you can't use absolute transparency. But you might be able to get away with using an alpha value of 1. I doubt you will notice a difference in the painting of the "transparent frame".

So I would use code like the following:

//frame.setBackground(new Color(0f,0f,0f,0f));
frame.setBackground(new Color(0f, 0f, 0f, 1f));

The following is not needed since you set the "contentPane" transparent when you add it to the frame:

//setBackground(new Color(0f,0f,0f,0f));

It should be noted that this code will only work when your application has focus.

Shool answered 24/8, 2014 at 2:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.