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