CONDevice.java
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: package xeij;
14:
15: import java.awt.datatransfer.*;
16: import java.awt.event.*;
17: import java.io.*;
18: import java.util.*;
19: import java.util.concurrent.*;
20: import javax.swing.*;
21:
22: public class CONDevice {
23:
24:
25: public static final long CON_PASTE_DELAY = 10L;
26:
27:
28:
29: public static final long CON_PASTE_INTERVAL = 10L;
30:
31:
32: public static final String CON_PASTE_PIPE_NAME = "XEiJPaste";
33:
34: public static final String CON_CONTROL_PIPE_NAME = "XEiJControl";
35:
36:
37:
38:
39:
40:
41:
42:
43:
44: public static final int CON_PIPE_INSTANCES = 10;
45:
46:
47: public static final String[] CON_KEY_BASE = (
48: "esc,1," +
49: "1,2," +
50: "2,3," +
51: "3,4," +
52: "4,5," +
53: "5,6," +
54: "6,7," +
55: "7,8," +
56: "8,9," +
57: "9,10," +
58: "0,11," +
59: "minus,12," +
60: "caret,13," +
61: "yen,14," +
62: "bs,15," +
63: "tab,16," +
64: "q,17," +
65: "w,18," +
66: "e,19," +
67: "r,20," +
68: "t,21," +
69: "y,22," +
70: "u,23," +
71: "i,24," +
72: "o,25," +
73: "p,26," +
74: "at,27," +
75: "leftbracket,28," +
76: "return,29," +
77: "a,30," +
78: "s,31," +
79: "d,32," +
80: "f,33," +
81: "g,34," +
82: "h,35," +
83: "j,36," +
84: "k,37," +
85: "l,38," +
86: "semicolon,39," +
87: "colon,40," +
88: "rightbracket,41," +
89: "z,42," +
90: "x,43," +
91: "c,44," +
92: "v,45," +
93: "b,46," +
94: "n,47," +
95: "m,48," +
96: "comma,49," +
97: "period,50," +
98: "slash,51," +
99: "underline,52," +
100: "space,53," +
101: "home,54," +
102: "del,55," +
103: "rollup,56," +
104: "rolldown,57," +
105: "undo,58," +
106: "left,59," +
107: "up,60," +
108: "right,61," +
109: "down,62," +
110: "clr,63," +
111: "tenkeyslash,64," +
112: "tenkeyasterisk,65," +
113: "tenkeyminus,66," +
114: "tenkey7,67," +
115: "tenkey8,68," +
116: "tenkey9,69," +
117: "tenkeyplus,70," +
118: "tenkey4,71," +
119: "tenkey5,72," +
120: "tenkey6,73," +
121: "tenkeyequal,74," +
122: "tenkey1,75," +
123: "tenkey2,76," +
124: "tenkey3,77," +
125: "enter,78," +
126: "tenkey0,79," +
127: "tenkeycomma,80," +
128: "tenkeyperiod,81," +
129: "kigou,82," +
130: "touroku,83," +
131: "help,84," +
132: "xf1,85," +
133: "xf2,86," +
134: "xf3,87," +
135: "xf4,88," +
136: "xf5,89," +
137: "kana,90," +
138: "roma,91," +
139: "code,92," +
140: "caps,93," +
141: "ins,94," +
142: "hiragana,95," +
143: "zenkaku,96," +
144: "break,97," +
145: "copy,98," +
146: "f1,99," +
147: "f2,100," +
148: "f3,101," +
149: "f4,102," +
150: "f5,103," +
151: "f6,104," +
152: "f7,105," +
153: "f8,106," +
154: "f9,107," +
155: "f10,108," +
156:
157: "shift,112," +
158: "ctrl,113," +
159: "opt1,114," +
160: "opt2,115," +
161: "num,116," +
162: "").split (",");
163:
164:
165: public static boolean conPipeOn;
166:
167: public static JMenu conSettingsMenu;
168:
169: public static JCheckBoxMenuItem conPipeCheckBox;
170:
171:
172: public static boolean conCleanupFlag;
173:
174: public static int conCON;
175:
176:
177: public static CONPasteTask conPasteTask;
178:
179: public static LinkedBlockingQueue<String> conPasteQueue;
180:
181: public static CONPasteQueueThread conPasteQueueThread;
182:
183:
184: public static HashMap<String,Integer> conKeyMap;
185:
186: public static LinkedBlockingQueue<String> conControlQueue;
187:
188: public static CONControlQueueThread conControlQueueThread;
189:
190:
191: public static CONPipeThread[] conPipeThreadArray;
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211: public static void conInit () {
212:
213: conPipeOn = XEiJ.prgWindllLoaded && Settings.sgsGetOnOff ("pastepipe");
214:
215: ActionListener listener = new ActionListener () {
216: @Override public void actionPerformed (ActionEvent ae) {
217: Object source = ae.getSource ();
218: String command = ae.getActionCommand ();
219: switch (command) {
220: case "Stop paste":
221: conStopPaste ();
222: break;
223: case "Paste pipe":
224: conSetPipeOn (((JCheckBoxMenuItem) source).isSelected ());
225: break;
226: }
227: }
228: };
229: conSettingsMenu = Multilingual.mlnText (
230: ComponentFactory.createMenu (
231: "Paste settings",
232:
233: Multilingual.mlnText (ComponentFactory.createMenuItem ("Stop paste", listener), "ja", "貼り付け中止"),
234: ComponentFactory.createHorizontalSeparator (),
235: conPipeCheckBox =
236: ComponentFactory.setEnabled (
237: Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (conPipeOn, "Paste pipe", listener), "ja", "貼り付けパイプ"),
238: XEiJ.prgWindllLoaded)
239: ),
240: "ja", "貼り付け設定");
241:
242:
243: conCleanupFlag = false;
244:
245: conCON = 0;
246:
247:
248: conPasteTask = null;
249:
250: conPasteQueue = new LinkedBlockingQueue<String> ();
251:
252: conPasteQueueThread = new CONPasteQueueThread ();
253:
254: conPasteQueueThread.start ();
255:
256:
257: conKeyMap = new HashMap<String,Integer> ();
258: for (int i = 0; i + 1 < CON_KEY_BASE.length; i += 2) {
259: conKeyMap.put (CON_KEY_BASE[i], Integer.parseInt (CON_KEY_BASE[i + 1], 10));
260: }
261:
262: conControlQueue = new LinkedBlockingQueue<String> ();
263:
264: conControlQueueThread = new CONControlQueueThread ();
265:
266: conControlQueueThread.start ();
267:
268:
269: conPipeThreadArray = new CONPipeThread[CON_PIPE_INSTANCES];
270:
271: for (int i = 0; i < CON_PIPE_INSTANCES; i++) {
272: if (conPipeOn) {
273:
274: conPipeThreadArray[i] = new CONPipeThread (CON_PIPE_INSTANCES / 2 <= i);
275:
276: if (conPipeThreadArray[i].getPipeStream () != null) {
277:
278: conPipeThreadArray[i].start ();
279: }
280: } else {
281:
282: conPipeThreadArray[i] = null;
283: }
284: }
285: }
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307: public static void conTini () {
308:
309: Settings.sgsPutOnOff ("pastepipe", conPipeOn);
310:
311: conCleanupFlag = true;
312:
313: if (conPasteQueueThread != null) {
314:
315: conPasteQueueThread.interrupt ();
316:
317: try {
318: conPasteQueueThread.join (100);
319: } catch (InterruptedException ie) {
320: }
321:
322: conPasteQueueThread = null;
323: }
324:
325: CONPasteTask t = conPasteTask;
326: if (t != null) {
327:
328: t.cancel ();
329:
330: conPasteTask = null;
331: }
332:
333: if (conControlQueueThread != null) {
334:
335: conControlQueueThread.interrupt ();
336:
337: try {
338: conControlQueueThread.join (100);
339: } catch (InterruptedException ie) {
340: }
341:
342: conControlQueueThread = null;
343: }
344:
345: for (int i = 0; i < CON_PIPE_INSTANCES; i++) {
346:
347: if (conPipeThreadArray[i] != null) {
348:
349: conPipeThreadArray[i].closePipe ();
350:
351: try {
352: conPipeThreadArray[i].join (100);
353: } catch (InterruptedException ie) {
354: }
355:
356: conPipeThreadArray[i] = null;
357: }
358: }
359: }
360:
361:
362:
363:
364: public static void conReset () {
365:
366: conCON = 0;
367: }
368:
369:
370:
371:
372:
373: public static void conDoPaste () {
374:
375: if (XEiJ.clpClipboard == null) {
376: return;
377: }
378: String string = null;
379: try {
380: string = (String) XEiJ.clpClipboard.getData (DataFlavor.stringFlavor);
381: } catch (Exception e) {
382: return;
383: }
384: if (string == null || string.equals ("")) {
385: return;
386: }
387:
388: conPasteQueue.add (string);
389: }
390:
391:
392:
393:
394:
395:
396: public static void conStopPaste () {
397:
398: conPasteQueue.clear ();
399:
400: CONPasteTask t = conPasteTask;
401: if (t != null) {
402:
403: t.stopPaste ();
404: }
405: }
406:
407:
408:
409:
410:
411:
412:
413:
414:
415:
416:
417:
418:
419:
420:
421: public static void conSetPipeOn (boolean on) {
422: on = XEiJ.prgWindllLoaded && on;
423: if (conPipeOn != on) {
424: conPipeOn = on;
425: conPipeCheckBox.setSelected (on);
426: if (on) {
427:
428: for (int i = 0; i < CON_PIPE_INSTANCES; i++) {
429:
430: if (conPipeThreadArray[i] == null) {
431:
432: conPipeThreadArray[i] = new CONPipeThread (CON_PIPE_INSTANCES / 2 <= i);
433:
434: if (conPipeThreadArray[i].getPipeStream () != null) {
435:
436: conPipeThreadArray[i].start ();
437: }
438: }
439: }
440: } else {
441:
442: for (int i = 0; i < CON_PIPE_INSTANCES; i++) {
443:
444: if (conPipeThreadArray[i] != null) {
445:
446: conPipeThreadArray[i].closePipe ();
447:
448: try {
449: conPipeThreadArray[i].join (100);
450: } catch (InterruptedException ie) {
451: }
452:
453: conPipeThreadArray[i] = null;
454: }
455: }
456: }
457: }
458: }
459:
460:
461:
462:
463:
464:
465:
466:
467:
468:
469:
470:
471:
472:
473:
474: public static class CONPasteQueueThread extends Thread {
475: @Override public void run () {
476:
477: for (;;) {
478:
479: if (conCleanupFlag) {
480:
481: return;
482: }
483:
484: if (conPasteTask == null) {
485:
486:
487: String string = null;
488: try {
489: string = conPasteQueue.take ();
490: } catch (InterruptedException ie) {
491: }
492:
493: if (conCleanupFlag) {
494:
495: return;
496: }
497:
498: if (string != null && !string.equals ("")) {
499:
500: conPasteTask = new CONPasteTask (string);
501:
502: conPasteTask.start ();
503: }
504: }
505:
506: try {
507: Thread.sleep (200);
508: } catch (InterruptedException ie) {
509: }
510: }
511: }
512: }
513:
514:
515:
516:
517:
518:
519:
520:
521:
522:
523:
524:
525:
526: public static class CONControlQueueThread extends Thread {
527: @Override public void run () {
528: StringBuilder controlBuilder = new StringBuilder ();
529:
530: for (;;) {
531:
532: if (conCleanupFlag) {
533:
534: return;
535: }
536:
537:
538: String string = null;
539: try {
540: string = conControlQueue.take ();
541: } catch (InterruptedException ie) {
542: }
543:
544: if (conCleanupFlag) {
545:
546: return;
547: }
548:
549: if (string != null && !string.equals ("")) {
550:
551: controlBuilder.append (string);
552: for (;;) {
553: int l = controlBuilder.length ();
554:
555: int i = 0;
556: for (; i < l; i++) {
557: int c = controlBuilder.charAt (i);
558: if (!(c == '\n' || c == '\r' || c == ':')) {
559: break;
560: }
561: }
562: if (l <= i) {
563: break;
564: }
565:
566: int j = i;
567: for (; j < l; j++) {
568: int c = controlBuilder.charAt (j);
569: if (c == '\n' || c == '\r' || c == ':') {
570: break;
571: }
572: }
573: if (l <= j) {
574: break;
575: }
576:
577: String s = controlBuilder.substring (i, j);
578: controlBuilder.delete (0, j);
579:
580: conCommand (s);
581: }
582: }
583:
584: try {
585: Thread.sleep (200);
586: } catch (InterruptedException ie) {
587: }
588: }
589: }
590: }
591:
592:
593:
594:
595:
596:
597:
598:
599: public static void conCommand (String command) {
600:
601: command = command.trim ().toLowerCase (Locale.ROOT);
602:
603: if (command.length () == 0) {
604: return;
605: }
606:
607: String[] args = command.split ("[\\x00-\\x20]+");
608:
609: switch (args[0]) {
610: case "interrupt":
611: XEiJ.sysInterrupt ();
612: return;
613: case "presskey":
614: conPressKey (args);
615: return;
616: case "releasekey":
617: conReleaseKey (args);
618: return;
619: case "typekey":
620: conPressKey (args);
621: conReleaseKey (args);
622: return;
623: case "opt1reset":
624: XEiJ.mpuReset (0, -1);
625: return;
626: case "reset":
627: XEiJ.mpuReset (-1, -1);
628: return;
629: default:
630: System.out.println ("unknown command " + args[0]);
631: return;
632: }
633: }
634:
635:
636:
637: public static void conPressKey (String[] args) {
638: for (int k = 1; k < args.length; k++) {
639: String key = args[k];
640: if (conKeyMap.containsKey (key)) {
641: Keyboard.kbdCommandPress (conKeyMap.get (key).intValue ());
642: } else {
643: System.out.println ("unknown key " + key);
644: return;
645: }
646: }
647: }
648:
649:
650:
651: public static void conReleaseKey (String[] args) {
652: for (int k = args.length - 1; 1 <= k; k--) {
653: String key = args[k];
654: if (conKeyMap.containsKey (key)) {
655: Keyboard.kbdCommandRelease (conKeyMap.get (key).intValue ());
656: } else {
657: System.out.println ("unknown key " + key);
658: return;
659: }
660: }
661: }
662:
663:
664:
665: public static class CONPipeThread extends Thread {
666:
667:
668: public boolean isControlPipe;
669:
670: public NamedPipeInputStream pipeStream;
671:
672: public boolean closeFlag;
673:
674:
675:
676:
677:
678:
679:
680: public CONPipeThread (boolean isControlPipe) {
681:
682: this.isControlPipe = isControlPipe;
683:
684: pipeStream = null;
685:
686: closeFlag = false;
687:
688: try {
689: pipeStream = NamedPipeInputStream.createInputStream (isControlPipe ? CON_CONTROL_PIPE_NAME : CON_PASTE_PIPE_NAME);
690: } catch (IOException ioe) {
691: ioe.printStackTrace ();
692: }
693: }
694:
695:
696:
697:
698:
699: public NamedPipeInputStream getPipeStream () {
700:
701: return pipeStream;
702: }
703:
704:
705:
706:
707:
708: public void closePipe () {
709:
710: closeFlag = true;
711:
712: if (pipeStream != null) {
713: try {
714: pipeStream.cancel ();
715: } catch (IOException ioe) {
716: ioe.printStackTrace ();
717: }
718: }
719: }
720:
721:
722:
723:
724:
725:
726:
727:
728:
729:
730:
731:
732:
733:
734:
735:
736:
737:
738:
739:
740:
741: @Override public void run () {
742: byte[] buffer = new byte[1024];
743: int length = 0;
744:
745: for (;;) {
746:
747: if (closeFlag) {
748:
749: return;
750: }
751:
752: if (pipeStream == null) {
753:
754: return;
755: }
756:
757:
758: try {
759: pipeStream.connect ();
760: } catch (IOException ioe) {
761: ioe.printStackTrace ();
762: return;
763: }
764:
765: while (!conCleanupFlag) {
766: if (length == buffer.length) {
767: byte[] newBuffer = new byte[length * 2];
768: System.arraycopy (buffer, 0, newBuffer, 0, length);
769: buffer = newBuffer;
770: }
771: try {
772: int t = pipeStream.read (buffer, length, buffer.length - length);
773: if (t == 0) {
774: break;
775: }
776: length += t;
777: } catch (IOException ioe) {
778: ioe.printStackTrace ();
779: break;
780: }
781: }
782:
783: try {
784: pipeStream.close ();
785: } catch (IOException ioe) {
786: ioe.printStackTrace ();
787: return;
788: }
789:
790: if (closeFlag) {
791:
792: return;
793: }
794:
795: pipeStream = null;
796: try {
797: pipeStream = NamedPipeInputStream.createInputStream (isControlPipe ? CON_CONTROL_PIPE_NAME : CON_PASTE_PIPE_NAME);
798: } catch (IOException ioe) {
799: ioe.printStackTrace ();
800: }
801: if (length != 0) {
802:
803: StringBuilder sb = new StringBuilder ();
804: for (int i = 0; i < length; i++) {
805: int s = buffer[i] & 0xff;
806: if ((0x80 <= s && s <= 0x9f) || 0xe0 <= s) {
807: i++;
808: s = s << 8 | (i < length ? buffer[i] & 0xff : 0x00);
809: }
810: int c = CharacterCode.chrSJISToChar[s];
811: sb.append ((char) (s != 0 && c == 0 ? '※' : c));
812: }
813: if (isControlPipe) {
814:
815: conControlQueue.add (sb.toString ());
816: } else {
817:
818: conPasteQueue.add (sb.toString ());
819: }
820: length = 0;
821: }
822: }
823: }
824:
825: }
826:
827:
828: public static class CONPasteTask extends TimerTask {
829:
830:
831: public String string;
832:
833: public int length;
834:
835: public int index;
836:
837: public boolean stopFlag;
838:
839:
840:
841:
842: public CONPasteTask (String string) {
843: this.string = string;
844: length = string.length ();
845: index = 0;
846:
847: stopFlag = false;
848: }
849:
850:
851:
852:
853: public void start () {
854:
855: XEiJ.tmrTimer.schedule (conPasteTask, CON_PASTE_DELAY, CON_PASTE_INTERVAL);
856: }
857:
858:
859:
860:
861: public void stopPaste () {
862:
863: stopFlag = true;
864: }
865:
866:
867:
868:
869:
870:
871:
872:
873:
874:
875:
876:
877:
878:
879:
880:
881:
882:
883:
884:
885:
886:
887:
888: @Override public void run () {
889:
890: int con = conCON;
891: if (con == 0) {
892:
893: con = MainMemory.mmrHumanDev ('C' << 24 | 'O' << 16 | 'N' << 8 | ' ',
894: ' ' << 24 | ' ' << 16 | ' ' << 8 | ' ');
895: if (0 <= con &&
896: (
897:
898:
899:
900:
901:
902: MC68060.mmuPeekLongData (con + 0x000180, 1) == 0x20826082 &&
903: MC68060.mmuPeekLongData (con + 0x000184, 1) == 0x72826a82 &&
904: MC68060.mmuPeekLongData (con + 0x000188, 1) == 0x55825782 &&
905: MC68060.mmuPeekLongData (con + 0x00018c, 1) == 0x6a20666f &&
906: MC68060.mmuPeekLongData (con + 0x000190, 1) == 0x72205836 &&
907: MC68060.mmuPeekLongData (con + 0x000194, 1) == 0x38303030 &&
908: MC68060.mmuPeekLongData (con + 0x000198, 1) == 0x20766572 &&
909: MC68060.mmuPeekLongData (con + 0x00019c, 1) == 0x73696f6e &&
910: MC68060.mmuPeekLongData (con + 0x0001a0, 1) == 0x20332e30 &&
911: MC68060.mmuPeekLongData (con + 0x0001a4, 1) == 0x320d0a43
912:
913:
914:
915:
916:
917:
918:
919:
920:
921:
922:
923:
924: )) {
925: conCON = con;
926: }
927: }
928:
929: if (con == 0 || stopFlag) {
930:
931: conPasteQueue.clear ();
932:
933: cancel ();
934:
935: conPasteTask = null;
936:
937: return;
938: }
939:
940: int read = MC68060.mmuPeekLongData (con + 0x00e460, 1);
941: int write = MC68060.mmuPeekLongData (con + 0x00e464, 1);
942: if (write != read) {
943:
944: return;
945: }
946:
947: int head = con + 0x010504;
948: int tail = head + 200;
949: for (; index < length; index++) {
950: int c = CharacterCode.chrCharToSJIS[string.charAt (index)];
951: if (c == 0) {
952: continue;
953: }
954: if (c == '\r' && index + 1 < length && string.charAt (index + 1) == '\n') {
955: index++;
956: } else if (c == '\n') {
957: c = '\r';
958: }
959: if (!(c >= ' ' || c == '\t' || c == '\r' || c == 0x1b)) {
960: continue;
961: }
962: int write1 = write + 1 == tail ? head : write + 1;
963: int write2 = write1 + 1 == tail ? head : write1 + 1;
964: int write3 = write2 + 1 == tail ? head : write2 + 1;
965: if (write1 == read || write2 == read || write3 == read || write3 == read) {
966: break;
967: }
968: if (c < 0x0100) {
969: MC68060.mmuPokeByteData (write1, c, 1);
970: write = write1;
971: } else {
972: MC68060.mmuPokeByteData (write1, c >> 8, 1);
973: MC68060.mmuPokeByteData (write2, c, 1);
974: write = write2;
975: }
976: }
977: MC68060.mmuPokeLongData (con + 0x00e464, write, 1);
978:
979: if (index == length) {
980:
981: cancel ();
982:
983: conPasteTask = null;
984:
985: return;
986: }
987:
988: }
989:
990: }
991:
992: }