FullScreen Swing组件无法在Mac OS X Mountain Lion上的Java 7上接收键盘输入 [英] FullScreen Swing Components Fail to Receive Keyboard Input on Java 7 on Mac OS X Mountain Lion

查看:153
本文介绍了FullScreen Swing组件无法在Mac OS X Mountain Lion上的Java 7上接收键盘输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新12/21:



最近发布了7u10。确认:


  1. 问题仍然存在

  2. 值得庆幸的是,解决方法仍然有效!

更新11/7:



我们有解决方法!



来自Oracle的Leonid Romanov在openjdk.java.net邮件列表中提供了一些有关正在发生的事情的见解


好吧,虽然我还不是100%肯定,但看起来当我们进入全屏时,其他一些窗口成为第一个响应者,因此发出哔哔声。您可以尝试以下解决方法:在框架上调用setFullScreenWindow()之后,调用setVisible(false),然后调用setVisible(true)。理论上,这应该恢复正确的第一响应者。


似乎有效的代码片段就是:

  dev.setFullScreenWindow(F); 
f.setVisible(false);
f.setVisible(true);

我更新了示例代码,可以打开和关闭此修复程序;每次窗口进入全屏时都需要它。



在我更复杂的应用程序的更大的上下文中,我仍然在全屏窗口中的子组件上遇到键盘焦点问题,鼠标单击导致我的窗口失去焦点。 (我猜它会转到上面提到的不受欢迎的第一响应者窗口。)当我有关于这种情况的更多信息时我会报告 - 我无法在较小的样本中重现它。






更新10/31:



示例代码的主要更新:




  • 包括在FullScreen独占模式和Lion风格的全屏模式之间切换

  • 收听 KeyboardFocusManager 显示当前焦点组件的层次结构

  • 使用输入映射和 KeyListener s试图捕获输入



还与同事一起进行了更多挖掘以试图找出问题:



在一方面,我们尝试覆盖RT.jar中的一些方法,以查看屏幕设备的选择方式是否存在问题。还尝试了Toolkit.beep()功能的入口点,以查看警报声是否来自Java端 - 似乎没有。



在另一方面,它很明显,甚至本机方都没有收到键盘事件。同事将此归因于7u6中从 AWTView NSWindow 的转换。



已找到一系列现有的Oracle错误,您可以在此处








更新10/26:



感谢下面@maslovalex关于工作7u5的Applet的评论,我回去并仔细检查了与OSX的JDK版本的兼容性:




  • 10.7.1 with 7u4:Fullscreen Works!

  • 10.7.1 with 7u5:Fullscreen Works!

  • 10.7.5 with 7u5:Fullscreen Works!

  • 10.7.5 7u6:全屏休息:(



结合其他地方提到的其他测试,显然7u6引入的问题仍然存在7u7和7u9,它影响Lion 10.7和Mountain Lion 10.8。



7u6是一个重要的里程碑版本,将JRE和JDK全面支持到Mac OS X和还包括Java FX作为发行的一部分。有关详细信息,请参阅发行说明路线图。这种问题可能会随着支持转移到Java FX而出现并不令人惊讶。



问题变为:


  1. Oracle会在近期发布的JDK中修复此问题吗? (如果您有现有错误的链接,请在此处加入。)

  2. 过渡期是否可以解决?

今天的其他更新:




  • 我合并了 Apple扩展进入全屏模式作为探索的替代路径(更新的示例代码等待清理)。好消息:输入有效!坏消息:似乎没有任何自助终端/隔离选项。

    我试图杀死Dock - 直接应用程序 - 据我所知,Dock负责Command -Tab app切换,Mission Control和Launch Pad,只是为了发现它还负责处理全屏应用程序!因此,Java调用变得无法运行并且永远不会返回。

    如果有办法禁用命令选项卡(以及任务控制和启动板和空间),而不会影响Dock的全屏处理,非常有用。或者,可以尝试重新映射某些键,例如Command,但这会影响在程序中的其他位置和系统本身使用该修饰符的能力(当您需要Command-C复制某些文本时,这并不完全理想)。 / p>


  • 我对KeyListeners没有好运(我没有收到任何回调),但我还有其他一些选择。


  • 根据同事的建议,我尝试了((sun.lwawt.macosx.LWCToolkit)Toolkit.getDefaultToolkit())。isApplicationActive()通过反思。我的想法是:

    是一个带有注释的本机方法如果应用程序(其中一个窗口)拥有键盘焦点,则返回true。在过去几个月中,与聚焦逻辑相关的CPlatformWindow.java中添加了对此方法的调用。如果它在你的测试代码中返回false,那么它可能是问题的一部分。

    不幸的是,无论我在哪里检查它,方法都返回true。因此,即使根据低级别系统,我的窗口也应该有键盘焦点。


  • 我之前关于JAlbum修复的乐观情绪已经破灭。开发人员在他们的论坛上发布了一个回复,解释了他们如何简单地删除了正确的全屏在运行Java 7时支持OS X.他们在Oracle中有一个错误(我希望得到错误号)。







更新10/25:



我现在也尝试过Java 7u9在Lion 10.7.4上已经看到完全相同的问题,所以它是JDK-而不是特定于操作系统。



核心问题是你是否可以嵌入全屏窗口核心Swing组件,具有键盘输入的默认处理( JTextField / JTextArea 甚至可编辑的组合框),并期望它们正常运行(无需求助于重建其基本键绑定手动地)。另外还有一个问题是,窗口布局的其他支持者(例如使用制表符进行焦点遍历)是否应该有效。



理想的目标是让能力采取窗口摆动应用程序及其所有按钮,选项卡,字段等,并以全屏独占/自助服务终端模式运行,大多数功能完好无损。 (之前,我已经看到在OS X上的Java 6上,Dialog弹出窗口或ComboBox下拉列表无法全屏显示,但其他组件表现良好。)



我'我们将研究eawt的FullScreen功能,如果它们支持kiosk锁定选项,例如消除Command-Tab应用程序切换,那将会很有趣。






原始问题:



我有一个多年来一直支持的Swing应用 Mac OS X上的FullScreen(独家)模式直到Java 6.我一直在进行兼容性测试使用最新的Mountain Lion版本(10.8.2 Supplemental)和Oracle的JDK 7,并注意到在该模式下的一个明显问题:鼠标移动和点击工作正常,但键盘输入未传递给组件。



(我在下面的测试用例中将其缩小到在全屏模式下无法输入简单的JTextField。)



一个症状是,每次按键都会导致系统发出蜂鸣声,就好像操作系统禁止将键盘事件传递给应用程序一样。



另外,我的应用程序安装了一个退出钩子,Command-Q组合将触发该钩子 - 很明显操作系统正在监听标准键组合。



I已经在具有各种安装的三个不同Mac上单独测试了这个:




  • 在Apple Java 6u35和6u37上:窗口和全屏模式都接收输入。

  • 在Oracle Java 7u7和7u9上:窗口模式按预期工作,而全屏具有上述症状。



这可能是之前报道的:
Java图形全屏模式未注册键盘输入
但是,这个问题并不是关于Java版本或平台的具体问题。



其他搜索已经在Lion中引入了一个单独的全屏选项:
OSX Lion上的Java应用程序的全屏功能
我还没有尝试使用这种方法,因为键盘输入似乎是FullScreen Exclusive模式的目标用例不可或缺的部分,例如游戏。



有一些在JavaDoc中提到此模式可能会禁用输入方法。我试图调用建议的 Component.enableInputMethods(false),但似乎无效



我有点乐观,基于我遇到的Java应用程序(JAlbum)的发行说明中的​​条目,有一个解决此问题的方法。 声明的10.10.6修复程序:运行时,键盘支持无效Mac和Java 7上的全屏幻灯片放映



我的测试用例如下。从本期的第二个例子中可以轻微修改(未经修改,也出现了我的问题):如何在java中以全屏独占模式处理键盘和鼠标中的事件?
特别是,它添加了一个按钮来切换全屏。

  import java.lang.reflect。*; 
import java.awt。*;
import java.awt.event。*;
import javax.swing。*;
import java.beans。*;

/ ** @see https://stackoverflow.com/questions/13064607/ * /
公共类FullScreenTest扩展JPanel {
private GraphicsDevice dev = GraphicsEnvironment.getLocalGraphicsEnvironment() .getDefaultScreenDevice();
private JFrame f = new JFrame(FullScreenTest);

private static final String EXIT =Exit;
private Action exit = new AbstractAction(EXIT){
@Override
public void actionPerformed(ActionEvent e){
Object o = dev.getFullScreenWindow();
if(o!= null){
dev.setFullScreenWindow(null);
}
f.dispatchEvent(new WindowEvent(f,WindowEvent.WINDOW_CLOSING));
}
};
private JButton exitBTN = new JButton(exit);

private JTextField jtf = new JTextField(在Mac OS X 10.7.3+上使用Java7u6 +在FullScreen中不可编辑);

private JLabel keystrokeLabel = new JLabel((最后修饰符+在JTextField中按下的键));

private JLabel jtfFocusLabel = new JLabel((JTextField Focus State));

private JLabel focusLabel = new JLabel((聚焦组件层次结构));

私有JCheckBox使用OSXFullScreenCB =新的JCheckBox(使用狮子式全屏模式);

private JCheckBox useWorkaroundCB = new JCheckBox(使用可见性解决方法恢复第一个响应者窗口);

private static final String TOGGLE =Toggle FullScreen(Command-T或Enter);
private Action toggle = new AbstractAction(TOGGLE){
@Override
public void actionPerformed(ActionEvent e){
Object o = dev.getFullScreenWindow();
if(o == null){
f.pack();

/ **
* !!这些电话似乎都没有任何后期效果。
*一个例外:我有一个
* Mini的报告进入一个不可恢复的黑屏,没有setVisible(true);
*可能只是Java 6兼容性问题。 !
* /
//f.setVisible(true);
//f.setVisible(false);

if(!useOSXFullScreenCB.isSelected()){
//此调用后没有键盘输入,除非使用解决方法
dev.setFullScreenWindow(f);

/ **
*由Leonid Romanov在Oracle提供的解决方法。
* /
if(useWorkaroundCB.isSelected()){
f.setVisible(false);
f.setVisible(true);
//以后不需要调用...
/*SwingUtilities.invokeLater(new Runnable(){
public void run(){
f.setVisible(false);
f.setVisible(true);
}
}); * /
}
}
else {
toggleOSXFullscreen(f);
}
}
else {
dev.setFullScreenWindow(null);
f.pack();
f.setVisible(true);
}

isAppActive();
}
};
private JButton toggleBTN = new JButton(toggle);

public FullScreenTest(){
// - 布局 -
this.setLayout(新BoxLayout(this,BoxLayout.PAGE_AXIS));

exitBTN.setAlignmentX(JComponent.CENTER_ALIGNMENT);
exitBTN.setMaximumSize(new Dimension(Short.MAX_VALUE,50));
this.add(exitBTN);

jtf.setAlignmentX(JComponent.CENTER_ALIGNMENT);
jtf.setMaximumSize(new Dimension(Short.MAX_VALUE,Short.MAX_VALUE));
this.add(jtf);

keystrokeLabel.setAlignmentX(JComponent.CENTER_ALIGNMENT);
keystrokeLabel.setMaximumSize(new Dimension(Short.MAX_VALUE,50));
keystrokeLabel.setHorizo​​ntalAlignment(SwingConstants.CENTER);
keystrokeLabel.setForeground(Color.DARK_GRAY);
this.add(keystrokeLabel);

jtfFocusLabel.setAlignmentX(JComponent.CENTER_ALIGNMENT);
jtfFocusLabel.setMaximumSize(new Dimension(Short.MAX_VALUE,50));
jtfFocusLabel.setHorizo​​ntalAlignment(SwingConstants.CENTER);
jtfFocusLabel.setForeground(Color.DARK_GRAY);
this.add(jtfFocusLabel);

focusLabel.setAlignmentX(JComponent.CENTER_ALIGNMENT);
focusLabel.setMaximumSize(new Dimension(Short.MAX_VALUE,50));
focusLabel.setHorizo​​ntalAlignment(SwingConstants.CENTER);
focusLabel.setForeground(Color.DARK_GRAY);
this.add(focusLabel);

useOSXFullScreenCB.setAlignmentX(JComponent.CENTER_ALIGNMENT);
useOSXFullScreenCB.setMaximumSize(new Dimension(Short.MAX_VALUE,50));
useOSXFullScreenCB.setHorizo​​ntalAlignment(SwingConstants.CENTER);
this.add(useOSXFullScreenCB);

useWorkaroundCB.setAlignmentX(JComponent.CENTER_ALIGNMENT);
useWorkaroundCB.setMaximumSize(new Dimension(Short.MAX_VALUE,50));
useWorkaroundCB.setHorizo​​ntalAlignment(SwingConstants.CENTER);
this.add(useWorkaroundCB);

toggleBTN.setAlignmentX(JComponent.CENTER_ALIGNMENT);
toggleBTN.setMaximumSize(new Dimension(Short.MAX_VALUE,50));
this.add(toggleBTN);

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
f.setUndecorated(true);
f.add(this);
f.pack();

enableOSXFullscreen(f);

// - 听众 -

//默认BTN设置为查看输入地图如何在全屏中响应
f.getRootPane()。setDefaultButton(toggleBTN) ;

//使用来自窗口中任何位置的Command-T切换操作的显式输入映射测试
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent。 VK_T,Toolkit.getDefaultToolkit()。getMenuShortcutKeyMask()),
toggle.getValue(Action.NAME));
this.getActionMap()。put(toggle.getValue(Action.NAME),toggle);

// KeyListener test
jtf.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
String ktext =KeyPressed:+ e .getKeyModifiersText(e.getModifiers())+_+ e.getKeyText(e.getKeyCode());
keystrokeLabel.setText(ktext);
System.out.println(ktext);
}
});

// FocusListener测试
jtf.addFocusListener(new FocusListener(){
public void focusGained(FocusEvent fe){
focused(fe);
}
public void focusLost(FocusEvent fe){
focused(fe);
}
private void focused(FocusEvent fe){
boolean allGood = jtf.hasFocus( )&& jtf.isEditable()&& jtf.isEnabled();
jtfFocusLabel.setText(JTextField具有焦点(并且已启用/可编辑):+ allGood);
isAppActive ();
}
});

//键盘焦点管理器
KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(new PropertyChangeListener(){
public void propertyChange(PropertyChangeEvent e){
if(!(focusOwner.equals(e.getPropertyName())))return;
组件comp =(组件)e.getNewValue();
if(comp == null){
focusLabel.setText((无组件聚焦));
return;
}
String label = comp.getClass()。getName();
while(true){
comp = comp.getParent();
if(comp == null)break;
label = comp.getClass()。getSimpleName()+ - >+ label;
}
focusLabel.setText(Focus Hierarchy:+ label );
isAppActive();
}
});
}

/ **
*暗示此窗口可以进入全屏。每个窗口只需要调用一次。
* @param窗口
* /
@SuppressWarnings({unchecked,rawtypes})
public static void enableOSXFullscreen(Window window){
try {
Class util = Class.forName(com.apple.eawt.FullScreenUtilities);
Class params [] = new Class [] {Window.class,Boolean.TYPE};
方法方法= util.getMethod(setWindowCanFullScreen,params);
method.invoke(util,window,true);
} catch(ClassNotFoundException e1){
} catch(例外e){
System.out.println(无法启用Mac全屏:+ e);
}
}

/ **
*切换OSX全屏窗口状态。必须先调用enableOSXFullscreen。
*反思版:com.apple.eawt.Application.getApplication()。requestToggleFullScreen(f);
* @param窗口
* /
@SuppressWarnings({unchecked,rawtypes})
public static void toggleOSXFullscreen(Window window){
try {
类appClass = Class.forName(com.apple.eawt.Application);

方法method = appClass.getMethod(getApplication);
Object appInstance = method.invoke(appClass);

Class params [] = new Class [] {Window.class};
method = appClass.getMethod(requestToggleFullScreen,params);
method.invoke(appInstance,window);
} catch(ClassNotFoundException e1){
} catch(例外e){
System.out.println(无法切换Mac全屏:+ e);
}
}

/ **
*基于Apple的Javadoc快速检查低级窗口焦点状态:
*如果返回true,则返回应用程序(其中一个窗口)拥有键盘焦点。
* /
@SuppressWarnings({unchecked,rawtypes})
public static void isAppActive(){
try {
Class util = Class.forName ( sun.lwawt.macosx.LWCToolkit);
方法method = util.getMethod(isApplicationActive);
Object obj = method.invoke(Toolkit.getDefaultToolkit());
System.out.println(AppActive:+ obj);
} catch(ClassNotFoundException e1){
} catch(例外e){
System.out.println(无法检查App:+ e);
}
}

public static void main(String [] args){
System.out.println(Java Version:+ System.getProperty( java.version));
System.out.println(OS Version:+ System.getProperty(os.version));

SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
FullScreenTest fst = new FullScreenTest();
if (!fst.dev.isFullScreenSupported()){
System.out.println(此图形设备不支持FullScreen。正在退出。);
System.exit(0);
}
fst.toggle.actionPerformed(null);
}
});
}
}


解决方案

,使用键绑定,如下所示 FullScreenTest 。另外,请考虑此处 DocumentListener ,以了解文本组件。


Update 12/21:

7u10 was recently released. Confirmed that:

  1. The issue still persists
  2. Thankfully, the workaround still functions!

Update 11/7:

And we have a workaround!

Leonid Romanov from Oracle on the openjdk.java.net mailing list provided some insight as to what's going on:

Well, although I'm not 100% sure yet, but it looks like when we enter full screen some other window becomes the first responder, hence the beep. Could you please try the following workaround: after calling setFullScreenWindow() on a frame, call setVisible(false) followed by setVisible(true). This, in theory, should restore the correct first responder.

The snippet of code that seems to work is simply:

dev.setFullScreenWindow(f);
f.setVisible(false);
f.setVisible(true);

I have updated the sample code with the ability to toggle this fix on and off; it is required every time a window enters fullscreen.

In the larger context of my more complex application, I am still running into keyboard focus issues on subcomponents within the fullscreen window, where a mouse click causes my window to lose focus. (I'm guessing it's going to the undesired first responder window referenced above.) I'll report back when I have more information about this case - I cannot reproduce it in the smaller sample yet.


Update 10/31:

Major update to the sample code:

  • Includes toggle between FullScreen exclusive and Lion-style FullScreen modes
  • Listens to the KeyboardFocusManager to display the hierarchy for the currently focused component
  • Uses both input maps and KeyListeners to try to capture input

Also did some more digging with coworkers to try to isolate issues:

On one front, we tried overriding some methods in RT.jar to see if there were problems with the way the screen device is being selected. Also tried were the entry points to the Toolkit.beep() functionality to see if the alert sounds were coming from the Java side - appears not.

On another front, it was clear that not even the native side is receiving keyboard events. A coworker attributes this to a switch from an AWTView to a NSWindow in 7u6.

A selection of existing Oracle bugs has been found, which you can look up here:


Update 10/26:

Thanks to the comment by @maslovalex below regarding an Applet working on 7u5, I went back and painstakingly examined compatibility with the JDK versions for OSX:

  • 10.7.1 with 7u4: Fullscreen Works!
  • 10.7.1 with 7u5: Fullscreen Works!
  • 10.7.5 with 7u5: Fullscreen Works!
  • 10.7.5 with 7u6: Fullscreen Breaks :(

Combined with the other tests noted elsewhere, it's clear there was an issue introduced with 7u6 that remains in 7u7 and 7u9, and it affects both Lion 10.7 and Mountain Lion 10.8.

7u6 was a major milestone release, bringing full support of the JRE and JDK to Mac OS X and also including Java FX as part of the distribution. Further info is available in the Release Notes and the Roadmap. It's not tremendously surprising that such an issue could crop up as support shifts to Java FX.

The question becomes:

  1. Will Oracle fix this in a near-term release of the JDK? (If you have links to existing bugs, please include them here.)
  2. Is a workaround possible in the interim?

Other updates from today:

  • I incorporated the Apple extensions approach to fullscreen mode as an alternate path of exploration (updated sample code pending cleanup). The good news: input works! The bad news: there really don't seem to be any kiosking/isolation options.
    I tried killing the Dock - directly or with an App - as I understand the Dock is responsible for Command-Tab app switching, Mission Control, and Launch Pad, only to find out that it's responsible for the handling of fullscreen apps as well! As such, the Java calls become non-functional and never return.
    If there's a way to disable Command-Tab (and Mission Control and Launchpad and Spaces) without affecting the Dock's fullscreen handling, that would be extremely useful. Alternatively, one can try to remap certain keys such as Command, but that will affect the ability to use that modifier elsewhere in the program and the system itself (not exactly ideal, when you need to Command-C to copy some text).

  • I've had no luck with KeyListeners (I'm not receiving any callbacks), but I have a few more options to try.

  • Based on a coworker's suggestion, I tried ((sun.lwawt.macosx.LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive() via reflection. The idea was that it:
    is a native method with the comment "Returns true if the application (one of its windows) owns keyboard focus.". Calls to this method were added in CPlatformWindow.java in the past few months related to focus logic. If it returns false in your test code, it's probably part of the problem.
    Unfortunately, everywhere I checked it, the method returned true. So even according to the low level system, my windows should have keyboard focus.

  • My previous optimism regarding the JAlbum fix has been dashed. The developer posted a response on their forum that explains how they simply removed proper fullscreen support on OS X while running Java 7. They have a bug into Oracle (and I'm hoping to get the bug number).


Update 10/25:

I have now also tried Java 7u9 on Lion 10.7.4 and have seen the exact same issue, so it's JDK- not OS-specific.

The core question has become whether you can embed in a fullscreen window core Swing Components that have default handling for keyboard input (JTextField/JTextArea or even editable combo boxes) and expect them to behave normally (without having to resort to rebuilding their basic key bindings manually). Also in question is whether other stalwarts of windowed layouts, such as using tab for focus traversal, should work.

The ideal goal would be to have the ability take a windowed Swing app with all of its buttons, tabs, fields, etc. and run it in fullscreen exclusive/kiosk mode with most functionality intact. (Previously, I have seen that Dialog pop ups or ComboBox drop downs do not function in fullscreen on Java 6 on OS X, but other Components behave fine.)

I'll be looking into the eawt FullScreen capabilities, which will be interesting if they support kiosk lock down options, such as eliminating Command-Tab application switching.


Original Question:

I have a Swing app that for years has supported FullScreen (exclusive) mode on Mac OS X up through Java 6. I've been doing compatibility testing with the latest Mountain Lion release (10.8.2 Supplemental) and Oracle's JDK 7 and noticed a glaring issue while in that mode: mouse movement and clicks work fine, but keyboard input is not delivered to the components.

(I've narrowed this down in a test case below to not being able to type into a simple JTextField while in fullscreen mode.)

One symptom is that each key press results in a system beep, as if the OS is disallowing keyboard events from being delivered to the application.

Separately, my application has an exit hook installed, and the Command-Q combo will trigger that hook - it's clear that the OS is listening to standard key combos.

I have tested this separately on three different Macs with various installs:

  • On Apple Java 6u35 and 6u37: both windowed and fullscreen modes receive input.
  • On Oracle Java 7u7 and 7u9: windowed mode works as expected while fullscreen has the symptoms above.

This may have been previously reported: Java Graphics Full Screen Mode not Registering Keyboard Input. However, that question is not specific about the Java version or platform.

Additional searching has turned up a separate fullscreen option introduced in Lion: Fullscreen feature for Java Apps on OSX Lion. I have yet to try using this approach, as keyboard input seems integral to the target use cases of FullScreen Exclusive mode, such as games.

There is some mention in the JavaDoc for this mode that input methods might be disabled. I tried to call the suggested Component.enableInputMethods(false), but it seemed to have no effect.

I'm somewhat optimistic that there's a solution to this issue based on an entry in the release notes of a Java app I came across (JAlbum). A stated fix for 10.10.6: "Keyboard support wasn't working when running the full screen slide show on Mac and Java 7"

My test case is below. It is lightly modified from the second example in this issue (which, unmodified, also exhibits my problem): How to handle events from keyboard and mouse in full screen exclusive mode in java? In particular, it adds a button to toggle fullscreen.

import java.lang.reflect.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;

/** @see https://stackoverflow.com/questions/13064607/ */
public class FullScreenTest extends JPanel {
    private GraphicsDevice dev = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
    private JFrame f = new JFrame("FullScreenTest");

    private static final String EXIT = "Exit";
    private Action exit = new AbstractAction(EXIT) {
        @Override
        public void actionPerformed(ActionEvent e) {
            Object o = dev.getFullScreenWindow();
            if(o != null) {
                dev.setFullScreenWindow(null);
            }
            f.dispatchEvent(new WindowEvent(f, WindowEvent.WINDOW_CLOSING));
        }
    };
    private JButton exitBTN = new JButton(exit);

    private JTextField jtf = new JTextField("Uneditable in FullScreen with Java7u6+ on Mac OS X 10.7.3+");

    private JLabel keystrokeLabel = new JLabel("(Last Modifier+Key Pressed in JTextField)");

    private JLabel jtfFocusLabel = new JLabel("(JTextField Focus State)");

    private JLabel focusLabel = new JLabel("(Focused Component Hierarchy)");

    private JCheckBox useOSXFullScreenCB = new JCheckBox("Use Lion-Style FullScreen Mode");

    private JCheckBox useWorkaroundCB = new JCheckBox("Use Visibility Workaround to Restore 1st Responder Window");

    private static final String TOGGLE = "Toggle FullScreen (Command-T or Enter)"; 
    private Action toggle = new AbstractAction(TOGGLE) {
        @Override
        public void actionPerformed(ActionEvent e) {
            Object o = dev.getFullScreenWindow();
            if(o == null) {
                f.pack();

                /** 
                 * !! Neither of these calls seem to have any later effect.  
                 * One exception: I have a report of a 
                 * Mini going into an unrecoverable black screen without setVisible(true);  
                 * May be only a Java 6 compatibility issue.  !!
                 */
                //f.setVisible(true);
                //f.setVisible(false);

                if(!useOSXFullScreenCB.isSelected()) {
                    // No keyboard input after this call unless workaround is used
                    dev.setFullScreenWindow(f);

                    /**
                     * Workaround provided by Leonid Romanov at Oracle.
                     */
                    if(useWorkaroundCB.isSelected()) {
                        f.setVisible(false);
                        f.setVisible(true);
                        //Not necessary to invoke later...
                        /*SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                f.setVisible(false);
                                f.setVisible(true);
                            }
                        });*/
                    }
                }
                else {
                    toggleOSXFullscreen(f);
                }
            }
            else {
                dev.setFullScreenWindow(null);
                f.pack();
                f.setVisible(true);
            }

            isAppActive();
        }
    };
    private JButton toggleBTN = new JButton(toggle);

    public FullScreenTest() {            
        // -- Layout --
        this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));

        exitBTN.setAlignmentX(JComponent.CENTER_ALIGNMENT);
        exitBTN.setMaximumSize(new Dimension(Short.MAX_VALUE, 50));
        this.add(exitBTN);

        jtf.setAlignmentX(JComponent.CENTER_ALIGNMENT);
        jtf.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
        this.add(jtf);

        keystrokeLabel.setAlignmentX(JComponent.CENTER_ALIGNMENT);
        keystrokeLabel.setMaximumSize(new Dimension(Short.MAX_VALUE, 50));
        keystrokeLabel.setHorizontalAlignment(SwingConstants.CENTER);
        keystrokeLabel.setForeground(Color.DARK_GRAY);
        this.add(keystrokeLabel);

        jtfFocusLabel.setAlignmentX(JComponent.CENTER_ALIGNMENT);
        jtfFocusLabel.setMaximumSize(new Dimension(Short.MAX_VALUE, 50));
        jtfFocusLabel.setHorizontalAlignment(SwingConstants.CENTER);
        jtfFocusLabel.setForeground(Color.DARK_GRAY);
        this.add(jtfFocusLabel);

        focusLabel.setAlignmentX(JComponent.CENTER_ALIGNMENT);
        focusLabel.setMaximumSize(new Dimension(Short.MAX_VALUE, 50));
        focusLabel.setHorizontalAlignment(SwingConstants.CENTER);
        focusLabel.setForeground(Color.DARK_GRAY);
        this.add(focusLabel);

        useOSXFullScreenCB.setAlignmentX(JComponent.CENTER_ALIGNMENT);
        useOSXFullScreenCB.setMaximumSize(new Dimension(Short.MAX_VALUE, 50));
        useOSXFullScreenCB.setHorizontalAlignment(SwingConstants.CENTER);
        this.add(useOSXFullScreenCB);

        useWorkaroundCB.setAlignmentX(JComponent.CENTER_ALIGNMENT);
        useWorkaroundCB.setMaximumSize(new Dimension(Short.MAX_VALUE, 50));
        useWorkaroundCB.setHorizontalAlignment(SwingConstants.CENTER);
        this.add(useWorkaroundCB);

        toggleBTN.setAlignmentX(JComponent.CENTER_ALIGNMENT);
        toggleBTN.setMaximumSize(new Dimension(Short.MAX_VALUE, 50));
        this.add(toggleBTN);

        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setResizable(false);
        f.setUndecorated(true);
        f.add(this);
        f.pack();

        enableOSXFullscreen(f);

        // -- Listeners --

        // Default BTN set to see how input maps respond in fullscreen
        f.getRootPane().setDefaultButton(toggleBTN);

        // Explicit input map test with Command-T toggle action from anywhere in the window
        this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), 
                toggle.getValue(Action.NAME));
        this.getActionMap().put(toggle.getValue(Action.NAME), toggle);

        // KeyListener test
        jtf.addKeyListener(new KeyAdapter() {                                                                                                                                                                                                                                                    
            public void keyPressed(KeyEvent e) {                                                                                                                                                                                                                                                  
                String ktext = "KeyPressed: "+e.getKeyModifiersText(e.getModifiers()) + "_"+ e.getKeyText(e.getKeyCode());
                keystrokeLabel.setText(ktext);
                System.out.println(ktext);
            }
        });

        // FocusListener test
        jtf.addFocusListener(new FocusListener() {
            public void focusGained(FocusEvent fe) {
                focused(fe);
            }
            public void focusLost(FocusEvent fe) {
                focused(fe);
            }
            private void focused(FocusEvent fe) {
                boolean allGood = jtf.hasFocus() && jtf.isEditable() && jtf.isEnabled();
                jtfFocusLabel.setText("JTextField has focus (and is enabled/editable): " + allGood);
                isAppActive();
            }
        });

        // Keyboard Focus Manager
        KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        focusManager.addPropertyChangeListener(new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent e) {
                if (!("focusOwner".equals(e.getPropertyName()))) return;
                Component comp = (Component)e.getNewValue();
                if(comp == null) {
                    focusLabel.setText("(No Component Focused)");
                    return;
                }
                String label = comp.getClass().getName();
                while(true) {
                    comp = comp.getParent();
                    if(comp == null) break;
                    label = comp.getClass().getSimpleName() + " -> " + label;
                }
                focusLabel.setText("Focus Hierarchy: " + label);
                isAppActive();
            }
        });
    }

    /**
     * Hint that this Window can enter fullscreen.  Only need to call this once per Window.
     * @param window
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static 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 e1) {
        } catch (Exception e) {
            System.out.println("Failed to enable Mac Fullscreen: "+e);
        }
    }

    /**
     * Toggle OSX fullscreen Window state. Must call enableOSXFullscreen first.
     * Reflection version of: com.apple.eawt.Application.getApplication().requestToggleFullScreen(f);
     * @param window
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static void toggleOSXFullscreen(Window window) {
        try {
            Class appClass = Class.forName("com.apple.eawt.Application");

            Method method = appClass.getMethod("getApplication");
            Object appInstance = method.invoke(appClass);

            Class params[] = new Class[]{Window.class};
            method = appClass.getMethod("requestToggleFullScreen", params);
            method.invoke(appInstance, window);
        } catch (ClassNotFoundException e1) {
        } catch (Exception e) {
            System.out.println("Failed to toggle Mac Fullscreen: "+e);
        }
    }

    /**
     * Quick check of the low-level window focus state based on Apple's Javadoc:
     *  "Returns true if the application (one of its windows) owns keyboard focus."
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static void isAppActive() {
        try {
            Class util = Class.forName("sun.lwawt.macosx.LWCToolkit");
            Method method = util.getMethod("isApplicationActive");
            Object obj = method.invoke(Toolkit.getDefaultToolkit());
            System.out.println("AppActive: "+obj);
        } catch (ClassNotFoundException e1) {
        } catch (Exception e) {
            System.out.println("Failed to check App: "+e);
        }
    }

    public static void main(String[] args) {
        System.out.println("Java Version: " + System.getProperty("java.version"));
        System.out.println("OS Version: " + System.getProperty("os.version"));

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                FullScreenTest fst = new FullScreenTest();
                if(!fst.dev.isFullScreenSupported()) {
                    System.out.println("FullScreen not supported on this graphics device.  Exiting.");
                    System.exit(0);
                }
                fst.toggle.actionPerformed(null);
            }
        });
    }
}

解决方案

Instead, use key bindings, as shown in this FullScreenTest. Also, consider a DocumentListener, shown here, for text components.

这篇关于FullScreen Swing组件无法在Mac OS X Mountain Lion上的Java 7上接收键盘输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆