4

My question is essentially is if there was a way, in Java, to have some type of un-selectable overlay on the screen. By 'un-selectable' I mean, if I overlayed the JWindow/JFrame over a window from another process for example, I can still interact with the window as normal, but I can render content in the JWindow/JFrame that appears on top of the window at the same time.

Simply creating a component and setting the following flags AutoRequestFocus/Focusable/Enabled to false does not achieve my goal as the overlay blocks the mouse from clicking on anything behind it.

This would be on a windows system but preferably isn't restricted to OS.

Joe C
  • 1,788
  • 2
  • 17
  • 27
  • just to clarify: "browser" means a regular browser like Chrome, Firefox, Internet Explorer, i.e. a window from another process? Or a JFrame within your java application that shows a webpage? – cello Feb 23 '15 at 19:50
  • Windows as Operating system? – Christian Kuetbach Feb 23 '15 at 20:18
  • 1
    The answers in related question [Making a window click-through](http://stackoverflow.com/q/11217660/3080094) might get you started ... – vanOekel Feb 23 '15 at 21:27
  • @ChristianKuetbach Windows would be the OS, but I was hoping this wouldn't be OS dependant. – Joe C Feb 25 '15 at 04:23
  • @cello The browser was an example, but a window from another process would be a more accurate description. I'll edit my post to say that. – Joe C Feb 25 '15 at 04:23
  • How about `JDialog` ? –  Feb 25 '15 at 04:28
  • another possible duplicate: http://stackoverflow.com/questions/20808331/creating-a-jframe-you-can-click-through. There it says it cannot be done if you also want to paint something into that overlay window. – cello Feb 25 '15 at 10:44

3 Answers3

1

Only option i can see of achieving this is to use JNA, and this works. You have to refer JNA libraries

public class Main
{
    public static void main(String[] args)
    {
        TestFrame frame = new TestFrame();
        frame.setVisible(true);
        WinDef.HWND hwnd = User32.INSTANCE.FindWindow("SunAwtFrame", "Transparent Window");

        int wl =  User32.INSTANCE.GetWindowLong(hwnd, WinUser.GWL_EXSTYLE);
        wl = wl | 0x80000 | 0x20;
        User32.INSTANCE.SetWindowLong(hwnd, WinUser.GWL_EXSTYLE, wl);
    }

    public static long getHWnd(Frame f) {
        return f.getPeer() != null ? ((WComponentPeer) f.getPeer()).getHWnd() : 0;
    }

    static class TestFrame extends JFrame
    {
        public TestFrame()
        {
            super("Transparent Window");
            setUndecorated(true);
            setBackground(new Color(0, 0, 0, 0));
            setAlwaysOnTop(true);
            setSize(800, 600);
            // Without this, the window is draggable from any non transparent
            // point, including points  inside textboxes.
            getRootPane().putClientProperty("apple.awt.draggableWindowBackground", false);

            getContentPane().setLayout(new java.awt.BorderLayout());
            getContentPane().add(new JTextField("text field north"), java.awt.BorderLayout.NORTH);
            getContentPane().add(new JTextField("text field south"), java.awt.BorderLayout.SOUTH);
        }

        @Override
        public void paint(Graphics g)
        {
            super.paint(g);
            g.setColor(Color.BLUE);
            g.fill3DRect(0,0,100,100,false);
        }
    }
}
Low Flying Pelican
  • 5,974
  • 1
  • 32
  • 43
  • Does not allow same time interaction. Clicking on the JFrame takes focus from the underlying window and does allow the click to pass through. – Joe C Feb 25 '15 at 17:21
  • yes.. so only solution seems to be use JNA, and it does not sure work across platforms, but you should be able to create platform specific code for other platforms. See the edited answer – Low Flying Pelican Feb 26 '15 at 00:01
  • Edited answer works as hoped for. Thank you very much. Curious though to why you set the WS_EX_LAYERED flag? – Joe C Feb 26 '15 at 06:48
0

I think it is possible, because I used to create the opposite thing. A window, that is transparent, but receives Events.

You will need to write an application, which creates a completely transparent Window (I used SWT). Every part, that is complete transparent, will not receive any events. Parts, which are not complete transparent, will get events.

Your application will need to interact with the operatingsystem, to find the correct process and get the windows position and size.

Within your paintloop, you will need to set your windows position and size.

This part was easier in my application, because it was the same process.

Christian Kuetbach
  • 15,850
  • 5
  • 43
  • 79
0

Have a look at this demo, it shows how to pass click events from the glass pane (where you paint your extra content) to the underlying "real" pane (where you want the clicks/events to happen). See the method redispatchMouseEvent. Some relevant parts of the code are below:

glass = new FixedGlassPane(jFrame.getContentPane());
jFrame.setGlassPane(glass);

public class FixedGlassPane extends JPanel
    ...
    addMouseListener(this);
    addMouseMotionListener(this);
    addFocusListener(this);
    ...
  }

  public void mouseDragged(MouseEvent e) {
    if (needToRedispatch)
      redispatchMouseEvent(e);
  }

  public void mouseMoved(MouseEvent e) {
    if (needToRedispatch)
      redispatchMouseEvent(e);
  }

  ... other mouse event methods ...

 private void redispatchMouseEvent(MouseEvent e) {
    boolean inButton = false;
    boolean inMenuBar = false;
    Point glassPanePoint = e.getPoint();
    Component component = null;
    Container container = contentPane;
    Point containerPoint = SwingUtilities.convertPoint(this,
        glassPanePoint, contentPane);
    int eventID = e.getID();

    if (containerPoint.y < 0) {
      inMenuBar = true;
      container = menuBar;
      containerPoint = SwingUtilities.convertPoint(this, glassPanePoint,
          menuBar);
      testForDrag(eventID);
    }

    //XXX: If the event is from a component in a popped-up menu,
    //XXX: then the container should probably be the menu's
    //XXX: JPopupMenu, and containerPoint should be adjusted
    //XXX: accordingly.
    component = SwingUtilities.getDeepestComponentAt(container,
        containerPoint.x, containerPoint.y);

    if (component == null) {
      return;
    } else {
      inButton = true;
      testForDrag(eventID);
    }

    if (inMenuBar || inButton || inDrag) {
      Point componentPoint = SwingUtilities.convertPoint(this,
          glassPanePoint, component);
      component.dispatchEvent(new MouseEvent(component, eventID, e
          .getWhen(), e.getModifiers(), componentPoint.x,
          componentPoint.y, e.getClickCount(), e.isPopupTrigger()));
    }
  }

  private void testForDrag(int eventID) {
    if (eventID == MouseEvent.MOUSE_PRESSED) {
      inDrag = true;
    }
  }
}
geert3
  • 7,086
  • 1
  • 33
  • 49
  • This misses the point of the question, I want to pass through events from the Java created window to a window created by a different process. – Joe C Feb 25 '15 at 17:40
  • OK i missed that. But it would sound like a enormous security issue if this were possible. You could basically draw anything on top of native windows (e.g. hide relevant information or add fake information), and/or invisibly hijack mouse events not intended for you. It's the stuff malware makers dreams of. – geert3 Feb 25 '15 at 22:13