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