13

In passive rendering mode one can use KeyListener and ActionListener interfaces to handle events from user.

What is the correct way of event handling in full screen mode? Please extend this skeleton providing implementation for mouse click and key press events, please don't bloat your example (the example starts full screen exclusive mode, using a Timer to update graphics in window):

import java.applet.Applet;
import java.awt.Color;
import java.awt.DisplayMode;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.Timer;

public class applet extends Applet
{
    Timer timer;
    JFrame frame;
    DisplayMode[] displayModes = new DisplayMode[] {
            new DisplayMode(1280, 800, 32, 60)
    };

    BufferStrategy bufferStrategy;
    Rectangle bounds;

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    /**
     * @param args
     */

    public void init()
    {

        GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); //displays, fonts, color shemes...
        GraphicsDevice device = env.getDefaultScreenDevice(); //for one-display systems

        setIgnoreRepaint(true);

        GraphicsConfiguration gc = device.getDefaultConfiguration();
        frame = new JFrame(gc);

        device.setFullScreenWindow(frame);

        if (device.isDisplayChangeSupported())
            device.setDisplayMode(displayModes[0]);

        frame.createBufferStrategy(2);
        bufferStrategy = frame.getBufferStrategy();

        timer = new Timer(1000 / 50, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                Graphics2D g = null;
                try {
                    g = (Graphics2D) bufferStrategy.getDrawGraphics();
                    render(g);
                } finally {
                    g.dispose();
                }
                bufferStrategy.show();
            }

        });

    }

    private void render(Graphics2D g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, bounds.width, bounds.height);
    }

    public void start()
    {
        timer.start();

    }

    public void stop()
    {
        timer.stop();
    }

}
Phoebe
  • 2,774
  • 3
  • 22
  • 27
Vadim
  • 1,223
  • 2
  • 17
  • 26

2 Answers2

24

It looks like the usual approaches shown in How to Use Key Bindings and How to Write a Mouse Listener work correctly in Full-Screen Exclusive Mode.

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

/** @see http://stackoverflow.com/questions/7456227 */
public class FullScreenTest extends JPanel {

    private static final String EXIT = "Exit";
    private JFrame f = new JFrame("FullScreenTest");
    private Action exit = new AbstractAction(EXIT) {

            @Override
            public void actionPerformed(ActionEvent e) {
                f.dispatchEvent(new WindowEvent(
                    f, WindowEvent.WINDOW_CLOSING));
            }
        };
    private JButton b = new JButton(exit);

    public FullScreenTest() {
        this.add(b);
        f.getRootPane().setDefaultButton(b);
        this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0), EXIT);
        this.getActionMap().put(EXIT, exit);
        this.addMouseMotionListener(new MouseAdapter() {

            @Override
            public void mouseMoved(MouseEvent e) {
                FullScreenTest.this.setToolTipText(
                    "("+ e.getX() + "," + e.getY() + ")");
            }
        });
    }

    private void display() {
        GraphicsEnvironment env =
            GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice dev = env.getDefaultScreenDevice();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setBackground(Color.darkGray);
        f.setResizable(false);
        f.setUndecorated(true);
        f.add(this);
        f.pack();
        dev.setFullScreenWindow(f);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new FullScreenTest().display();
            }
        });
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Thank you for the answer! Could you please also provide the same example, but as java applet? I wanted example to be a java applet, but seems I forgot to include that in the first post... I think you need to do only small additions/changes to the actual code you provided, will be very thank you if you do that, because your example is very good to study from! – Vadim Sep 17 '11 at 20:22
  • 2
    I'd suggest `JApplet`, but it would probably have to be [signed](http://download.oracle.com/javase/tutorial/deployment/applet/security.html) for security. You can try it using a hybrid approach shown [here](https://sites.google.com/site/drjohnbmatthews/subway); [tag:java-web-start] would be a better deployment strategy. – trashgod Sep 17 '11 at 21:04
  • Thank you, will be checking it! – Vadim Sep 17 '11 at 21:09
  • 1
    @Vadim Be aware that Java 1.7 in OSX actually has a bug using this technique http://stackoverflow.com/questions/14317352. – sage88 Sep 29 '13 at 09:16
  • See also [*FullScreen Swing Components Fail to Receive Keyboard Input on Java 7 on Mac OS X Mountain Lion*](http://stackoverflow.com/q/13064607/230513). – trashgod May 18 '15 at 16:10
9

As suggested here, Mac OS X users may have different user expectations for full screen applications. An alternative approach, shown here, relies on com.apple.eawt classes that "provide a simple way to implement native features to fine tune Java applications on Mac OS X." The FullScreenUtilities method setWindowCanFullScreen() enables the feature, and the Application method requestToggleFullScreen() changes the setting dynamically. Note how the expand icon differs among versions.

Mac OS 10.9, Mavericks:

10.9

Mac OS 10.10, Yosemite:

10.10

Mac OS X 10.11, El Capitan:

enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

/**
 * @see https://stackoverflow.com/a/30308671/230513
 * @see https://stackoverflow.com/questions/7456227
 * @see https://stackoverflow.com/q/13064607/230513
 * @see https://stackoverflow.com/q/30089804/230513
 * @see https://stackoverflow.com/q/25270465/230513
 * @see http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/macosx/classes/com/apple/
 */
public class FullScreenTest extends JPanel {

    private static final String NAME = "Mac OS X Full Screen Test";
    private static final String TOGGLE = "Toggle Full Screen";
    private final JFrame f = new JFrame(NAME);
    private final Action exit = new AbstractAction(TOGGLE) {

        @Override
        public void actionPerformed(ActionEvent e) {
            toggleOSXFullscreen(f);
        }
    };
    private final JButton b = new JButton(exit);

    public FullScreenTest() {
        this.add(b);
        f.getRootPane().setDefaultButton(b);
        this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0), TOGGLE);
        this.getActionMap().put(TOGGLE, exit);
        this.addMouseMotionListener(new MouseAdapter() {

            @Override
            public void mouseMoved(MouseEvent e) {
                FullScreenTest.this.setToolTipText(
                        "(" + e.getX() + "," + e.getY() + ")");
            }
        });
    }

    private void display() {
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setBackground(Color.darkGray);
        f.add(this);
        f.add(new JLabel(NAME, JLabel.CENTER), BorderLayout.SOUTH);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        if (System.getProperty("os.name").startsWith("Mac OS X")) {
            enableOSXFullscreen(f);
            toggleOSXFullscreen(f);
            enableOSXQuitStrategy();
        }
        f.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println(e);
            }
        });
    }

    //FullScreenUtilities.setWindowCanFullScreen(window, true);
    private void enableOSXFullscreen(Window window) {
        try {
            Class util = Class.forName("com.apple.eawt.FullScreenUtilities");
            Class params[] = new Class[]{Window.class, Boolean.TYPE};
            Method method = util.getMethod("setWindowCanFullScreen", params);
            method.invoke(util, window, true);
        } catch (ClassNotFoundException | NoSuchMethodException |
                SecurityException | IllegalAccessException |
                IllegalArgumentException | InvocationTargetException exp) {
            exp.printStackTrace(System.err);
        }
    }

    //Application.getApplication().requestToggleFullScreen(window);
    private void toggleOSXFullscreen(Window window) {
        try {
            Class application = Class.forName("com.apple.eawt.Application");
            Method getApplication = application.getMethod("getApplication");
            Object instance = getApplication.invoke(application);
            Method method = application.getMethod("requestToggleFullScreen", Window.class);
            method.invoke(instance, window);
        } catch (ClassNotFoundException | NoSuchMethodException |
                SecurityException | IllegalAccessException |
                IllegalArgumentException | InvocationTargetException exp) {
            exp.printStackTrace(System.err);
        }
    }

    //Application.getApplication().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
    private void enableOSXQuitStrategy() {
        try {
            Class application = Class.forName("com.apple.eawt.Application");
            Method getApplication = application.getMethod("getApplication");
            Object instance = getApplication.invoke(application);
            Class strategy = Class.forName("com.apple.eawt.QuitStrategy");
            Enum closeAllWindows = Enum.valueOf(strategy, "CLOSE_ALL_WINDOWS");
            Method method = application.getMethod("setQuitStrategy", strategy);
            method.invoke(instance, closeAllWindows);
        } catch (ClassNotFoundException | NoSuchMethodException |
                SecurityException | IllegalAccessException |
                IllegalArgumentException | InvocationTargetException exp) {
            exp.printStackTrace(System.err);
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new FullScreenTest()::display);
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • See also [*Swing on OSX: How to Trap command-Q?*](http://stackoverflow.com/q/2061194/230513) – trashgod Mar 29 '16 at 01:50
  • Quick note: the call to `requestToggleFullScreen` seems to fail silently if it's made before the frame is [made displayable](https://docs.oracle.com/javase/8/docs/api/java/awt/Component.html#isDisplayable--). (Testing on El Capitan 10.11.6.) – Radiodef Nov 30 '17 at 00:22