2016-12-30 65 views
13

我正在使用Swing进行游戏,并使用KeyBindings从键盘输入。Java Swing KeyBindings仅在Mac上停止工作

我遇到了KeyBindings停止响应的问题。每次运行应用程序时都会发生这种情况,但据我所知,并不是发生某些事件时。 KeyBindings停止接收来自键盘的输入。我也使用鼠标输入,它继续工作,所以我知道它通常与输入无关。

有些事情我已经试过:

  • 确信我对象没有被垃圾收集
  • 看了由于某种原因出现问题(例如:一定量的时间后,一组组合键按下),而我能找到没有
  • 试图使用这些工作了KeyListener代替

无。

然后,我将项目(无需更改任何代码)复制到Windows机器,并且在测试之后,我无法将问题发生一次。我没有在这里粘贴代码,因为我99%的积极性,这与我的代码无关,但与它运行的操作系统有关。

这是MacOS或JDK for Mac或其他我不知道的问题吗?

我正在使用JDK版本8更新112,计算机正在运行macOS Sierra版本10.12.2。

看来别人有我现在做的same problem,但他们从来没有得到答案。

编辑

这里就是发生问题的代码示例:

import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.awt.image.BufferedImage; 

import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.KeyStroke; 
import javax.swing.SwingUtilities; 
import javax.swing.Timer; 

//an example of the problem where the keyboard stops receiving input randomly 
public class ProblemExample extends JPanel { 
    private static final long serialVersionUID = 1L; 

    private int xPos = 200, yPos = 200; 
    private boolean wKey, aKey, sKey, dKey; 
    private BufferedImage image; //sprite 

    public ProblemExample() { 
     JFrame frame = new JFrame(); 
     frame.add(this); 
     frame.pack(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setResizable(false); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 

     //makes the sprite a red square 
     image = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB); 
     int[] redPixels = new int[50 * 50]; 
     for (int i = 0; i < redPixels.length; i++) { 
      redPixels[i] = 0xffff0000; 
     } 
     image.setRGB(0, 0, 50, 50, redPixels, 0, 50); 
     initializeKeys(); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(800, 600); 
    } 

    //sets up Key Bindings 
    private void initializeKeys() { 
     final String W = "W", 
        A = "A", 
        S = "S", 
        D = "D", 
        PRESSED = "PRESSED", 
        RELEASED = "RELEASED"; 

     InputMap inputMap = this.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW); 
     ActionMap actionMap = this.getActionMap(); 

     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), W + PRESSED); 
     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), A + PRESSED); 
     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), S + PRESSED); 
     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), D + PRESSED); 
     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), W + RELEASED); 
     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), A + RELEASED); 
     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), S + RELEASED); 
     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), D + RELEASED); 

     Action wActionPressed = new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       wKey = true; 
      } 
     }; 
     Action aActionPressed = new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       aKey = true; 
      } 
     }; 
     Action sActionPressed = new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       sKey = true; 
      } 
     }; 
     Action dActionPressed = new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       dKey = true; 
      } 
     }; 
     Action wActionReleased = new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       wKey = false; 
      } 
     }; 
     Action aActionReleased = new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       aKey = false; 
      } 
     }; 
     Action sActionReleased = new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       sKey = false; 
      } 
     }; 
     Action dActionReleased = new AbstractAction() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       dKey = false; 
      } 
     }; 

     actionMap.put(W + PRESSED, wActionPressed); 
     actionMap.put(A + PRESSED, aActionPressed); 
     actionMap.put(S + PRESSED, sActionPressed); 
     actionMap.put(D + PRESSED, dActionPressed); 
     actionMap.put(W + RELEASED, wActionReleased); 
     actionMap.put(A + RELEASED, aActionReleased); 
     actionMap.put(S + RELEASED, sActionReleased); 
     actionMap.put(D + RELEASED, dActionReleased); 
    } 

    public void loop() { 
     if (wKey) yPos -= 5; 
     if (aKey) xPos -= 5; 
     if (sKey) yPos += 5; 
     if (dKey) xPos += 5; 
     repaint(); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     g.drawImage(image, xPos, yPos, null); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       ProblemExample example = new ProblemExample(); 
       Timer timer = new Timer(60, new ActionListener() { 
        @Override 
        public void actionPerformed(ActionEvent e) { 
         example.loop(); 
        } 
       }); 
       timer.start(); 
      } 
     }); 
    } 

} 
+1

看起来像用户说,问题是与Mac - _它与我的Mac有关,无论如何。 - user5637682 12月13日在12:21_ – anacron

+0

我看到了,但不幸的是,用户没有发布解决方案的问题,如果他们发现一个 – kneedhelp

+0

没有你的[mcve],其他人怎么能重现你的结果? – trashgod

回答

6

你也许会认为这是MAC的错误,而不是因为MAC具有辅助功能钥匙
因为你是MAC的用户,我希望你知道这个功能。此功能可能是原因您的问题。
使用MAC的辅助键功能:用于按住一个字母键将显示该字母的变化,如按住“u”以获得“ü”。这在拼写非英语单词时非常方便。

有一种简单的方法来控制和改变长按键的行为以适应您的需求。

打开终端应用程序,并写:

defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false 

然后,重新启动要在其中该设置激活所有打开的应用程序。

BACK回复:只是,只是代替false添加true到前面的命令是这样的:

defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool true 

UPDATE:
可以加快重点重复率或降低在保持键开始重复之前延迟,进入系统偏好设置并在键盘标题下进行更改。

+0

如果我要发布此应用程序和一些用户将它们下载到他们的Mac上,这会对他们造成问题吗?如果是这样,我可以为他们禁用此功能吗? – kneedhelp

+1

@kneedhelp是的,你可以。使用java.lang.Runtime.exec()将设置更改为false,然后当您的应用程序退出时,将设置更改回原始(true)。如果你不知道如何使用这个,这里是我的答案http://stackoverflow.com/questions/40882808/java-how-to-delete-a-file-that-has-the-immutable-bit-set/ 41140860#41140860 –

+0

非常感谢! – kneedhelp

1

除了Tahir Hussain Mir关于更改Mac键设置的建议之外,我发现问题在于循环,以事件驱动的方式实现它会更有效率,所以我冒昧地更改代码一点点。与侯赛因米尔一起提出解决方案,它应该解决你的问题。

您还可以自己处理按键重复操作,例如,通过按键启动计时器并在按键释放时停止计时,但是Windows和Mac之间的按键行为会有所不同,这不是您真正的方式想去。

package swing; 

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import java.awt.image.BufferedImage; 

//an example of the problem where the keyboard stops receiving input randomly 
public class SOMacKeyBindings extends JPanel 
{ 
    private BufferedImage image; //sprite 
    private Point point = new Point(200, 200); 
    private int steps = 5; 

    private class KeyAction extends AbstractAction 
    { 
     private Runnable runnable; 

     public KeyAction(Runnable runnable) 
     { 
      this.runnable = runnable; 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) 
     { 
      runnable.run(); 
     } 
    } 

    public SOMacKeyBindings() 
    { 
     JFrame frame = new JFrame(); 
     frame.add(this); 
     frame.pack(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setResizable(false); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 

     //makes the sprite a red square 
     image = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB); 
     int[] redPixels = new int[50 * 50]; 
     for (int i = 0; i < redPixels.length; i++) 
     { 
      redPixels[i] = 0xffff0000; 
     } 
     image.setRGB(0, 0, 50, 50, redPixels, 0, 50); 
     initializeKeys(); 
    } 

    @Override 
    public Dimension getPreferredSize() 
    { 
     return new Dimension(800, 600); 
    } 

    //sets up Key Bindings 
    private void initializeKeys() 
    { 
     final String W = "W", 
       A = "A", 
       S = "S", 
       D = "D", 
       PRESSED = "PRESSED"; 

     InputMap inputMap = this.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW); 
     ActionMap actionMap = this.getActionMap(); 

     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), W + PRESSED); 
     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), A + PRESSED); 
     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), S + PRESSED); 
     inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), D + PRESSED); 

     actionMap.put(W + PRESSED, new KeyAction(() -> { point.y -= steps; repaint(); })); 
     actionMap.put(A + PRESSED, new KeyAction(() -> { point.x -= steps; repaint(); })); 
     actionMap.put(S + PRESSED, new KeyAction(() -> { point.y += steps; repaint(); })); 
     actionMap.put(D + PRESSED, new KeyAction(() -> { point.x += steps; repaint(); })); 
    } 

    @Override 
    public void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 
     g.drawImage(image, point.x, point.y, null); 
    } 

    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(() -> new SOMacKeyBindings()); 
    } 
}