/* * The MIT License * * Copyright 2016 summers. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package net.saga.console.chip8; import net.saga.console.chip8.util.Chip8DisplayPanel; import net.saga.console.chip8.util.Chip8Utils; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.File; import java.io.IOException; import static java.lang.Thread.sleep; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import net.saga.console.chip8.util.Input; /** * * @author summers */ public class SwingMain extends javax.swing.JFrame implements KeyListener { private static final long serialVersionUID = 1L; final JFileChooser fc = new JFileChooser(); private Chip8 chip8; private boolean running = false; private boolean pause = false; private boolean step = false; /** * Creates new form SwingMain */ public SwingMain() { this.chip8Runner = new Thread(() -> { while (true) { try { if (running) { if (pause == false || step) { step = false; chip8.cycle(); ((Chip8Model) jTable1.getModel()).update(chip8); } outputPanel.repaint(); } sleep(1); } catch (InterruptedException ex) { Logger.getLogger(SwingMain.class.getName()).log(Level.SEVERE, null, ex); } } }); initComponents(); KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); manager.addKeyEventDispatcher(new KeyEventDispatcher() { @Override public boolean dispatchKeyEvent(KeyEvent e) { switch (e.getID()) { case KeyEvent.KEY_PRESSED: Input.press(e.getKeyChar() + ""); break; case KeyEvent.KEY_RELEASED: Input.unpress(); break; default: break; } return false; } }); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jPanel1 = new javax.swing.JPanel(); openButton = new javax.swing.JButton(); aboutButton = new javax.swing.JButton(); inputMapButton = new javax.swing.JButton(); outputPanel = new Chip8DisplayPanel(); jScrollPane1 = new javax.swing.JScrollPane(); jTable1 = new javax.swing.JTable(); jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); jButton3 = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setBackground(java.awt.Color.white); setMinimumSize(new java.awt.Dimension(286, 175)); addKeyListener(new java.awt.event.KeyAdapter() { public void keyPressed(java.awt.event.KeyEvent evt) { formKeyPressed(evt); } public void keyReleased(java.awt.event.KeyEvent evt) { formKeyReleased(evt); } }); jPanel1.setBackground(new java.awt.Color(51, 51, 255)); outputPanel.addKeyListener(SwingMain.this); openButton.setBackground(new java.awt.Color(102, 102, 255)); openButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/open.png"))); // NOI18N openButton.setToolTipText("Open Binary"); openButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { openButtonActionPerformed(evt); } }); aboutButton.setBackground(new java.awt.Color(102, 102, 255)); aboutButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/about.png"))); // NOI18N aboutButton.setToolTipText("About"); aboutButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { aboutButtonActionPerformed(evt); } }); inputMapButton.setBackground(new java.awt.Color(102, 102, 255)); inputMapButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/input.png"))); // NOI18N inputMapButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { inputMapButtonActionPerformed(evt); } }); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addComponent(openButton, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(aboutButton, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(inputMapButton, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(inputMapButton, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(aboutButton, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openButton, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); outputPanel.setMinimumSize(new java.awt.Dimension(64, 32)); outputPanel.addKeyListener(SwingMain.this); javax.swing.GroupLayout outputPanelLayout = new javax.swing.GroupLayout(outputPanel); outputPanel.setLayout(outputPanelLayout); outputPanelLayout.setHorizontalGroup( outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 697, Short.MAX_VALUE) ); outputPanelLayout.setVerticalGroup( outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 0, Short.MAX_VALUE) ); jTable1.setModel(new Chip8Model()); jScrollPane1.setViewportView(jTable1); jButton1.setBackground(new java.awt.Color(102, 102, 255)); jButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/play.png"))); // NOI18N jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton1ActionPerformed(evt); } }); jButton2.setBackground(new java.awt.Color(102, 102, 255)); jButton2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/pause.png"))); // NOI18N jButton2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton2ActionPerformed(evt); } }); jButton3.setBackground(new java.awt.Color(102, 102, 255)); jButton3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/skip.png"))); // NOI18N jButton3.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton3ActionPerformed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(outputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 186, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() .addGap(2, 2, 2) .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jButton3, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE))))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(outputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 456, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jButton3, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addContainerGap()) ); pack(); }// </editor-fold>//GEN-END:initComponents private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed if (evt.getSource() == openButton) { int returnVal = fc.showOpenDialog(SwingMain.this); if (returnVal == JFileChooser.APPROVE_OPTION) { try { running = false; File file = fc.getSelectedFile(); SwingMain.this.chip8 = Chip8Utils.createFromRom(file); restartEmulator(); } catch (IOException ex) { Logger.getLogger(SwingMain.class.getName()).log(Level.SEVERE, null, ex); JOptionPane.showMessageDialog(null, ex, "Error", JOptionPane.ERROR_MESSAGE); } } } }//GEN-LAST:event_openButtonActionPerformed private void aboutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutButtonActionPerformed JOptionPane.showMessageDialog(null, "Chip-8 in Java by secondsun. \n github.com/secondsun/chip8"); }//GEN-LAST:event_aboutButtonActionPerformed private void inputMapButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_inputMapButtonActionPerformed new InputMapping().setVisible(true); }//GEN-LAST:event_inputMapButtonActionPerformed private void formKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyPressed Input.press(evt.getKeyChar()); }//GEN-LAST:event_formKeyPressed private void formKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyReleased Input.unpress(); }//GEN-LAST:event_formKeyReleased private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed this.pause = true; }//GEN-LAST:event_jButton2ActionPerformed private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed this.pause = false; }//GEN-LAST:event_jButton1ActionPerformed private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed this.step = true; }//GEN-LAST:event_jButton3ActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { /* Set the Nimbus look and feel */ //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html */ try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(SwingMain.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (InstantiationException ex) { java.util.logging.Logger.getLogger(SwingMain.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { java.util.logging.Logger.getLogger(SwingMain.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(SwingMain.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } //</editor-fold> /* Create and display the form */ java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new SwingMain().setVisible(true); } }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton aboutButton; private javax.swing.JButton inputMapButton; private javax.swing.JButton jButton1; private javax.swing.JButton jButton2; private javax.swing.JButton jButton3; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTable jTable1; private javax.swing.JButton openButton; private javax.swing.JPanel outputPanel; // End of variables declaration//GEN-END:variables private void restartEmulator() { Chip8DisplayPanel panel = (Chip8DisplayPanel) outputPanel; panel.setChip8(chip8); if (!chip8Runner.isAlive()) { this.chip8Runner = new Thread(() -> { while (true) { try { if (running) { if (pause == false || step) { step = false; chip8.cycle(); ((Chip8Model) jTable1.getModel()).update(chip8); } outputPanel.repaint(); } sleep(1); } catch (InterruptedException ex) { Logger.getLogger(SwingMain.class.getName()).log(Level.SEVERE, null, ex); } } }); chip8Runner.start(); } running = true; } private Thread chip8Runner; @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { Input.press(e.getKeyChar()); } @Override public void keyReleased(KeyEvent e) { Input.unpress(); } }