MegaDrive3ButtonPad.java
     1: //========================================================================================
     2: //  MegaDrive3ButtonPad.java
     3: //    en:MEGA DRIVE 3 button pad
     4: //    ja:メガドラ3ボタンパッド
     5: //  Copyright (C) 2003-2024 Makoto Kamada
     6: //
     7: //  This file is part of the XEiJ (X68000 Emulator in Java).
     8: //  You can use, modify and redistribute the XEiJ if the conditions are met.
     9: //  Read the XEiJ License for more details.
    10: //  https://stdkmd.net/xeij/
    11: //========================================================================================
    12: 
    13: //メガドラパッド
    14: //
    15: //  配線図
    16: //                      JS
    17: //     IOA0    IOA1    IOA2    IOA3    VCC1
    18: //      ○ IOA5 ○ IOA6 ○ PC4  ○ GND  ○
    19: //     1│  ○ 2│  ○ 3│  ○ 4│  ○ 5│
    20: //      │ 6│  │ 7│  │ 8│  │ 9│  │
    21: //      │  │  │  └─┼┐│  │  │  │
    22: //      │  │  │  ┌─┼┼┘  │  │  │
    23: //      │  │  │  │  │└─┐│  │  │
    24: //      │  │  │  │  │  ┌┼┼─┘  │
    25: //      │  │  │  │  │  │└┼─┐  │
    26: //     1│  │ 2│  │ 3│  │ 4│  │ 5│
    27: //      ○ 6│  ○ 7│  ○ 8│  ○ 9│  ○
    28: //      U   ○  D   ○ 0/L  ○ 0/R  ○ VCC
    29: //         A/B     SEL     GND     ST/C
    30: //                      MD
    31: //
    32: //  データ
    33: //    +-------+---------------------------------------------------------------+
    34: //    | 出力  |                             入力                              |
    35: //    +-------+-------+-------+-------+-------+-------+-------+-------+-------+
    36: //    | pin8  |       | pin7  | pin6  |       | pin4  | pin3  | pin2  | pin1  |
    37: //    |       +-------+-------+-------+-------+-------+-------+-------+-------+
    38: //    |       |   7   |   6   |   5   |   4   |   3   |   2   |   1   |   0   |
    39: //    +-------+-------+-------+-------+-------+-------+-------+-------+-------+
    40: //    |   0   |   1   | START |   A   |   1   |   0   |   0   | DOWN  |  UP   |
    41: //    +-------+-------+-------+-------+-------+-------+-------+-------+-------+
    42: //    |   1   |   1   |   C   |   B   |   1   | RIGHT | LEFT  | DOWN  |  UP   |
    43: //    +-------+-------+-------+-------+-------+-------+-------+-------+-------+
    44: //    pin8の出力に合わせてpin1-4,6-7の入力が変化する
    45: //
    46: //  参考
    47: //    電脳倶楽部 067/B/MDPAD/M6PAD_AN.DOC
    48: //    電脳倶楽部 077/B/6B/T_EXPAD.DOC
    49: 
    50: package xeij;
    51: 
    52: import java.awt.*;
    53: import java.awt.event.*;
    54: import java.util.*;
    55: import javax.swing.*;
    56: import javax.swing.event.*;
    57: 
    58: //class MegaDrive3ButtonPad
    59: //  メガドラ3ボタンパッド
    60: public class MegaDrive3ButtonPad extends Joystick implements ActionListener, ChangeListener, FocusListener, XInput.GamepadListener, KeyListener {
    61: 
    62:   protected static final int UP_BIT            =  0;  //↑
    63:   protected static final int DOWN_BIT          =  1;  //↓
    64:   protected static final int LEFT_BIT          =  2;  //←
    65:   protected static final int RIGHT_BIT         =  3;  //→
    66:   protected static final int A_BIT             =  4;  //A
    67:   protected static final int B_BIT             =  5;  //B
    68:   protected static final int C_BIT             =  6;  //C
    69:   protected static final int START_BIT         =  7;  //START
    70:   protected static final int BUTTONS           =  8;  //ボタンの数
    71: 
    72:   protected static final int UP_MASK           = (1 << UP_BIT);
    73:   protected static final int DOWN_MASK         = (1 << DOWN_BIT);
    74:   protected static final int LEFT_MASK         = (1 << LEFT_BIT);
    75:   protected static final int RIGHT_MASK        = (1 << RIGHT_BIT);
    76:   protected static final int A_MASK            = (1 << A_BIT);
    77:   protected static final int B_MASK            = (1 << B_BIT);
    78:   protected static final int C_MASK            = (1 << C_BIT);
    79:   protected static final int START_MASK        = (1 << START_BIT);
    80: 
    81:   protected static final String[] BIT_TO_TEXT = {
    82:     "↑",
    83:     "↓",
    84:     "←",
    85:     "→",
    86:     "A",
    87:     "B",
    88:     "C",
    89:     "START",
    90:   };
    91: 
    92:   protected static final boolean[] BIT_TO_REPEATABLE = {
    93:     false,  //↑
    94:     false,  //↓
    95:     false,  //←
    96:     false,  //→
    97:     true,   //A
    98:     true,   //B
    99:     true,   //C
   100:     false,  //START
   101:   };
   102: 
   103:   protected static final int MAP_CODE     = BUTTONS * 0;  //XInputコードとキーコード
   104:   protected static final int MAP_REPEAT   = BUTTONS * 1;  //連射有効
   105:   protected static final int MAP_DELAY    = BUTTONS * 2;  //連射開始
   106:   protected static final int MAP_INTERVAL = BUTTONS * 3;  //連射間隔
   107:   protected static final int MAP_LENGTH   = BUTTONS * 4;
   108:   protected int[] map;
   109: 
   110:   protected int xinputFocusedButton;  //フォーカスされているXInputテキストフィールドの番号。-1=なし
   111:   protected long[] startTimeOf;  //連射開始時刻。ボタンが押されたとき初期化して押されている間だけ使う
   112:   protected int lastButtons;  //前回押されていたボタン。XInputを含む
   113:   protected int keyButtons;  //キーで押されているボタン
   114: 
   115:   protected int page;  //ページ
   116: 
   117:   protected JTextField[] xinputTextFieldOf = new JTextField[BUTTONS];
   118:   protected JTextField[] keyTextFieldOf = new JTextField[BUTTONS];
   119:   protected JCheckBox[] repeatCheckBoxOf = new JCheckBox[BUTTONS];
   120:   protected SpinnerNumberModel[] delayModelOf = new SpinnerNumberModel[BUTTONS];
   121:   protected JSpinner[] delaySpinnerOf = new JSpinner[BUTTONS];
   122:   protected SpinnerNumberModel[] intervalModelOf = new SpinnerNumberModel[BUTTONS];
   123:   protected JSpinner[] intervalSpinnerOf = new JSpinner[BUTTONS];
   124: 
   125:   //  map[i]=xCode<<16|keyCode
   126:   //  xCode=map[i]>>>16
   127:   //  keyCode=map[i]&65535
   128:   //  xCode=128|xIndex<<5|xBit
   129:   //  xIndex=(xCode>>5)&3
   130:   //  xBit=xCode&31
   131:   protected final int[][] defaultMaps = new int[][] {
   132:     {
   133:       (128 | 0 << 5 | XInput.UP_BIT     ) << 16 | KeyEvent.VK_UP,         //↑
   134:       (128 | 0 << 5 | XInput.DOWN_BIT   ) << 16 | KeyEvent.VK_DOWN,       //↓
   135:       (128 | 0 << 5 | XInput.LEFT_BIT   ) << 16 | KeyEvent.VK_LEFT,       //←
   136:       (128 | 0 << 5 | XInput.RIGHT_BIT  ) << 16 | KeyEvent.VK_RIGHT,      //→
   137:       (128 | 0 << 5 | XInput.A_BIT      ) << 16 | KeyEvent.VK_Z,          //A
   138:       (128 | 0 << 5 | XInput.B_BIT      ) << 16 | KeyEvent.VK_X,          //B
   139:       (128 | 0 << 5 | XInput.LB_BIT     ) << 16 | KeyEvent.VK_C,          //C
   140:       (128 | 0 << 5 | XInput.START_BIT  ) << 16 | KeyEvent.VK_R,          //START
   141:       0, 0, 0, 0,   0,   0,   0, 0,  //連射有効
   142:       0, 0, 0, 0,  50,  50 , 50, 0,  //連射開始
   143:       0, 0, 0, 0, 100, 100, 100, 0,  //連射間隔
   144:     },
   145:     {
   146:       (128 | 1 << 5 | XInput.UP_BIT     ) << 16 | KeyEvent.VK_UNDEFINED,  //↑
   147:       (128 | 1 << 5 | XInput.DOWN_BIT   ) << 16 | KeyEvent.VK_UNDEFINED,  //↓
   148:       (128 | 1 << 5 | XInput.LEFT_BIT   ) << 16 | KeyEvent.VK_UNDEFINED,  //←
   149:       (128 | 1 << 5 | XInput.RIGHT_BIT  ) << 16 | KeyEvent.VK_UNDEFINED,  //→
   150:       (128 | 1 << 5 | XInput.A_BIT      ) << 16 | KeyEvent.VK_UNDEFINED,  //A
   151:       (128 | 1 << 5 | XInput.B_BIT      ) << 16 | KeyEvent.VK_UNDEFINED,  //B
   152:       (128 | 1 << 5 | XInput.LB_BIT     ) << 16 | KeyEvent.VK_UNDEFINED,  //C
   153:       (128 | 1 << 5 | XInput.START_BIT  ) << 16 | KeyEvent.VK_UNDEFINED,  //START
   154:       0, 0, 0, 0,   0,   0,   0, 0,  //連射有効
   155:       0, 0, 0, 0,  50,  50 , 50, 0,  //連射開始
   156:       0, 0, 0, 0, 100, 100, 100, 0,  //連射間隔
   157:     },
   158:   };
   159: 
   160:   //new MegaDrive3ButtonPad (number)
   161:   //  コンストラクタ
   162:   //  number  枝番号。1~2
   163:   public MegaDrive3ButtonPad (int number) {
   164:     this.number = number;
   165:     id = "megadrive3button" + number;
   166:     nameEn = "MEGA DRIVE 3 button pad #" + number;
   167:     nameJa = "メガドラ 3 ボタンパッド #" + number;
   168:     map = new int[MAP_LENGTH];
   169:     int[] tempMap = Settings.sgsGetIntArray (id);
   170:     if (0 < tempMap.length && 0 <= tempMap[0]) {  //旧フォーマット
   171:       for (int i = 0; i < MAP_LENGTH; i++) {
   172:         map[i] = i < tempMap.length ? tempMap[i] : 0;
   173:       }
   174:       //間隔を倍にする
   175:       for (int i = 0; i < BUTTONS; i++) {
   176:         map[MAP_INTERVAL + i] = Math.min (INTERVAL_MAX, map[MAP_INTERVAL + i] << 1);
   177:       }
   178:     } else if (0 < tempMap.length && tempMap[0] == -2) {  //新フォーマット
   179:       for (int i = 0; i < MAP_LENGTH; i++) {
   180:         map[i] = i + 1 < tempMap.length ? tempMap[i + 1] : 0;
   181:       }
   182:     } else {  //初期値
   183:       System.arraycopy (defaultMaps[number - 1], 0,  //from
   184:                         map, 0,  //to
   185:                         MAP_LENGTH);  //length
   186:     }
   187:     if (PPI.PPI_XINPUT_ON) {
   188:       xinputFocusedButton = -1;
   189:     }
   190:     startTimeOf = new long[BUTTONS];
   191:     reset ();
   192:     configurationPanel = null;
   193:   }
   194: 
   195:   //tini ()
   196:   //  後始末
   197:   @Override public void tini () {
   198:     if (true &&  //false=初期値と同じでも出力して値を確認する
   199:         Arrays.equals (map, defaultMaps[number - 1])) {  //初期値と同じ
   200:       Settings.sgsPutIntArray (id, new int[0]);  //"none"ではなく""にする
   201:     } else {  //初期値と違う
   202:       int[] tempMap = new int[1 + MAP_LENGTH];
   203:       tempMap[0] = -2;  //新フォーマット
   204:       for (int i = 0; i < MAP_LENGTH; i++) {
   205:         tempMap[1 + i] = map[i];
   206:       }
   207:       Settings.sgsPutIntArray (id, tempMap);
   208:     }
   209:   }
   210: 
   211:   //reset ()
   212:   //  リセット。設定パネルが表示されるとき呼び出される
   213:   @Override public final void reset () {
   214:     lastButtons = 0;
   215:     keyButtons = 0;
   216:     page = 0;
   217:   }
   218: 
   219:   private void updateText () {
   220:     for (int i = 0; i < BUTTONS; i++) {
   221:       String text;
   222:       int xCode = map[MAP_CODE + i] >>> 16;
   223:       if (xCode == 0) {
   224:         text = Multilingual.mlnJapanese ? "なし" : "none";
   225:       } else {
   226:         int xIndex = (xCode >> 5) & 3;
   227:         int xBit = xCode & 31;
   228:         text = "#" + xIndex + " " + XInput.BIT_TO_TEXT[xBit];
   229:       }
   230:       xinputTextFieldOf[i].setText (text);
   231:       int keyCode = map[MAP_CODE + i] & 65535;
   232:       if (keyCode == 0) {
   233:         text = Multilingual.mlnJapanese ? "なし" : "none";
   234:       } else {
   235:         text = KeyEvent.getKeyText (keyCode);
   236:       }
   237:       keyTextFieldOf[i].setText (text);
   238:     }
   239:   }
   240: 
   241: 
   242:   //ボタンのアクションリスナー
   243:   @Override public void actionPerformed (ActionEvent ae) {
   244:     Object source = ae.getSource ();
   245:     String command = ae.getActionCommand ();
   246:     if (command.equals ("Reset to default values")) {  //初期値に戻す
   247:       if (Arrays.equals (map, defaultMaps[number - 1])) {  //初期値と同じ
   248:         JOptionPane.showMessageDialog (
   249:           null,
   250:           Multilingual.mlnJapanese ? nameJa + " の設定は初期値と同じです" : nameEn + " settings are equals to default values",
   251:           Multilingual.mlnJapanese ? "確認" : "Confirmation",
   252:           JOptionPane.PLAIN_MESSAGE);
   253:         return;
   254:       }
   255:       if (JOptionPane.showConfirmDialog (
   256:         null,
   257:         Multilingual.mlnJapanese ? nameJa + " の設定を初期値に戻しますか?" : "Do you want to reset " + nameEn + " settings to default values?",
   258:         Multilingual.mlnJapanese ? "確認" : "Confirmation",
   259:         JOptionPane.YES_NO_OPTION,
   260:         JOptionPane.PLAIN_MESSAGE) != JOptionPane.YES_OPTION) {
   261:         return;
   262:       }
   263:       System.arraycopy (defaultMaps[number - 1], 0,  //from
   264:                         map, 0,  //to
   265:                         MAP_LENGTH);  //length
   266:       updateText ();
   267:       for (int i = 0; i < BUTTONS; i++) {
   268:         if (BIT_TO_REPEATABLE[i]) {
   269:           repeatCheckBoxOf[i].setSelected (map[MAP_REPEAT + i] != 0);
   270:           delayModelOf[i].setValue (Math.max (DELAY_MIN, Math.min (DELAY_MAX, map[MAP_DELAY + i])));
   271:           intervalModelOf[i].setValue (Math.max (INTERVAL_MIN, Math.min (INTERVAL_MAX, map[MAP_INTERVAL + i])));
   272:         }
   273:       }
   274:     } else if (command.startsWith ("Repeat ")) {
   275:       int i = Integer.parseInt (command.substring (7));
   276:       map[MAP_REPEAT + i] = repeatCheckBoxOf[i].isSelected () ? 1 : 0;
   277:     } else {
   278:       System.out.println ("unknown action command " + command);
   279:     }
   280:   }
   281: 
   282: 
   283:   //スピナーのチェンジリスナー
   284:   @Override public void stateChanged (ChangeEvent ce) {
   285:     JSpinner spinner = (JSpinner) ce.getSource ();
   286:     String name = spinner.getName ();
   287:     if (name.startsWith ("Delay ")) {
   288:       int i = Integer.parseInt (name.substring (6));
   289:       map[MAP_DELAY + i] = delayModelOf[i].getNumber ().intValue ();
   290:     } else if (name.startsWith ("Interval ")) {
   291:       int i = Integer.parseInt (name.substring (9));
   292:       map[MAP_INTERVAL + i] = intervalModelOf[i].getNumber ().intValue ();
   293:     } else {
   294:       System.out.println ("unknown spinner name " + name);
   295:     }
   296:   }
   297: 
   298: 
   299:   //テキストフィールドのフォーカスリスナー
   300:   @Override public void focusGained (FocusEvent fe) {
   301:     Component component = fe.getComponent ();
   302:     String componentName = component.getName ();
   303:     int type = componentName.charAt (0);  //'x'または'k'
   304:     int i = Integer.parseInt (componentName.substring (1));
   305:     //背景色を変えて目立たさせる
   306:     component.setBackground (new Color (LnF.lnfRGB[6]));
   307:     if (PPI.PPI_XINPUT_ON && type == 'x') {  //XInput
   308:       //Gamepadリスナーを追加する
   309:       xinputFocusedButton = i;
   310:       if (PPI.ppiXInput != null) {
   311:         PPI.ppiXInput.addGamepadListener (this);
   312:       }
   313:     } else if (type == 'k') {  //キー
   314:     } else {
   315:       System.out.println ("unknown component name " + componentName);
   316:     }
   317:   }
   318:   @Override public void focusLost (FocusEvent fe) {
   319:     Component component = fe.getComponent ();
   320:     String componentName = component.getName ();
   321:     int type = componentName.charAt (0);  //'x'または'k'
   322:     int i = Integer.parseInt (componentName.substring (1));
   323:     //背景色を元に戻す
   324:     component.setBackground (null);
   325:     if (PPI.PPI_XINPUT_ON && type == 'x') {  //XInput
   326:       //Gamepadリスナーを削除する
   327:       if (PPI.ppiXInput != null) {
   328:         PPI.ppiXInput.removeGamepadListeners ();
   329:       }
   330:       xinputFocusedButton = -1;
   331:     } else if (type == 'k') {  //キー
   332:     } else {
   333:       System.out.println ("unknown component name " + componentName);
   334:     }
   335:   }
   336: 
   337: 
   338:   //Gamepadリスナー
   339:   @Override public void connected (XInput.Gamepad gamepad) {
   340:   }
   341:   @Override public void disconnected (XInput.Gamepad gamepad) {
   342:   }
   343:   @Override public void buttonPressed (XInput.Gamepad gamepad, int buttonMasks) {
   344:     if (buttonMasks == 0) {  //ないはず
   345:       return;
   346:     }
   347:     if (PPI.PPI_XINPUT_ON && 0 <= xinputFocusedButton) {  //フォーカスされているxinputのテキストフィールドがある
   348:       int xIndex = gamepad.getIndex ();
   349:       int xBit = Integer.numberOfTrailingZeros (buttonMasks);
   350:       int xCode = 128 | xIndex << 5 | xBit;
   351:       int keyCode = map[MAP_CODE + xinputFocusedButton] & 65535;
   352:       map[MAP_CODE + xinputFocusedButton] = xCode << 16 | keyCode;
   353:       //すべてのボタンのxIndexを更新する
   354:       //  インデックスを変更したいときボタンを1個割り当て直せば済む
   355:       for (int i = 0; i < BUTTONS; i++) {
   356:         int xCode2 = map[MAP_CODE + i] >>> 16;
   357:         if (xCode2 != 0) {
   358:           int keyCode2 = map[MAP_CODE + i] & 65535;
   359:           map[MAP_CODE + i] = ((xCode2 & ~(3 << 5)) | xIndex << 5) << 16 | keyCode2;
   360:         }
   361:       }
   362:       updateText ();
   363:     }
   364:   }
   365:   @Override public void buttonReleased (XInput.Gamepad gamepad, int buttonMasks) {
   366:   }
   367:   @Override public void leftStickMovedX (XInput.Gamepad gamepad) {
   368:   }
   369:   @Override public void leftStickMovedY (XInput.Gamepad gamepad) {
   370:   }
   371:   @Override public void leftTriggerMoved (XInput.Gamepad gamepad) {
   372:   }
   373:   @Override public void rightStickMovedX (XInput.Gamepad gamepad) {
   374:   }
   375:   @Override public void rightStickMovedY (XInput.Gamepad gamepad) {
   376:   }
   377:   @Override public void rightTriggerMoved (XInput.Gamepad gamepad) {
   378:   }
   379: 
   380: 
   381:   //テキストフィールドのキーリスナー
   382:   @Override public void keyPressed (KeyEvent ke) {
   383:     Component component = ke.getComponent ();
   384:     String componentName = component.getName ();
   385:     int type = componentName.charAt (0);  //'x'または'k'
   386:     int i = Integer.parseInt (componentName.substring (1));
   387:     int xCode = map[MAP_CODE + i] >>> 16;
   388:     int keyCode = map[MAP_CODE + i] & 65535;
   389:     if (PPI.PPI_XINPUT_ON && type == 'x') {  //XInput
   390:       if (ke.getKeyCode () == KeyEvent.VK_ESCAPE) {  //Escキーは解除とみなす
   391:         xCode = 0;
   392:       }
   393:     } else if (type == 'k') {  //キー
   394:       if (ke.getKeyCode () == KeyEvent.VK_ESCAPE) {  //Escキーは解除とみなす
   395:         keyCode = KeyEvent.VK_UNDEFINED;
   396:       } else {  //それ以外は割り当てを変更する
   397:         keyCode = ke.getKeyCode ();
   398:       }
   399:     } else {
   400:       System.out.println ("unknown component name " + componentName);
   401:     }
   402:     map[MAP_CODE + i] = xCode << 16 | keyCode;
   403:     updateText ();
   404:     ke.consume ();
   405:   }
   406:   @Override public void keyReleased (KeyEvent ke) {
   407:     ke.consume ();
   408:   }
   409:   @Override public void keyTyped (KeyEvent ke) {
   410:     ke.consume ();
   411:   }
   412: 
   413: 
   414:   //configurationPanel = getConfigurationPanel ()
   415:   //  設定パネルを返す。初回は作る
   416:   @Override public JComponent getConfigurationPanel () {
   417: 
   418:     if (configurationPanel != null) {
   419:       return configurationPanel;
   420:     }
   421: 
   422:     for (int i = 0; i < BUTTONS; i++) {
   423:       xinputTextFieldOf[i] =
   424:         ComponentFactory.setEnabled (
   425:           ComponentFactory.addListener (
   426:             ComponentFactory.addListener (
   427:               ComponentFactory.setHorizontalAlignment (
   428:                 ComponentFactory.setName (
   429:                   ComponentFactory.createTextField ("", 8),
   430:                   "x" + i),
   431:                 JTextField.CENTER),
   432:               (KeyListener) this),
   433:             (FocusListener) this),
   434:           PPI.PPI_XINPUT_ON && XEiJ.prgWindllLoaded);
   435:       keyTextFieldOf[i] =
   436:         ComponentFactory.addListener (
   437:           ComponentFactory.addListener (
   438:             ComponentFactory.setHorizontalAlignment (
   439:               ComponentFactory.setName (
   440:                 ComponentFactory.createTextField ("", 8),
   441:                 "k" + i),
   442:               JTextField.CENTER),
   443:             (KeyListener) this),
   444:           (FocusListener) this);
   445:       if (BIT_TO_REPEATABLE[i]) {
   446:         repeatCheckBoxOf[i] =
   447:           ComponentFactory.setText (
   448:             ComponentFactory.createCheckBox (map[MAP_REPEAT + i] != 0, "Repeat " + i, (ActionListener) this),
   449:             "");
   450:         delayModelOf[i] =
   451:           new SpinnerNumberModel (Math.max (DELAY_MIN, Math.min (DELAY_MAX, map[MAP_DELAY + i])),
   452:                                   DELAY_MIN, DELAY_MAX, DELAY_STEP);
   453:         delaySpinnerOf[i] =
   454:           ComponentFactory.setName (
   455:             ComponentFactory.createNumberSpinner (delayModelOf[i], 4, (ChangeListener) this),
   456:             "Delay " + i);
   457:         intervalModelOf[i] =
   458:           new SpinnerNumberModel (Math.max (INTERVAL_MIN, Math.min (INTERVAL_MAX, map[MAP_INTERVAL + i])),
   459:                                   INTERVAL_MIN, INTERVAL_MAX, INTERVAL_STEP);
   460:         intervalSpinnerOf[i] =
   461:           ComponentFactory.setName (
   462:             ComponentFactory.createNumberSpinner (intervalModelOf[i], 4, (ChangeListener) this),
   463:             "Interval " + i);
   464:       }
   465:     }
   466:     updateText ();
   467: 
   468:     //    0    1       2        3        4      5       6
   469:     //       Button  XInput  Keyboard  Burst  Delay  Interval
   470:     //    ---------------------------------------------------
   471:     //    #    *       *        *        *      *       *
   472:     ArrayList<Object> cellList = new ArrayList<Object> ();
   473:     //
   474:     cellList.add (null);
   475:     cellList.add (Multilingual.mlnText (ComponentFactory.createLabel ("Button"), "ja", "ボタン"));
   476:     cellList.add (ComponentFactory.createLabel ("XInput"));
   477:     cellList.add (Multilingual.mlnText (ComponentFactory.createLabel ("Keyboard"), "ja", "キーボード"));
   478:     cellList.add (Multilingual.mlnText (ComponentFactory.createLabel ("Burst"), "ja", "連射"));
   479:     cellList.add (Multilingual.mlnText (ComponentFactory.createLabel ("Delay (ms)"), "ja", "開始 (ms)"));
   480:     cellList.add (Multilingual.mlnText (ComponentFactory.createLabel ("Interval (ms)"), "ja", "間隔 (ms)"));
   481:     //
   482:     cellList.add (ComponentFactory.createHorizontalSeparator ());
   483:     //
   484:     for (int i = 0; i < BUTTONS; i++) {
   485:       cellList.add (String.valueOf (1 + i));  //#
   486:       cellList.add (BIT_TO_TEXT[i]);  //Button
   487:       cellList.add (xinputTextFieldOf[i]);  //XInput
   488:       cellList.add (keyTextFieldOf[i]);  //Keyboard
   489:       cellList.add (BIT_TO_REPEATABLE[i] ? repeatCheckBoxOf[i] : null);  //Burst
   490:       cellList.add (BIT_TO_REPEATABLE[i] ? delaySpinnerOf[i] : null);  //Delay
   491:       cellList.add (BIT_TO_REPEATABLE[i] ? intervalSpinnerOf[i] : null);  //Interval
   492:     }
   493: 
   494:     configurationPanel =
   495:       ComponentFactory.createVerticalBox (
   496:         Box.createVerticalStrut (5),
   497:         ComponentFactory.createHorizontalBox (
   498:           Box.createHorizontalGlue (),
   499:           Multilingual.mlnText (ComponentFactory.createLabel (getNameEn ()), "ja", getNameJa ()),
   500:           Box.createHorizontalGlue ()),
   501:         Box.createVerticalStrut (5),
   502:         ComponentFactory.createHorizontalBox (
   503:           ComponentFactory.createGridPanel (
   504:             7,  //colCount
   505:             2 + BUTTONS,  //rowCount
   506:             "paddingLeft=3,paddingRight=3,center",   //gridStyles
   507:             "",  //colStyles
   508:             "italic;colSpan=7,widen",  //rowStyles
   509:             "",  //cellStyles
   510:             cellList.toArray (new Object[0]))),
   511:         Box.createVerticalStrut (5),
   512:         ComponentFactory.createHorizontalBox (
   513:           Box.createHorizontalGlue (),
   514:           Multilingual.mlnText (ComponentFactory.createButton ("Reset to default values", (ActionListener) this), "ja", "初期値に戻す"),
   515:           Box.createHorizontalGlue ()),
   516:         Box.createVerticalStrut (5));
   517: 
   518:     return configurationPanel;
   519:   }
   520: 
   521: 
   522:   //input (ke, pressed)
   523:   //  キー入力イベントを処理する
   524:   //  ke  キーイベント
   525:   //  pressed  false=離された,true=押された
   526:   @Override public boolean input (KeyEvent ke, boolean pressed) {
   527:     int keyCode = ke.getKeyCode ();
   528:     //キーで押されているボタンを更新する
   529:     for (int i = 0; i < BUTTONS; i++) {
   530:       if (keyCode == (map[MAP_CODE + i] & 65535)) {
   531:         if (pressed) {
   532:           keyButtons |= 1 << i;
   533:         } else {
   534:           keyButtons &= ~(1 << i);
   535:         }
   536:         return true;
   537:       }
   538:     }
   539:     return false;
   540:   }
   541: 
   542: 
   543:   //setPin8 (pin8)
   544:   //  ピン8を変更する
   545:   //  pin8  ピン8
   546:   @Override public void setPin8 (int pin8) {
   547:     page = pin8;
   548:   }
   549: 
   550: 
   551:   //d = readByte ()
   552:   //  ポートから読み出す
   553:   //  d  値。0~255
   554:   @Override public int readByte () {
   555:     //ボタンの状態を確認する
   556:     int currentButtons = keyButtons;  //現在押されているボタン
   557:     int lastIndex = -1;
   558:     int lastMasks = 0;
   559:     for (int i = 0; i < BUTTONS; i++) {
   560:       int xCode = map[MAP_CODE + i] >>> 16;
   561:       if (xCode != 0) {  //割り当てられている
   562:         int xIndex = (xCode >> 5) & 3;
   563:         int xBit = xCode & 31;
   564:         if (lastIndex != xIndex) {
   565:           lastIndex = xIndex;
   566:           lastMasks = PPI.ppiXInput == null ? 0 : PPI.ppiXInput.getButtonMasks (lastIndex);
   567:         }
   568:         if ((lastMasks & (1 << xBit)) != 0) {  //押されている
   569:           currentButtons |= 1 << i;
   570:         }
   571:       }
   572:     }
   573:     int pressedButtons = ~lastButtons & currentButtons;  //今回押されたボタン
   574:     lastButtons = currentButtons;
   575:     int outputButtons = 0;  //出力するボタン
   576:     for (int i = 0; i < BUTTONS; i++) {
   577:       if ((pressedButtons & (1 << i)) != 0 &&  //今回押された
   578:           map[MAP_REPEAT + i] != 0) {  //連射有効
   579:         startTimeOf[i] = XEiJ.mpuClockTime + map[MAP_DELAY + i] * (XEiJ.TMR_FREQ / 1000);  //連射開始時刻
   580:       }
   581:       if ((currentButtons & (1 << i)) != 0 &&  //現在押されている
   582:           (map[MAP_REPEAT + i] == 0 ||  //連射が無効または
   583:            XEiJ.mpuClockTime < startTimeOf[i] ||  //連射開始時刻になっていないまたは
   584:            ((int) ((XEiJ.mpuClockTime - startTimeOf[i]) /  //連射開始時刻を過ぎた時間を
   585:                    ((map[MAP_INTERVAL + i] >> 1) * (XEiJ.TMR_FREQ / 1000)))  //連射間隔の半分で割った商が
   586:             & 1) != 0)) {  //奇数
   587:         outputButtons |= 1 << i;
   588:       }
   589:     }
   590:     //データを作る
   591:     return (page == 0 ?
   592:             0b11110011 &
   593:             ((outputButtons & (UP_MASK | DOWN_MASK)) == UP_MASK ? ~0b00000001 : -1) &  //↑が押されていて↓が押されていない
   594:             ((outputButtons & (DOWN_MASK | UP_MASK)) == DOWN_MASK ? ~0b00000010 : -1) &  //↓が押されていて↑が押されていない
   595:             ((outputButtons & A_MASK) != 0 ? ~0b00100000 : -1) &
   596:             ((outputButtons & START_MASK) != 0 ? ~0b01000000 : -1)
   597:             :
   598:             0b11111111 &
   599:             ((outputButtons & (UP_MASK | DOWN_MASK)) == UP_MASK ? ~0b00000001 : -1) &  //↑が押されていて↓が押されていない
   600:             ((outputButtons & (DOWN_MASK | UP_MASK)) == DOWN_MASK ? ~0b00000010 : -1) &  //↓が押されていて↑が押されていない
   601:             ((outputButtons & (LEFT_MASK | RIGHT_MASK)) == LEFT_MASK ? ~0b00000100 : -1) &  //←が押されていて→が押されていない
   602:             ((outputButtons & (RIGHT_MASK | LEFT_MASK)) == RIGHT_MASK ? ~0b00001000 : -1) &  //→が押されていて←が押されていない
   603:             ((outputButtons & B_MASK) != 0 ? ~0b00100000 : -1) &
   604:             ((outputButtons & C_MASK) != 0 ? ~0b01000000 : -1));
   605:   }  //readByte
   606: 
   607: }  //class MegaDrive3ButtonPad