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