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