PPI.java
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: package xeij;
14:
15: import java.awt.*;
16: import java.awt.event.*;
17: import java.io.*;
18: import java.util.*;
19: import javax.swing.*;
20: import javax.swing.event.*;
21:
22: import com.fazecast.jSerialComm.*;
23:
24: public class PPI {
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101: public static final int PPI_PORT_A = 0x00e9a001;
102: public static final int PPI_PORT_B = 0x00e9a003;
103: public static final int PPI_PORT_C = 0x00e9a005;
104: public static final int PPI_CONTROL = 0x00e9a007;
105:
106:
107: public static Joystick[] ppiJoysticks;
108: public static Joystick ppiJoystick1;
109: public static Joystick ppiJoystick2;
110:
111:
112: public static boolean ppiJoyKey;
113: public static boolean ppiJoyAuto;
114: public static boolean ppiJoyBlock;
115:
116:
117:
118: public static int ppiPortCData;
119:
120:
121:
122: public static final long PPI_CONTINUOUS_ACCESS_SPAN = XEiJ.TMR_FREQ / 10;
123: public static long ppiLastAccessTime;
124:
125:
126: public static final boolean PPI_XINPUT_ON = true;
127: public static boolean ppiXInputOn;
128: public static XInput ppiXInput;
129: public static int ppiXInputLastButtons;
130:
131:
132: public static JFrame ppiFrame;
133:
134: public static JScrollPane ppiConfigurationScrollPane;
135:
136:
137:
138: public static void ppiInit () {
139: ppiJoyKey = Settings.sgsGetOnOff ("joykey");
140: ppiJoyAuto = Settings.sgsGetOnOff ("joyauto");
141: ppiJoyBlock = Settings.sgsGetOnOff ("joyblock");
142:
143: ppiJoysticks = new Joystick[] {
144: new DummyPad (),
145: new Normal2ButtonPad (1),
146: new Normal2ButtonPad (2),
147: new MegaDrive3ButtonPad (1),
148: new MegaDrive3ButtonPad (2),
149: new MegaDrive6ButtonPad (1),
150: new MegaDrive6ButtonPad (2),
151: new CyberStickAnalog (1),
152: new CyberStickAnalog (2),
153: new CyberStickDigital (1),
154: new CyberStickDigital (2),
155: new Shiromadokun (1),
156: new Shiromadokun (2),
157: };
158:
159: String id1 = Settings.sgsGetString ("joystick1");
160: ppiJoystick1 = ppiJoysticks[0];
161: for (Joystick joystick : ppiJoysticks) {
162: if (joystick.getId ().equalsIgnoreCase (id1)) {
163: ppiJoystick1 = joystick;
164: }
165: }
166:
167: String id2 = Settings.sgsGetString ("joystick2");
168: ppiJoystick2 = ppiJoysticks[0];
169: for (Joystick joystick : ppiJoysticks) {
170: if (joystick.getId ().equalsIgnoreCase (id2)) {
171: ppiJoystick2 = joystick;
172: }
173: }
174:
175: if (PPI_XINPUT_ON) {
176: ppiXInputOn = XEiJ.prgIsWindows && Settings.sgsGetOnOff ("xinput");
177: if (ppiXInputOn) {
178: ppiXInputStart ();
179: }
180: ppiXInputLastButtons = 0;
181: }
182:
183: ppiReset ();
184: }
185:
186:
187:
188: public static void ppiTini () {
189: Settings.sgsPutOnOff ("joykey", ppiJoyKey);
190: Settings.sgsPutOnOff ("joyauto", ppiJoyAuto);
191: Settings.sgsPutOnOff ("joyblock", ppiJoyBlock);
192: for (Joystick joystick : ppiJoysticks) {
193: joystick.tini ();
194: }
195: Settings.sgsPutString ("joystick1", ppiJoystick1.getId ());
196: Settings.sgsPutString ("joystick2", ppiJoystick2.getId ());
197:
198: if (PPI_XINPUT_ON) {
199: Settings.sgsPutOnOff ("xinput", ppiXInputOn);
200: if (ppiXInputOn) {
201: ppiXInputOn = false;
202: ppiXInputEnd ();
203: }
204: }
205: }
206:
207:
208:
209: public static void ppiReset () {
210: ppiPortCData = 0;
211: ppiLastAccessTime = 0L;
212: }
213:
214:
215: public static void ppiXInputStart () {
216: if (ppiXInput == null) {
217: System.out.println (Multilingual.mlnJapanese ?
218: "XInput のポーリングを開始します" :
219: "Starts polling XInput");
220: ppiXInput = new XInput ();
221: }
222: }
223:
224: public static void ppiXInputEnd () {
225: if (ppiXInput != null) {
226: System.out.println (Multilingual.mlnJapanese ?
227: "XInput のポーリングを終了します" :
228: "Ends polling XInput");
229: ppiXInput.end ();
230: ppiXInput = null;
231: }
232: }
233:
234:
235:
236: public static void ppiStart () {
237: if (RestorableFrame.rfmGetOpened (Settings.SGS_PPI_FRAME_KEY)) {
238: ppiOpen ();
239: }
240: }
241:
242:
243:
244: public static void ppiOpen () {
245: if (ppiFrame == null) {
246: ppiMakeFrame ();
247: }
248: XEiJ.pnlExitFullScreen (false);
249: ppiFrame.setVisible (true);
250: }
251:
252:
253:
254:
255: public static void ppiMakeFrame () {
256:
257:
258: ActionListener actionListener = new ActionListener () {
259: @Override public void actionPerformed (ActionEvent ae) {
260: Object source = ae.getSource ();
261: String command = ae.getActionCommand ();
262: switch (command) {
263: case "Consider part of keyboard as joystick":
264:
265: ppiJoyKey = ((JCheckBox) ae.getSource ()).isSelected ();
266: break;
267: case "Enabled only while the port is read repeatedly":
268:
269: ppiJoyAuto = ((JCheckBox) ae.getSource ()).isSelected ();
270: break;
271: case "Remove key input data processed as a joystick operation":
272:
273: ppiJoyBlock = ((JCheckBox) ae.getSource ()).isSelected ();
274: break;
275:
276: case "XInput":
277: if (PPI_XINPUT_ON) {
278: if (((JCheckBox) ae.getSource ()).isSelected ()) {
279: if (!ppiXInputOn) {
280: ppiXInputOn = true;
281: ppiXInputStart ();
282: }
283: } else {
284: if (ppiXInputOn) {
285: ppiXInputOn = false;
286: ppiXInputEnd ();
287: }
288: }
289: }
290: }
291: }
292: };
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312: ButtonGroup port1Group = new ButtonGroup ();
313: ButtonGroup port2Group = new ButtonGroup ();
314: ActionListener port1Listener = new ActionListener () {
315: @Override public void actionPerformed (ActionEvent ae) {
316: Joystick joyStick = ppiJoysticks[Integer.parseInt (ae.getActionCommand ())];
317: if (ppiJoystick1 != joyStick) {
318: ppiJoystick1.reset ();
319: ppiJoystick1 = joyStick;
320: }
321: ppiConfigurationScrollPane.setViewportView (joyStick.getConfigurationPanel ());
322: }
323: };
324: ActionListener port2Listener = new ActionListener () {
325: @Override public void actionPerformed (ActionEvent ae) {
326: Joystick joyStick = ppiJoysticks[Integer.parseInt (ae.getActionCommand ())];
327: if (ppiJoystick2 != joyStick) {
328: ppiJoystick2.reset ();
329: ppiJoystick2 = joyStick;
330: }
331: ppiConfigurationScrollPane.setViewportView (joyStick.getConfigurationPanel ());
332: }
333: };
334: ArrayList<Object> cellList = new ArrayList<Object> ();
335: cellList.add (Multilingual.mlnText (ComponentFactory.createLabel ("Port"), "ja", "ポート"));
336: cellList.add (Multilingual.mlnText (ComponentFactory.createLabel ("Connect to"), "ja", "接続"));
337: cellList.add ("1");
338: cellList.add ("2");
339: cellList.add (ComponentFactory.createHorizontalSeparator ());
340: for (int i = 0; i < ppiJoysticks.length; i++) {
341: Joystick joyStick = ppiJoysticks[i];
342: cellList.add (ComponentFactory.setText (ComponentFactory.createRadioButton (
343: port1Group, joyStick == ppiJoystick1, String.valueOf (i), port1Listener), ""));
344: cellList.add (ComponentFactory.setText (ComponentFactory.createRadioButton (
345: port2Group, joyStick == ppiJoystick2, String.valueOf (i), port2Listener), ""));
346: cellList.add (Multilingual.mlnText (ComponentFactory.createLabel (joyStick.getNameEn ()), "ja", joyStick.getNameJa ()));
347: }
348: JScrollPane portMenuPanel = new JScrollPane (
349: ComponentFactory.createGridPanel (
350: 3, 3 + ppiJoysticks.length,
351: "paddingLeft=3,paddingRight=3,center",
352: "",
353: "italic;italic;colSpan=3,widen",
354: "colSpan=2;rowSpan=2",
355: cellList.toArray (new Object[0])));
356:
357:
358: ppiConfigurationScrollPane = new JScrollPane ((((ppiJoystick1 instanceof DummyPad) &&
359: !(ppiJoystick2 instanceof DummyPad)) ||
360: (!(ppiJoystick1 instanceof Shiromadokun) &&
361: (ppiJoystick2 instanceof Shiromadokun))
362: ? ppiJoystick2 : ppiJoystick1).getConfigurationPanel ());
363:
364:
365: ppiFrame = Multilingual.mlnTitle (
366: ComponentFactory.createRestorableSubFrame (
367: Settings.SGS_PPI_FRAME_KEY,
368: "Joystick port settings",
369: null,
370: ComponentFactory.setEmptyBorder (
371: ComponentFactory.createVerticalBox (
372:
373: !(PPI_XINPUT_ON && XEiJ.prgIsWindows) ? null :
374: ComponentFactory.createFlowPanel (
375: ComponentFactory.createCheckBox (ppiXInputOn, "XInput", actionListener)
376: ),
377: !(PPI_XINPUT_ON && XEiJ.prgIsWindows) ? null : ComponentFactory.createHorizontalSeparator (),
378:
379: ComponentFactory.createFlowPanel (
380: Multilingual.mlnText (
381: ComponentFactory.createCheckBox (
382: ppiJoyKey,
383: "Consider part of keyboard as joystick",
384: actionListener),
385: "ja", "キーボードの一部をジョイスティックとみなす")
386: ),
387: ComponentFactory.createFlowPanel (
388: Multilingual.mlnText (
389: ComponentFactory.createCheckBox (
390: ppiJoyAuto,
391: "Enabled only while the port is read repeatedly",
392: actionListener),
393: "ja", "ポートが繰り返し読み出されている間だけ有効")
394: ),
395: ComponentFactory.createFlowPanel (
396: Multilingual.mlnText (
397: ComponentFactory.createCheckBox (
398: ppiJoyBlock,
399: "Remove key input data processed as a joystick operation",
400: actionListener),
401: "ja", "ジョイスティック操作として処理されたキー入力データを取り除く")
402: ),
403: Box.createVerticalStrut (5),
404: ComponentFactory.createHorizontalBox (
405: ComponentFactory.createHorizontalSplitPane (
406: portMenuPanel,
407: ppiConfigurationScrollPane)
408: )
409: ),
410: 5, 5, 5, 5)),
411: "ja", "ジョイスティックポート設定");
412: }
413:
414:
415:
416:
417: public static boolean ppiInput (KeyEvent ke, boolean pressed) {
418: boolean consume = false;
419: if (ppiJoyKey && (!ppiJoyAuto || XEiJ.mpuClockTime < ppiLastAccessTime + PPI_CONTINUOUS_ACCESS_SPAN)) {
420: if (ppiJoystick1.input (ke, pressed) ||
421: ppiJoystick2.input (ke, pressed)) {
422:
423:
424:
425: consume = pressed && ppiJoyBlock;
426: }
427: }
428: return consume;
429: }
430:
431:
432:
433:
434:
435: public static int ppiReadByte (int a) {
436: int d;
437:
438: switch (a & 7) {
439:
440: case PPI_PORT_A & 7:
441: if (XEiJ.regOC >> 6 != 0b0100_101_000) {
442: ppiLastAccessTime = XEiJ.mpuClockTime;
443: }
444: d = ppiJoystick1.readByte () & 0xff;
445: break;
446:
447: case PPI_PORT_B & 7:
448: if (XEiJ.regOC >> 6 != 0b0100_101_000) {
449: ppiLastAccessTime = XEiJ.mpuClockTime;
450: }
451: d = ppiJoystick2.readByte () & 0xff;
452: break;
453:
454: case PPI_PORT_C & 7:
455: d = ppiPortCData;
456: break;
457: default:
458: d = 0xff;
459: }
460:
461: return d;
462: }
463:
464:
465: public static void ppiWriteByte (int a, int d) {
466: d &= 0xff;
467:
468: switch (a & 7) {
469:
470: case PPI_PORT_A & 7:
471: ppiJoystick1.writeByte (d);
472: break;
473:
474: case PPI_PORT_B & 7:
475: ppiJoystick2.writeByte (d);
476: break;
477:
478: case PPI_PORT_C & 7:
479: ppiPortCData = d;
480:
481: ADPCM.pcmSetPan (d);
482: ADPCM.pcmDivider = d >> 2 & 3;
483: ADPCM.pcmUpdateRepeatInterval ();
484:
485: ppiJoystick1.setPin8 (d >> 4 & 1);
486: ppiJoystick2.setPin8 (d >> 5 & 1);
487: ppiJoystick1.setPin6 ((d >> 6 & 1) ^ 1);
488: ppiJoystick1.setPin7 ((d >> 7 & 1) ^ 1);
489: break;
490:
491: case PPI_CONTROL & 7:
492: if ((d & 0b1000_0000) == 0b0000_0000) {
493: int n = (d >> 1) & 7;
494: int x = d & 1;
495: ppiPortCData = ppiPortCData & ~(1 << n) | x << n;
496: if (n < 4) {
497: switch (n) {
498: case 0:
499: case 1:
500: ADPCM.pcmSetPan (ppiPortCData & 3);
501: break;
502: case 2:
503: case 3:
504: ADPCM.pcmDivider = ppiPortCData >> 2 & 3;
505: ADPCM.pcmUpdateRepeatInterval ();
506: break;
507: }
508: } else {
509: switch (n) {
510: case 4:
511: ppiJoystick1.setPin8 (x);
512: break;
513: case 5:
514: ppiJoystick2.setPin8 (x);
515: break;
516: case 6:
517: ppiJoystick1.setPin6 (x ^ 1);
518: break;
519: case 7:
520: ppiJoystick1.setPin7 (x ^ 1);
521: break;
522: }
523: }
524: } else if ((d & 0b1000_0100) == 0b1000_0000){
525:
526: } else {
527:
528: }
529: }
530:
531: }
532:
533: }