2016-12-30 3 views
13

Я работаю над игрой с использованием Swing, и я использую KeyBindings для ввода с клавиатуры.Java Swing KeyBindings перестает работать только на Mac

У меня возникли проблемы, когда KeyBindings перестают отвечать. Это происходит каждый раз, когда я запускаю приложение, но, насколько я могу судить, это не когда происходит определенная цепочка событий. KeyBindings просто прекращают прием ввода с клавиатуры. Я также использую ввод мыши, который продолжает работать, поэтому я знаю, что он не связан с вводом в целом.

Некоторые вещи, которые я пробовал:

  • сделал, что мой объект не мусора
  • искал какой-либо причине проблема возникает (например: после определенного количества времени, определенное сочетание клавиш прессованные), к которому я мог бы найти ни
  • пытался не использовать KeyListener вместо

ни один из них работал.

Затем я скопировал проект (без изменения какого-либо кода) на машину Windows, и после тестирования я не мог решить проблему один раз. Я не вставлял код здесь, потому что я на 99% уверен, что это не связано с моим кодом, но связано с операционной системой, в которой он работает.

Это проблема с macOS или JDK для Mac или с чем-то еще, о чем я не знаю?

Я использую обновление JDK версии 8 112, на компьютере работает macOS Sierra версии 10.12.2.

Кажется, у кого-то еще был same problem Я сейчас делаю, но у них никогда не было ответа.

EDIT

Вот пример кода, где возникла проблема:

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 - _It связано с моим mac спасибо в любом случае. - user5637682 13 декабря в 12: 21_ – anacron

+0

Я видел это, но, к сожалению, пользователь не опубликовал решение проблемы, если нашел один – kneedhelp

+0

Без вашего [mcve], как кто-нибудь может воспроизвести ваш результат? – trashgod

ответ

6

Вы можете подумать, что это ошибка в MAC, в то время как это не потому, что MAC имеет функцию вторичного ключи.
Поскольку вы являетесь пользователем MAC, я надеюсь, что вы знаете об этой функции. Эта функция может быть причиной проблемы.
Вторичная ключевая особенность MAC: используется, когда нажатие клавиши буквы будет отображать варианты этой буквы, например, удерживание «u» для получения «ü». Это полезно при написании неанглийских слов.

Существует простой способ взять под контроль и изменить поведение длинного нажатия клавиш, чтобы удовлетворить ваши потребности.

Открыть терминал приложение и записи:

defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false 

Затем перезагрузите любое открытое приложение, в котором вы хотите этот параметр, чтобы активировать.

ВОЗВРАТ НАЗАД: Просто, просто добавьте true вместо false к предыдущей команде, как это:

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, я обнаружил, что проблема кроется в том, что это было бы более эффективным, чтобы реализовать ее в управляемом событиями образом, я взял на себя смелость изменить свой код немного. Вместе с решением Hussain Mir предлагает решение, оно должно решить вашу проблему.

Вы также можете обрабатывать клавиши, повторяя себя, например, начиная таймер при нажатии клавиши и останавливая его при отпускании клавиши, но тогда поведение нажатия клавиш будет отличаться между 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()); 
    } 
} 
Смежные вопросы