TextCopy.java
     1: //========================================================================================
     2: //  TextCopy.java
     3: //    en:Text screen copy
     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: package xeij;
    14: 
    15: import java.awt.event.*;
    16: import javax.swing.*;
    17: 
    18: //class TextCopy
    19: //  テキスト画面コピー
    20: public class TextCopy {
    21: 
    22:   public static final int TXC_AREA_DISPLAY = 0;  //表示範囲
    23:   public static final int TXC_AREA_C_WIDTH = 1;  //C_WIDTH
    24:   public static final int TXC_AREA_VRAM = 2;  //VRAM全体
    25:   public static final int TXC_AREA_ENCLOSED = 3;  //最後に囲んだ範囲
    26:   public static int txcAreaMode;  //範囲モード
    27:   public static boolean txcEncloseEachTime;  //true=マウスで都度囲む
    28: 
    29:   //class HanPat
    30:   //  半角パターン
    31:   static class HanPat {
    32:     int c;  //文字コード
    33:     int p0, p1, p2, p3;  //フォントパターン
    34:     HanPat next;  //同じハッシュコードを持つ次のフォントパターン
    35:   }
    36: 
    37:   //class ZenPat
    38:   //  全角パターン
    39:   static class ZenPat {
    40:     int c;  //文字コード
    41:     int p0, p1, p2, p3, p4, p5, p6, p7;  //パターン
    42:     ZenPat next;  //同じハッシュコードを持つ次のパターン
    43:   }
    44: 
    45:   static HanPat[] hanTable;  //半角ハッシュテーブル
    46:   static ZenPat[] zenTable;  //全角ハッシュテーブル
    47:   static int pressedX, pressedY;  //マウスの左ボタンが押された位置の画面座標。-1=なし
    48:   static int enclosedX1, enclosedY1, enclosedX2, enclosedY2;  //最後に囲んだ範囲
    49: 
    50:   public static int txcRow1, txcRow2, txcCol1, txcCol2;  //現在選択されている範囲。-1=なし
    51: 
    52:   //txcInit ()
    53:   //  初期化
    54:   public static void txcInit () {
    55:     String v = Settings.sgsGetString ("textcopyarea").toLowerCase ();
    56:     txcAreaMode = (v.equals ("display") ? TXC_AREA_DISPLAY :
    57:                    v.equals ("c_width") ? TXC_AREA_C_WIDTH :
    58:                    v.equals ("vram") ? TXC_AREA_VRAM :
    59:                    v.equals ("enclosed") ? TXC_AREA_ENCLOSED :
    60:                    TXC_AREA_DISPLAY);
    61:     txcEncloseEachTime = Settings.sgsGetOnOff ("textcopy");
    62:     pressedX = -1;
    63:     pressedY = -1;
    64:     enclosedX1 = 0;
    65:     enclosedY1 = 0;
    66:     enclosedX2 = 0;
    67:     enclosedY2 = 0;
    68:     txcRow1 = -1;
    69:     txcRow2 = -1;
    70:     txcCol1 = -1;
    71:     txcCol2 = -1;
    72:   }  //txcInit
    73: 
    74:   //txcTini ()
    75:   //  後始末
    76:   public static void txcTini () {
    77:     Settings.sgsPutString ("textcopyarea",
    78:                            txcAreaMode == TXC_AREA_DISPLAY ? "display" :
    79:                            txcAreaMode == TXC_AREA_C_WIDTH ? "c_width" :
    80:                            txcAreaMode == TXC_AREA_VRAM ? "vram" :
    81:                            txcAreaMode == TXC_AREA_ENCLOSED ? "enclosed" :
    82:                            "display");
    83:     Settings.sgsPutOnOff ("textcopy", txcEncloseEachTime);
    84:   }  //txcTini
    85: 
    86:   //txcMakeMenuItem ()
    87:   //  テキスト画面コピーメニューアイテムを作る
    88:   public static JMenuItem txcMakeMenuItem () {
    89:     return ComponentFactory.setEnabled (
    90:       Multilingual.mlnText (
    91:         ComponentFactory.createMenuItem (
    92:           "Text screen copy", 'C', XEiJ.MNB_MODIFIERS,
    93:           new ActionListener () {
    94:             @Override public void actionPerformed (ActionEvent ae) {
    95:               txcCopy ();
    96:             }
    97:           }),
    98:         "ja", "テキスト画面コピー"),
    99:       XEiJ.clpClipboard != null);
   100:   }  //txcMakeMenuItem
   101: 
   102:   //txcMakeSettingMenu ()
   103:   //  テキスト画面コピー設定メニューを作る
   104:   public static JMenu txcMakeSettingMenu () {
   105:     ActionListener listener = new ActionListener () {
   106:       @Override public void actionPerformed (ActionEvent ae) {
   107:         Object source = ae.getSource ();
   108:         String command = ae.getActionCommand ();
   109:         switch (command) {
   110:         case "Display area":  //表示領域
   111:           txcAreaMode = TXC_AREA_DISPLAY;
   112:           break;
   113:         case "C_WIDTH":
   114:           txcAreaMode = TXC_AREA_C_WIDTH;
   115:           break;
   116:         case "Entire VRAM":  //VRAM全体
   117:           txcAreaMode = TXC_AREA_VRAM;
   118:           break;
   119:         case "Last enclosed area":  //最後に囲んだ範囲
   120:           txcAreaMode = TXC_AREA_ENCLOSED;
   121:           break;
   122:         case "Enclose each time with mouse":  //マウスで都度囲む
   123:           txcEncloseEachTime = ((JCheckBoxMenuItem) source).isSelected ();
   124:           break;
   125:         }
   126:       }
   127:     };
   128:     ButtonGroup areaGroup = new ButtonGroup ();
   129:     return ComponentFactory.setEnabled (
   130:       Multilingual.mlnText (
   131:         ComponentFactory.createMenu (
   132:           "Text screen copy setting",
   133:           Multilingual.mlnText (
   134:             ComponentFactory.createRadioButtonMenuItem (areaGroup, txcAreaMode == TXC_AREA_DISPLAY, "Display area", listener),
   135:             "ja", "表示領域"),
   136:           ComponentFactory.createRadioButtonMenuItem (areaGroup, txcAreaMode == TXC_AREA_C_WIDTH, "C_WIDTH", listener),
   137:           Multilingual.mlnText (
   138:             ComponentFactory.createRadioButtonMenuItem (areaGroup, txcAreaMode == TXC_AREA_VRAM, "Entire VRAM", listener),
   139:             "ja", "VRAM 全体"),
   140:           Multilingual.mlnText (
   141:             ComponentFactory.createRadioButtonMenuItem (areaGroup, txcAreaMode == TXC_AREA_ENCLOSED, "Last enclosed area", listener),
   142:             "ja", "最後に囲んだ範囲"),
   143:           ComponentFactory.createHorizontalSeparator (),
   144:           Multilingual.mlnText (
   145:             ComponentFactory.createCheckBoxMenuItem (txcEncloseEachTime, "Enclose each time with mouse", listener),
   146:             "ja", "マウスで都度囲む")
   147:           ),
   148:         "ja", "テキスト画面コピー設定"),
   149:       XEiJ.clpClipboard != null);
   150:   }  //txcMakeSettingMenu
   151: 
   152:   //txcReset ()
   153:   //  リセット
   154:   //  ハッシュテーブルを破棄する
   155:   public static void txcReset () {
   156:     hanTable = null;
   157:     zenTable = null;
   158:   }  //txcReset
   159: 
   160: 
   161: 
   162:   //txcMousePressed (screenX, screenY)
   163:   //  マウスの左ボタンが押された
   164:   public static void txcMousePressed (int screenX, int screenY) {
   165:     if ((VideoController.vcnReg3Curr & (1 << 5)) == 0) {  //テキスト画面が表示されていない
   166:       return;  //何もしない
   167:     }
   168:     screenX = Math.max (0, Math.min (XEiJ.pnlScreenWidth - 1, screenX));
   169:     screenY = Math.max (0, Math.min (XEiJ.pnlScreenHeight - 1, screenY));
   170:     pressedX = screenX;  //押された位置の画面座標を保存する
   171:     pressedY = screenY;
   172:   }  //txcMousePressed
   173: 
   174:   //txcMouseMoved (screenX, screenY)
   175:   //  マウスが動いた
   176:   public static void txcMouseMoved (int screenX, int screenY) {
   177:     if ((VideoController.vcnReg3Curr & (1 << 5)) == 0) {  //テキスト画面が表示されていない
   178:       return;  //何もしない
   179:     }
   180:     if (pressedX < 0) {  //押されていない
   181:       return;  //何もしない
   182:     }
   183:     screenX = Math.max (0, Math.min (XEiJ.pnlScreenWidth - 1, screenX));
   184:     screenY = Math.max (0, Math.min (XEiJ.pnlScreenHeight - 1, screenY));
   185:     calcLocation (screenX, screenY);
   186:     if (0 <= txcRow1) {  //選択あり
   187:       XEiJ.pnlPanel.repaint ();
   188:     }
   189:   }  //txcMouseMoved
   190: 
   191:   //txcMouseReleased (screenX, screenY)
   192:   //  マウスの左ボタンが離された
   193:   public static void txcMouseReleased (int screenX, int screenY) {
   194:     if ((VideoController.vcnReg3Curr & (1 << 5)) == 0) {  //テキスト画面が表示されていない
   195:       return;  //何もしない
   196:     }
   197:     if (pressedX < 0) {  //押されていない
   198:       return;  //何もしない
   199:     }
   200:     screenX = Math.max (0, Math.min (XEiJ.pnlScreenWidth - 1, screenX));
   201:     screenY = Math.max (0, Math.min (XEiJ.pnlScreenHeight - 1, screenY));
   202:     calcLocation (screenX, screenY);
   203:     if (0 <= txcRow1) {  //選択あり
   204:       XEiJ.clpCopy (getText (txcRow1, txcRow2, txcCol1, txcCol2));  //テキスト画面から文字列を読み取ってクリップボードにコピーする
   205:     }
   206:     pressedX = -1;
   207:     pressedY = -1;
   208:     txcRow1 = -1;
   209:     txcRow2 = -1;
   210:     txcCol1 = -1;
   211:     txcCol2 = -1;
   212:     XEiJ.pnlPanel.repaint ();
   213:   }  //txcMouseReleased
   214: 
   215:   //calcLocation ()
   216:   //  選択範囲を求める
   217:   static void calcLocation (int screenX, int screenY) {
   218:     int x1 = pressedX;  //押された位置の画面座標
   219:     int y1 = pressedY;
   220:     int x2 = screenX;  //現在位置の画面座標
   221:     int y2 = screenY;
   222:     if (x2 < x1) {  //x1<=x2にする
   223:       int t = x1;
   224:       x1 = x2;
   225:       x2 = t;
   226:     }
   227:     if (y2 < y1) {  //y1<=y2にする
   228:       int t = y1;
   229:       y1 = y2;
   230:       y2 = t;
   231:     }
   232:     x1 += CRTC.crtR10TxXCurr;  //VRAM座標の開始位置
   233:     y1 += CRTC.crtR11TxYCurr;
   234:     x2 += CRTC.crtR10TxXCurr;  //VRAM座標の終了位置。1024x1024を超える場合がある
   235:     y2 += CRTC.crtR11TxYCurr;
   236:     int col1 = (x1 + 4) >> 3;  //開始桁。桁の右半分にあるときその桁を含まない
   237:     int col2 = (x2 - 4) >> 3;  //終了桁。桁の左半分にあるときその桁を含まない
   238:     int row1 = (y1 + 8) >> 4;  //開始行。行の下半分にあるときその行を含まない
   239:     int row2 = (y2 - 8) >> 4;  //終了行。行の上半分にあるときその行を含まない
   240:     if (col1 <= col2 && row1 <= row2) {  //1桁以上かつ1行以上
   241:       enclosedX1 = x1;
   242:       enclosedY1 = y1;
   243:       enclosedX2 = x2;
   244:       enclosedY2 = y2;
   245:       txcCol1 = col1;
   246:       txcCol2 = col2;
   247:       txcRow1 = row1;
   248:       txcRow2 = row2;
   249:     } else {  //さもなくば
   250:       txcCol1 = -1;
   251:       txcCol2 = -1;
   252:       txcRow1 = -1;
   253:       txcRow2 = -1;
   254:     }
   255:   }  //calcLocation
   256: 
   257: 
   258: 
   259:   //txcCopy ()
   260:   //  コピー
   261:   public static void txcCopy () {
   262:     int x1 = CRTC.crtR10TxXCurr;  //左上ドット座標
   263:     int y1 = CRTC.crtR11TxYCurr;
   264:     int x2, y2;  //右下ドット座標
   265:     if (txcAreaMode == TXC_AREA_DISPLAY) {  //表示範囲
   266:       int w = (CRTC.crtR03HDispEndCurr - CRTC.crtR02HBackEndCurr) << 3;
   267:       int h = (CRTC.crtR07VDispEndCurr - CRTC.crtR06VBackEndCurr);
   268:       if (CRTC.crtDuplication || CRTC.crtDupExceptSp) {  //ラスタ2度読み
   269:         h >>= 1;
   270:       } else if (CRTC.crtInterlace) {  //インターレース
   271:         h <<= 1;
   272:       }
   273:       x2 = x1 + w - 1;
   274:       y2 = y1 + h - 1;
   275:     } else if (txcAreaMode == TXC_AREA_C_WIDTH) {  //C_WIDTH
   276:       //CONCTRL(16,n)
   277:       //  0 768x512 text
   278:       //  1 768x512 text+graphic16
   279:       //  2 512x512 text
   280:       //  3 512x512 text+graphic16
   281:       //  4 512x512 text+graphic256
   282:       //  5 512x512 text+graphic65536
   283:       int v = MainMemory.mmrHumanVersion;
   284:       int a = (v == 0x0302 ? 0x6800 + 0xa890 + 0x29b1 :
   285:                v == 0x0301 ? 0x6800 + 0xa77a + 0x29b1 :
   286:                v == 0x020f ? 0x6800 + 0xa822 + 0x29b1 :
   287:                v == 0x0203 ? 0x6800 + 0x96dc + 0x29af :
   288:                v == 0x0202 ? 0x6800 + 0x9950 + 0x29af :
   289:                v == 0x0201 ? 0x6800 + 0x9910 + 0x29af :
   290:                v == 0x0200 ? 0x6800 + 0x9910 + 0x29af :
   291:                //!!! 0x0101 0x0100
   292:                -1);
   293:       if (a < 0) {
   294:         return;
   295:       }
   296:       int n = MC68060.mmuPeekByteZeroData (a, 1);
   297:       if (0 <= n && n <= 1) {  //768x512
   298:         x2 = x1 + 768 - 1;
   299:         y2 = y1 + 512 - 1;
   300:       } else if (2 <= n && n <= 5) {  //512x512
   301:         x2 = x1 + 512 - 1;
   302:         y2 = y1 + 512 - 1;
   303:       } else {
   304:         return;
   305:       }
   306:     } else if (txcAreaMode == TXC_AREA_VRAM) {  //VRAM全体
   307:       x2 = x1 + 1024 - 1;
   308:       y2 = y1 + 1024 - 1;
   309:     } else if (txcAreaMode == TXC_AREA_ENCLOSED) {  //最後に囲んだ範囲
   310:       x1 = enclosedX1;  //初回は0,0,0,0なのでNO DATAになる
   311:       y1 = enclosedY1;
   312:       x2 = enclosedX2;
   313:       y2 = enclosedY2;
   314:     } else {
   315:       return;
   316:     }
   317:     int col1 = (x1 + 4) >> 3;  //開始桁。桁の右半分にあるときその桁を含まない
   318:     int col2 = (x2 - 4) >> 3;  //終了桁。桁の左半分にあるときその桁を含まない
   319:     int row1 = (y1 + 8) >> 4;  //開始行。行の下半分にあるときその行を含まない
   320:     int row2 = (y2 - 8) >> 4;  //終了行。行の上半分にあるときその行を含まない
   321:     //テキスト画面から文字列を読み取ってクリップボードにコピーする
   322:     XEiJ.clpCopy (getText (row1, row2, col1, col2));
   323:   }  //txcCopy
   324: 
   325: 
   326: 
   327:   //makeHash ()
   328:   //  ROMフォントからハッシュテーブルを作る
   329:   static void makeHash () {
   330:     byte[] m = MainMemory.mmrM8;
   331:     hanTable = new HanPat[65536];
   332:     zenTable = new ZenPat[65536];
   333:     //半角
   334:     for (int s = 0xff; 0x20 <= s; s--) {  //SJISコード
   335:       int c = CharacterCode.chrSJISToChar[
   336:         s == 0x80 ? 0x5c :  //\→¥
   337:         s == 0x81 ? 0x7e :  //~→ ̄
   338:         s == 0x82 ? 0x7c :  //¦→|
   339:         (0x86 <= s && s <= 0x9f && s != 0x90) || (0xe0 <= s && s <= 0xfd) ? s ^ 0x20 :  //ひらがな→カタカナ
   340:         s];  //文字コード
   341:       if (c == 0) {
   342:         continue;
   343:       }
   344:       for (int n = 2; 0 <= n; n--) {  //種類。0=半角,1=上付き1/4角,2=下付き1/4角
   345:         int a;  //フォントアドレス
   346:         int p0, p1, p2, p3;  //フォントパターン
   347:         int h;  //ハッシュコード
   348:         if (n == 0) {  //半角
   349:           a = 0x00f3a800 + (s << 4);  //8x16フォントアドレス
   350:         } else {  //1/4角
   351:           a = 0x00f3a000 + (s << 3);  //8x8フォントアドレス
   352:         }
   353:         p0 = ((m[a     ]      ) << 24 |
   354:               (m[a +  1] & 255) << 16 |
   355:               (m[a +  2] & 255) <<  8 |
   356:               (m[a +  3] & 255));
   357:         p1 = ((m[a +  4]      ) << 24 |
   358:               (m[a +  5] & 255) << 16 |
   359:               (m[a +  6] & 255) <<  8 |
   360:               (m[a +  7] & 255));
   361:         if (n == 0) {  //半角
   362:           p2 = ((m[a +  8]      ) << 24 |
   363:                 (m[a +  9] & 255) << 16 |
   364:                 (m[a + 10] & 255) <<  8 |
   365:                 (m[a + 11] & 255));
   366:           p3 = ((m[a + 12]      ) << 24 |
   367:                 (m[a + 13] & 255) << 16 |
   368:                 (m[a + 14] & 255) <<  8 |
   369:                 (m[a + 15] & 255));
   370:         } else if (n == 1) {  //上付き1/4角
   371:           p2 = 0;
   372:           p3 = 0;
   373:         } else {  //下付き1/4角
   374:           p2 = p0;
   375:           p3 = p1;
   376:           p0 = 0;
   377:           p1 = 0;
   378:         }
   379:         if ((p0 | p1 | p2 | p3) == 0 ||
   380:             (p0 & p1 & p2 & p3) == -1) {  //空白
   381:           continue;
   382:         }
   383:         for (int u = 3; 0 <= u; u--) {  //装飾。0=ノーマル,1=太字,2=反転,3=太字反転
   384:           int q0 = p0, q1 = p1, q2 = p2, q3 = p3;  //装飾されたフォントパターン
   385:           if ((u & 1) != 0) {  //太字
   386:             q0 |= (q0 >> 1) & 0x7f7f7f7f;
   387:             q1 |= (q1 >> 1) & 0x7f7f7f7f;
   388:             q2 |= (q2 >> 1) & 0x7f7f7f7f;
   389:             q3 |= (q3 >> 1) & 0x7f7f7f7f;
   390:           }
   391:           if ((u & 2) != 0) {  //反転
   392:             q0 = ~q0;
   393:             q1 = ~q1;
   394:             q2 = ~q2;
   395:             q3 = ~q3;
   396:           }
   397:           h = ((q0 * 31 + q1) * 31 + q2) * 31 + q3;
   398:           h = ((h >> 16) + h) & 65535;  //装飾されたフォントパターンのハッシュコード
   399:           HanPat pat = new HanPat ();
   400:           pat.c = c;  //文字コード
   401:           pat.p0 = q0;  //装飾されたフォントパターン
   402:           pat.p1 = q1;
   403:           pat.p2 = q2;
   404:           pat.p3 = q3;
   405:           pat.next = hanTable[h];  //リストの先頭に挿入する
   406:           hanTable[h] = pat;
   407:         }  //for m
   408:       }  //for n
   409:     }  //for s
   410:     //全角
   411:     for (int row = 77 - 1; 0 <= row; row--) {  //行
   412:       for (int col = 94 - 1; 0 <= col; col--) {  //列
   413:         int kum1 = row < 8 ? row : row + 7;
   414:         int sh = kum1 >> 1;
   415:         int sl = 94 * (kum1 & 1) + col;
   416:         sh += 0x81;
   417:         sl += 0x40;
   418:         if (0xa0 <= sh) {
   419:           sh += 0xe0 - 0xa0;
   420:         }
   421:         if (0x7f <= sl) {
   422:           sl += 0x80 - 0x7f;
   423:         }
   424:         int s = (sh << 8) | sl;  //SJISコード
   425:         int c = CharacterCode.chrSJISToChar[s];  //文字コード
   426:         if (c == 0) {
   427:           continue;
   428:         }
   429:         int a = 0x00f00000 + ((col + 94 * row) << 5);  //16x16フォントアドレス
   430:         int p0 = ((m[a     ]      ) << 24 | (m[a +  1] & 255) << 16 |
   431:                   (m[a +  2] & 255) <<  8 | (m[a +  3] & 255));
   432:         int p1 = ((m[a +  4]      ) << 24 | (m[a +  5] & 255) << 16 |
   433:                   (m[a +  6] & 255) <<  8 | (m[a +  7] & 255));
   434:         int p2 = ((m[a +  8]      ) << 24 | (m[a +  9] & 255) << 16 |
   435:                   (m[a + 10] & 255) <<  8 | (m[a + 11] & 255));
   436:         int p3 = ((m[a + 12]      ) << 24 | (m[a + 13] & 255) << 16 |
   437:                   (m[a + 14] & 255) <<  8 | (m[a + 15] & 255));
   438:         int p4 = ((m[a + 16]      ) << 24 | (m[a + 17] & 255) << 16 |
   439:                   (m[a + 18] & 255) <<  8 | (m[a + 19] & 255));
   440:         int p5 = ((m[a + 20]      ) << 24 | (m[a + 21] & 255) << 16 |
   441:                   (m[a + 22] & 255) <<  8 | (m[a + 23] & 255));
   442:         int p6 = ((m[a + 24]      ) << 24 | (m[a + 25] & 255) << 16 |
   443:                   (m[a + 26] & 255) <<  8 | (m[a + 27] & 255));
   444:         int p7 = ((m[a + 28]      ) << 24 | (m[a + 29] & 255) << 16 |
   445:                   (m[a + 30] & 255) <<  8 | (m[a + 31] & 255));
   446:         if ((p0 | p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0 ||
   447:             (p0 & p1 & p2 & p3 & p4 & p5 & p6 & p7) == -1) {  //空白
   448:           continue;
   449:         }
   450:         for (int u = 3; 0 <= u; u--) {  //装飾。0=ノーマル,1=太字,2=反転,3=太字反転
   451:           int q0 = p0, q1 = p1, q2 = p2, q3 = p3, q4 = p4, q5 = p5, q6 = p6, q7 = p7;  //装飾されたフォントパターン
   452:           if ((u & 1) != 0) {  //太字
   453:             q0 |= (q0 >> 1) & 0x7fff7fff;
   454:             q1 |= (q1 >> 1) & 0x7fff7fff;
   455:             q2 |= (q2 >> 1) & 0x7fff7fff;
   456:             q3 |= (q3 >> 1) & 0x7fff7fff;
   457:             q4 |= (q4 >> 1) & 0x7fff7fff;
   458:             q5 |= (q5 >> 1) & 0x7fff7fff;
   459:             q6 |= (q6 >> 1) & 0x7fff7fff;
   460:             q7 |= (q7 >> 1) & 0x7fff7fff;
   461:           }
   462:           if ((u & 2) != 0) {  //反転
   463:             q0 = ~q0;
   464:             q1 = ~q1;
   465:             q2 = ~q2;
   466:             q3 = ~q3;
   467:             q4 = ~q4;
   468:             q5 = ~q5;
   469:             q6 = ~q6;
   470:             q7 = ~q7;
   471:           }
   472:           int h = ((((((q0 * 31 + q1) * 31 + q2) * 31 + q3) * 31 + q4) * 31 + q5) * 31 + q6) * 31 + q7;
   473:           h = ((h >> 16) + h) & 65535;  //装飾されたフォントパターンのハッシュコード
   474:           ZenPat pat = new ZenPat ();
   475:           pat.c = c;  //文字コード
   476:           pat.p0 = q0;  //装飾されたフォントパターン
   477:           pat.p1 = q1;
   478:           pat.p2 = q2;
   479:           pat.p3 = q3;
   480:           pat.p4 = q4;
   481:           pat.p5 = q5;
   482:           pat.p6 = q6;
   483:           pat.p7 = q7;
   484:           pat.next = zenTable[h];  //リストの先頭に挿入する
   485:           zenTable[h] = pat;
   486:         }  //for m
   487:       }  //for col
   488:     }  //for row
   489:   }  //makeHash
   490: 
   491:   //getText (row1, row2, col1, col2)
   492:   //  テキスト画面から文字列を読み取る
   493:   //  球面スクロールに対応する。VRAMは128桁64行だが超えていても構わない
   494:   public static String getText (int row1, int row2, int col1, int col2) {
   495:     int cols = col2 - col1 + 1;  //桁数
   496:     int rows = row2 - row1 + 1;  //行数
   497:     if (cols <= 0 && rows <= 0) {  //範囲がないとき
   498:       return "NO DATA";  //何もせず"NO DATA"を返す
   499:     }
   500:     int[] co = new int[cols + 1];  //範囲内のVRAMの水平方向のオフセットの配列
   501:     for (int c = 0; c < co.length; c++) {
   502:       co[c] = (col1 + c) & 127;
   503:     }
   504:     int[] ra = new int[rows + 15];  //範囲内のVRAMの垂直方向のアドレスの配列
   505:     for (int r = 0; r < ra.length; r++) {
   506:       ra[r] = 0x00e00000 + (((row1 + r) & 63) << 11);
   507:     }
   508:     //
   509:     if (hanTable == null) {
   510:       makeHash ();
   511:     }
   512:     byte[] m = MainMemory.mmrM8;
   513:     StringBuilder sb = new StringBuilder ();
   514:     for (int r = 0; r < rows; r++) {  //範囲内の行
   515:       int a = ra[r];
   516:       if (0 < r) {
   517:         sb.append ('\n');
   518:       }
   519:       for (int c = 0; c < cols; c++) {  //範囲内の桁
   520:         //全角
   521:         if (c + 1 < cols) {  //右端でない
   522:           int a0 = a + co[c];
   523:           int a1 = a + co[c + 1];
   524:           int p0 = ((m[a0            ]      ) << 24 | (m[a1            ] & 255) << 16 |
   525:                     (m[a0 + ( 1 << 7)] & 255) <<  8 | (m[a1 + ( 1 << 7)] & 255));
   526:           int p1 = ((m[a0 + ( 2 << 7)]      ) << 24 | (m[a1 + ( 2 << 7)] & 255) << 16 |
   527:                     (m[a0 + ( 3 << 7)] & 255) <<  8 | (m[a1 + ( 3 << 7)] & 255));
   528:           int p2 = ((m[a0 + ( 4 << 7)]      ) << 24 | (m[a1 + ( 4 << 7)] & 255) << 16 |
   529:                     (m[a0 + ( 5 << 7)] & 255) <<  8 | (m[a1 + ( 5 << 7)] & 255));
   530:           int p3 = ((m[a0 + ( 6 << 7)]      ) << 24 | (m[a1 + ( 6 << 7)] & 255) << 16 |
   531:                     (m[a0 + ( 7 << 7)] & 255) <<  8 | (m[a1 + ( 7 << 7)] & 255));
   532:           int p4 = ((m[a0 + ( 8 << 7)]      ) << 24 | (m[a1 + ( 8 << 7)] & 255) << 16 |
   533:                     (m[a0 + ( 9 << 7)] & 255) <<  8 | (m[a1 + ( 9 << 7)] & 255));
   534:           int p5 = ((m[a0 + (10 << 7)]      ) << 24 | (m[a1 + (10 << 7)] & 255) << 16 |
   535:                     (m[a0 + (11 << 7)] & 255) <<  8 | (m[a1 + (11 << 7)] & 255));
   536:           int p6 = ((m[a0 + (12 << 7)]      ) << 24 | (m[a1 + (12 << 7)] & 255) << 16 |
   537:                     (m[a0 + (13 << 7)] & 255) <<  8 | (m[a1 + (13 << 7)] & 255));
   538:           int p7 = ((m[a0 + (14 << 7)]      ) << 24 | (m[a1 + (14 << 7)] & 255) << 16 |
   539:                     (m[a0 + (15 << 7)] & 255) <<  8 | (m[a1 + (15 << 7)] & 255));
   540:           if ((p0 | p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0 ||
   541:               (p0 & p1 & p2 & p3 & p4 & p5 & p6 & p7) == -1) {  //空白
   542:             a0 += 0x00020000;  //ページ1
   543:             a1 += 0x00020000;
   544:             p0 = ((m[a0            ]      ) << 24 | (m[a1            ] & 255) << 16 |
   545:                   (m[a0 + ( 1 << 7)] & 255) <<  8 | (m[a1 + ( 1 << 7)] & 255));
   546:             p1 = ((m[a0 + ( 2 << 7)]      ) << 24 | (m[a1 + ( 2 << 7)] & 255) << 16 |
   547:                   (m[a0 + ( 3 << 7)] & 255) <<  8 | (m[a1 + ( 3 << 7)] & 255));
   548:             p2 = ((m[a0 + ( 4 << 7)]      ) << 24 | (m[a1 + ( 4 << 7)] & 255) << 16 |
   549:                   (m[a0 + ( 5 << 7)] & 255) <<  8 | (m[a1 + ( 5 << 7)] & 255));
   550:             p3 = ((m[a0 + ( 6 << 7)]      ) << 24 | (m[a1 + ( 6 << 7)] & 255) << 16 |
   551:                   (m[a0 + ( 7 << 7)] & 255) <<  8 | (m[a1 + ( 7 << 7)] & 255));
   552:             p4 = ((m[a0 + ( 8 << 7)]      ) << 24 | (m[a1 + ( 8 << 7)] & 255) << 16 |
   553:                   (m[a0 + ( 9 << 7)] & 255) <<  8 | (m[a1 + ( 9 << 7)] & 255));
   554:             p5 = ((m[a0 + (10 << 7)]      ) << 24 | (m[a1 + (10 << 7)] & 255) << 16 |
   555:                   (m[a0 + (11 << 7)] & 255) <<  8 | (m[a1 + (11 << 7)] & 255));
   556:             p6 = ((m[a0 + (12 << 7)]      ) << 24 | (m[a1 + (12 << 7)] & 255) << 16 |
   557:                   (m[a0 + (13 << 7)] & 255) <<  8 | (m[a1 + (13 << 7)] & 255));
   558:             p7 = ((m[a0 + (14 << 7)]      ) << 24 | (m[a1 + (14 << 7)] & 255) << 16 |
   559:                   (m[a0 + (15 << 7)] & 255) <<  8 | (m[a1 + (15 << 7)] & 255));
   560:             if ((p0 | p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0 ||
   561:                 (p0 & p1 & p2 & p3 & p4 & p5 & p6 & p7) == -1) {  //空白
   562:               sb.append ("  ");
   563:               c++;
   564:               continue;
   565:             }
   566:           }
   567:           int h = ((((((p0 * 31 + p1) * 31 + p2) * 31 + p3) * 31 + p4) * 31 + p5) * 31 + p6) * 31 + p7;
   568:           h = ((h >> 16) + h) & 65535;  //ハッシュコード
   569:           ZenPat pat = zenTable[h];
   570:           while (pat != null) {  //リストを辿る
   571:             if (pat.p0 == p0 &&
   572:                 pat.p1 == p1 &&
   573:                 pat.p2 == p2 &&
   574:                 pat.p3 == p3 &&
   575:                 pat.p4 == p4 &&
   576:                 pat.p5 == p5 &&
   577:                 pat.p6 == p6 &&
   578:                 pat.p7 == p7) {
   579:               break;
   580:             }
   581:             pat = pat.next;
   582:           }
   583:           if (pat != null) {  //見つかった
   584:             sb.append ((char) pat.c);
   585:             c++;
   586:             continue;
   587:           }
   588:         }  //if 右端でない
   589:         //半角
   590:         {
   591:           int a0 = a + co[c];
   592:           int p0 = ((m[a0            ]      ) << 24 |
   593:                     (m[a0 + ( 1 << 7)] & 255) << 16 |
   594:                     (m[a0 + ( 2 << 7)] & 255) <<  8 |
   595:                     (m[a0 + ( 3 << 7)] & 255));
   596:           int p1 = ((m[a0 + ( 4 << 7)]      ) << 24 |
   597:                     (m[a0 + ( 5 << 7)] & 255) << 16 |
   598:                     (m[a0 + ( 6 << 7)] & 255) <<  8 |
   599:                     (m[a0 + ( 7 << 7)] & 255));
   600:           int p2 = ((m[a0 + ( 8 << 7)]      ) << 24 |
   601:                     (m[a0 + ( 9 << 7)] & 255) << 16 |
   602:                     (m[a0 + (10 << 7)] & 255) <<  8 |
   603:                     (m[a0 + (11 << 7)] & 255));
   604:           int p3 = ((m[a0 + (12 << 7)]      ) << 24 |
   605:                     (m[a0 + (13 << 7)] & 255) << 16 |
   606:                     (m[a0 + (14 << 7)] & 255) <<  8 |
   607:                     (m[a0 + (15 << 7)] & 255));
   608:           if ((p0 | p1 | p2 | p3) == 0 ||
   609:               (p0 & p1 & p2 & p3) == -1) {  //空白
   610:             a0 += 0x00020000;  //ページ1
   611:             p0 = ((m[a0            ]      ) << 24 |
   612:                   (m[a0 + ( 1 << 7)] & 255) << 16 |
   613:                   (m[a0 + ( 2 << 7)] & 255) <<  8 |
   614:                   (m[a0 + ( 3 << 7)] & 255));
   615:             p1 = ((m[a0 + ( 4 << 7)]      ) << 24 |
   616:                   (m[a0 + ( 5 << 7)] & 255) << 16 |
   617:                   (m[a0 + ( 6 << 7)] & 255) <<  8 |
   618:                   (m[a0 + ( 7 << 7)] & 255));
   619:             p2 = ((m[a0 + ( 8 << 7)]      ) << 24 |
   620:                   (m[a0 + ( 9 << 7)] & 255) << 16 |
   621:                   (m[a0 + (10 << 7)] & 255) <<  8 |
   622:                   (m[a0 + (11 << 7)] & 255));
   623:             p3 = ((m[a0 + (12 << 7)]      ) << 24 |
   624:                   (m[a0 + (13 << 7)] & 255) << 16 |
   625:                   (m[a0 + (14 << 7)] & 255) <<  8 |
   626:                   (m[a0 + (15 << 7)] & 255));
   627:             if ((p0 | p1 | p2 | p3) == 0 ||
   628:                 (p0 & p1 & p2 & p3) == -1) {  //空白
   629:               sb.append (' ');
   630:               continue;
   631:             }
   632:           }
   633:           int h = ((p0 * 31 + p1) * 31 + p2) * 31 + p3;
   634:           h = ((h >> 16) + h) & 65535;  //ハッシュコード
   635:           HanPat pat = hanTable[h];
   636:           while (pat != null) {  //リストを辿る
   637:             if (pat.p0 == p0 &&
   638:                 pat.p1 == p1 &&
   639:                 pat.p2 == p2 &&
   640:                 pat.p3 == p3) {
   641:               break;
   642:             }
   643:             pat = pat.next;
   644:           }
   645:           if (pat != null) {  //見つかった
   646:             sb.append ((char) pat.c);
   647:             continue;
   648:           }
   649:         }
   650:         //不明
   651:         sb.append ('?');
   652:       }  //for col
   653:     }  //for row
   654:     return sb.toString ();
   655:   }  //getText
   656: 
   657: 
   658: 
   659: }  //class TextCopy