Annotation of nono/vm/console.cpp, revision 1.1.1.2

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2024 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // メイン画面をコンソールにする
                      9: //
                     10: 
                     11: #include "console.h"
                     12: #include "bitmap.h"
                     13: #include "builtinrom.h"
                     14: #include "comdriver_cons.h"
                     15: #include "mainapp.h"
                     16: #include "scheduler.h"
                     17: #include "wxcolor.h"
                     18: #include <algorithm>
                     19: 
                     20: // エスケープシーケンス等。
                     21: #define ESC            '\x1b'
                     22: #define CSI            '['
                     23: 
                     24: #define PRINTLOG(fmt...)       do {    \
                     25:        if (log) {      \
                     26:                fprintf(log, fmt);      \
                     27:                fflush(log);    \
                     28:        }       \
                     29: } while (0)
                     30: 
                     31: // v[] がいずれかでも true なら true を返す。
                     32: static bool
                     33: AnyOf(const std::vector<bool>& v)
                     34: {
                     35:        return std::any_of(v.begin(), v.end(), [](bool x) { return x; });
                     36: }
                     37: 
                     38: // コンストラクタ
                     39: ConsoleDevice::ConsoleDevice()
                     40:        : inherited(OBJ_CONSOLE)
                     41: {
                     42:        screen.resize(width * height);
                     43:        dirty.resize(height);
                     44:        pending.resize(height);
                     45: }
                     46: 
                     47: // デストラクタ
                     48: ConsoleDevice::~ConsoleDevice()
                     49: {
                     50:        if (log) {
                     51:                fclose(log);
                     52:                log = NULL;
                     53:        }
                     54: }
                     55: 
                     56: // 初期化
                     57: bool
                     58: ConsoleDevice::Init()
                     59: {
                     60:        renderer = GetRenderer();
                     61: 
                     62:        // ログファイル。
                     63:        if (gMainApp.console_logfile) {
                     64:                log = fopen(gMainApp.console_logfile, "w");
                     65:                if (log == NULL) {
                     66:                        warn("console logfile '%s'", gMainApp.console_logfile);
                     67:                        return false;
                     68:                }
                     69:        }
                     70: 
                     71:        vsync_event.func = ToEventCallback(&ConsoleDevice::VSyncCallback);
                     72:        vsync_event.time = 16666.667_usec;
                     73:        vsync_event.SetName("Console V-Sync");
                     74:        scheduler->RegistEvent(vsync_event);
                     75: 
                     76:        return true;
                     77: }
                     78: 
                     79: // COM ドライバを接続。
                     80: // NULL を指定すると解除。
                     81: // (HostCOM の cons ドライバが呼ぶ)
                     82: void
                     83: ConsoleDevice::Attach(COMDriver *comdriver_)
                     84: {
                     85:        comdriver = comdriver_;
                     86: }
                     87: 
                     88: void
                     89: ConsoleDevice::ResetHard(bool poweron)
                     90: {
                     91:        if (poweron) {
                     92:                // 最初に一回フチを含めて描画する。
                     93:                init_screen = true;
                     94: 
                     95:                // シリアルコンソールなのでリセットには反応しない。
                     96:                Clear();
                     97:                Locate(0, 0);
                     98:        }
                     99: 
                    100:        if (comdriver) {
                    101:                scheduler->RestartEvent(vsync_event);
                    102:        }
                    103: 
                    104:        ResetTerminal();
                    105: }
                    106: 
                    107: void
                    108: ConsoleDevice::VSyncCallback(Event& ev)
                    109: {
                    110:        bool update_needed;
                    111: 
                    112:        // 更新 (dirty[]) があれば pending[] に重ねる。
                    113:        {
                    114:                std::unique_lock<std::mutex> lock(mtx);
                    115:                for (int y = 0; y < height; y++) {
                    116:                        // std::vector<bool> には operator|=() がない。
                    117:                        if (__predict_false(dirty[y])) {
                    118:                                pending[y] = true;
                    119:                                dirty[y] = false;
                    120:                        }
                    121:                }
                    122: 
                    123:                update_needed = AnyOf(pending);
                    124:        }
                    125: 
                    126:        // 更新の必要があれば Render に作画指示。
                    127:        if (update_needed) {
                    128:                renderer->NotifyRender();
                    129:        }
                    130: 
                    131:        scheduler->StartEvent(ev);
                    132: }
                    133: 
                    134: // 端末の状態をリセットする。
                    135: // (画面のクリアはここではしない?)
                    136: void
                    137: ConsoleDevice::ResetTerminal()
                    138: {
                    139:        ResetState();
                    140:        SetAttr(0);
                    141:        scroll_top = 0;
                    142:        scroll_btm = height - 1;
                    143:        save_curx = 0;
                    144:        save_cury = 0;
                    145: }
                    146: 
                    147: // エスケープシーケンスの状態を初期化する。
                    148: void
                    149: ConsoleDevice::ResetState()
                    150: {
                    151:        state = 0;
                    152:        seq.clear();
                    153:        arg.clear();
                    154: }
                    155: 
                    156: // ch をログ出力する。
                    157: void
                    158: ConsoleDevice::PutcharDebug(uint32 ch)
                    159: {
                    160:        if (ch == '\n') {
                    161:                // 改行が来たらログも改行する。
                    162:                fputs("\\n\n", log);
                    163:                log_newline = true;
                    164:        } else {
                    165:                if (ch == ESC) {
                    166:                        // 読みやすさのため ESC の前で改行したい。
                    167:                        if (log_newline == false) {
                    168:                                fputc('\n', log);
                    169:                        }
                    170:                        fputs("ESC", log);
                    171:                } else if (ch == '\r') {
                    172:                        fputs("\\r", log);
                    173:                } else if (ch == '\t') {
                    174:                        fputs("\\t", log);
                    175:                } else if (ch < 0x20 || ch >= 0x7f) {
                    176:                        fprintf(log, "\\x%02x", ch);
                    177:                } else {
                    178:                        fputc(ch, log);
                    179:                }
                    180:                log_newline = false;
                    181:        }
                    182:        fflush(log);
                    183: }
                    184: 
                    185: // シリアルコンソールから来る出力。
                    186: // ホストドライバスレッドから呼ばれる。
                    187: void
                    188: ConsoleDevice::Putchar(uint32 ch)
                    189: {
                    190:        if (__predict_false(log)) {
                    191:                PutcharDebug(ch);
                    192:        }
                    193: 
                    194:        switch (state) {
                    195:         case ESC:
                    196:                if (PutcharESC(ch)) {
                    197:                        return;
                    198:                }
                    199:                break;
                    200: 
                    201:         case CSI:
                    202:                if (PutcharCSI(ch)) {
                    203:                        return;
                    204:                }
                    205:                break;
                    206: 
                    207:         case '(':      // G0
                    208:                switch (ch) {
                    209:                 case '0':              // DEC 特殊記号
                    210:                        SetAttr(cur_attr | ATTR_DECSG);
                    211:                        break;
                    212:                 case 'B':              // ASCII
                    213:                 default:
                    214:                        SetAttr(cur_attr & ~ATTR_DECSG);
                    215:                        break;
                    216:                }
                    217:                ResetState();
                    218:                return;
                    219: 
                    220:         case ')':      // G1
                    221:         case '$':      // 94 multibyte
                    222:         case '#':
                    223:                // とりあえず何もしない。
                    224:                ResetState();
                    225:                return;
                    226: 
                    227:         case '?':      // CSI '?'
                    228:                if (PutcharCSIQ(ch)) {
                    229:                        return;
                    230:                }
                    231:                break;
                    232: 
                    233:         default:
                    234:                PutcharPlain(ch);
                    235:                return;
                    236:        }
                    237: 
                    238:        // シーケンスを破棄。ここまでのを表示して平文に戻る。
                    239:        putlog(0, "Unknown Sequence:%s", Dump(ch).c_str());
                    240:        for (auto c : seq) {
                    241:                Putc(c);
                    242:        }
                    243:        Putc(ch);
                    244:        ResetState();
                    245: }
                    246: 
                    247: // 何のシーケンスでもない1文字を表示する。
                    248: void
                    249: ConsoleDevice::PutcharPlain(uint32 ch)
                    250: {
                    251:        switch (ch) {
                    252:         case '\x00':   // NUL
                    253:         case '\x01':   // SOH
                    254:         case '\x02':   // STX
                    255:         case '\x03':   // ETX
                    256:         case '\x04':   // EOT
                    257:         case '\x05':   // ENQ
                    258:         case '\x06':   // ACK
                    259:                break;
                    260:         case '\x07':   // BEL
                    261:                // とりあえず無視。
                    262:                break;
                    263: 
                    264:         case '\x08':   // BS
                    265:                LocateX(cur_x - 1);
                    266:                return;
                    267: 
                    268:         case '\t':             // TAB
                    269:                // XXX 右端どうなる?
                    270:                LocateX(roundup(cur_x, 8));
                    271:                return;
                    272: 
                    273:         case '\n':             // LF
                    274:         case '\x0b':   // VT
                    275:         case '\x0c':   // FF
                    276:                LF();
                    277:                return;
                    278: 
                    279:         case '\r':     // CR
                    280:                CR();
                    281:                return;
                    282: 
                    283:         case '\x0e':   // SO
                    284:         case '\x0f':   // SI
                    285:                // Change GL
                    286:                break;
                    287: 
                    288:         case '\x10':   // DLE
                    289:         case '\x11':   // DC1/XON
                    290:         case '\x12':   // DC2
                    291:         case '\x13':   // DC3/XOFF
                    292:         case '\x14':   // DC4
                    293:         case '\x15':   // NAK
                    294:         case '\x16':   // SYN
                    295:         case '\x17':   // ETB
                    296:                break;
                    297: 
                    298:         case '\x18':   // CAN
                    299:                // Cancel
                    300:                ResetState();
                    301:                return;
                    302: 
                    303:         case '\x19':   // EM
                    304:                break;
                    305: 
                    306:         case '\x1a':   // SUB
                    307:                ResetState();
                    308:                return;
                    309: 
                    310:         case ESC:
                    311:                seq.push_back(ch);
                    312:                state = ch;
                    313:                return;
                    314: 
                    315:         case '\x1c':   // FS
                    316:         case '\x1d':   // GS
                    317:         case '\x1e':   // RS
                    318:         case '\x1f':   // US
                    319:                break;
                    320: 
                    321:         default:
                    322:                if (ch < 0x80) {
                    323:                        // ここが通常の1文字出力。
                    324:                        Putc(ch);
                    325:                        return;
                    326:                }
                    327:                // 8ビットシーケンスは無視?
                    328:                break;
                    329:        }
                    330:        putlog(2, "Ignore: \\x%02x", ch);
                    331: }
                    332: 
                    333: // ESC の次の文字を処理する。
                    334: // 処理すれば true、知らないシーケンスなので中止する場合は false を返す。
                    335: bool
                    336: ConsoleDevice::PutcharESC(uint32 ch)
                    337: {
                    338:        switch (ch) {
                    339:         case '[':              // CSI
                    340:         case '(':              // G0
                    341:         case ')':              // G1
                    342:         case '$':              // 94 multibyte
                    343:         case '#':              // Font width/height control
                    344:                seq.push_back(ch);
                    345:                state = ch;
                    346:                return true;
                    347: 
                    348:         case '\\':             // ST
                    349:                break;
                    350: 
                    351:         case '7':              // カーソル位置保存
                    352:                save_curx = cur_x;
                    353:                save_cury = cur_y;
                    354:                break;
                    355: 
                    356:         case '8':              // カーソル位置復帰
                    357:                Locate(save_curx, save_cury);
                    358:                break;
                    359: 
                    360:         case 'c':              // Hard terminal reset
                    361:                Clear();
                    362:                ResetTerminal();
                    363:                Locate(0, 0);
                    364:                break;
                    365: 
                    366:         case 'M':              // 1行上に移動 (画面を1行下にスクロール)
                    367:                ScrollDown();
                    368:                Locate(0, 0);
                    369:                break;
                    370: 
                    371:         case '*':              // G2
                    372:         case '+':              // G3
                    373:         case 'B':              // ASCII
                    374:         case 'A':              // ISO Latin 1
                    375:         case '<':              //
                    376:         case '0':              // DEC special graphics
                    377:         case '-':              // G1 (96)
                    378:         case '.':              // G2
                    379:         case '/':              // G3
                    380:         case '4':              // Dutch
                    381:         case '5':
                    382:         case '6':              // Norwegian/Danish
                    383:         case 'C':              // Finnish
                    384:         case 'R':              // French
                    385:         case 'Q':              // French canadian
                    386:         case 'K':              // German
                    387:         case 'Y':              // Italian
                    388:         // "%5" とかの2文字のやつは NetBSD/x68k ite も未対応。
                    389:         case '`':
                    390:         case 'n':
                    391:         case '}':
                    392:         case 'o':
                    393:         case '|':
                    394:         case '~':
                    395:         case '=':
                    396:         case '>':
                    397:                putlog(2, "Ignore:%s", Dump(ch).c_str());
                    398:                break;
                    399: 
                    400:         case 'Z':              // 端末属性を応答する。
                    401:         default:
                    402:                return false;
                    403:        }
                    404: 
                    405:        ResetState();
                    406:        return true;
                    407: }
                    408: 
                    409: // CSI の次の文字を処理する。
                    410: // 処理すれば true、知らないシーケンスなので中止する場合は false を返す。
                    411: bool
                    412: ConsoleDevice::PutcharCSI(uint32 ch)
                    413: {
                    414:        switch (ch) {
                    415:         case '0':
                    416:         case '1':
                    417:         case '2':
                    418:         case '3':
                    419:         case '4':
                    420:         case '5':
                    421:         case '6':
                    422:         case '7':
                    423:         case '8':
                    424:         case '9':
                    425:         case ';':
                    426:         case '\"':
                    427:         case '$':
                    428:         case '>':
                    429:                seq.push_back(ch);
                    430:                arg.push_back(ch);
                    431:                return true;
                    432: 
                    433:         case 'A':
                    434:         {
                    435:                int n = atoi(arg.c_str());
                    436:                if (n == 0) {
                    437:                        n = 1;
                    438:                }
                    439:                LocateY(cur_y - n);
                    440:                ResetState();
                    441:                return true;
                    442:         }
                    443: 
                    444:         case 'B':
                    445:         {
                    446:                int n = atoi(arg.c_str());
                    447:                if (n == 0) {
                    448:                        n = 1;
                    449:                }
                    450:                LocateY(cur_y + n);
                    451:                ResetState();
                    452:                return true;
                    453:         }
                    454: 
                    455:         case 'C':
                    456:         {
                    457:                int n = atoi(arg.c_str());
                    458:                if (n == 0) {
                    459:                        n = 1;
                    460:                }
                    461:                LocateX(cur_x + n);
                    462:                ResetState();
                    463:                return true;
                    464:         }
                    465: 
                    466:         case 'D':
                    467:         {
                    468:                int n = atoi(arg.c_str());
                    469:                if (n == 0) {
                    470:                        n = 1;
                    471:                }
                    472:                LocateX(cur_x - n);
                    473:                ResetState();
                    474:                return true;
                    475:         }
                    476: 
                    477:         case 'H':
                    478:         {
                    479:                // CSI <y> ; <x> H … (x-1, y-1) にカーソルを移動。
                    480:                int y = atoi(arg.c_str());
                    481:                int x = 0;
                    482:                const char *p = strchr(arg.c_str(), ';');
                    483:                if (p) {
                    484:                        x = atoi(p + 1);
                    485:                }
                    486:                if (x > 0) {
                    487:                        x--;
                    488:                }
                    489:                if (y > 0) {
                    490:                        y--;
                    491:                }
                    492:                Locate(x, y);
                    493:                ResetState();
                    494:                return true;
                    495:         }
                    496: 
                    497:         case 'J':
                    498:         {
                    499:                // CSI [<n>] J
                    500:                // <n> が 0 か省略なら、カーソル位置から右下までを消去。
                    501:                // <n> が 1 なら、カーソル位置から左上までを消去。
                    502:                // <n> が 2 なら、全画面消去。
                    503:                // XXX SPA と ERM は未対応。
                    504:                int n = atoi(arg.c_str());
                    505:                switch (n) {
                    506:                 default:       // 知らんけど
                    507:                 case 0:
                    508:                        for (int y = cur_y; y < height - 1; y++) {
                    509:                                int x = (y == cur_y) ? cur_x : 0;
                    510:                                for (; x < width; x++) {
                    511:                                        Setc(x, y, ' ' | cur_attr);
                    512:                                }
                    513:                        }
                    514:                        break;
                    515:                 case 1:
                    516:                        for (int y = 0; y <= cur_y; y++) {
                    517:                                int xend = (y == cur_y) ? cur_x : (width - 1);
                    518:                                for (int x = 0; x <= xend; x++) {
                    519:                                        Setc(x, y, ' ' | cur_attr);
                    520:                                }
                    521:                        }
                    522:                        break;
                    523:                 case 2:
                    524:                        // カーソル位置は移動しないまま?
                    525:                        Clear();
                    526:                        break;
                    527:                }
                    528:                ResetState();
                    529:                return true;
                    530:         }
                    531: 
                    532:         case 'K':
                    533:         {
                    534:                // CSI [<n>] K
                    535:                // <n> が 0 か省略なら、カーソル位置の右側を消去。
                    536:                // <n> が 1 なら、カーソル位置の左側を消去。
                    537:                // <n> が 2 なら、カーソル行を消去。
                    538:                int n = atoi(arg.c_str());
                    539:                int x0;
                    540:                int x1;
                    541:                switch (n) {
                    542:                 default:       // 知らんけど
                    543:                 case 0:
                    544:                        x0 = cur_x;
                    545:                        x1 = width - 1;
                    546:                        break;
                    547:                 case 1:
                    548:                        x0 = 0;
                    549:                        x1 = cur_x;
                    550:                        break;
                    551:                 case 2:
                    552:                        x0 = 0;
                    553:                        x1 = width - 1;
                    554:                        break;
                    555:                }
                    556:                for (int x = x0; x <= x1; x++) {
                    557:                        Setc(x, cur_y, ' ' | cur_attr);
                    558:                }
                    559:                ResetState();
                    560:                return true;
                    561:         }
                    562: 
                    563:         case 'm':
                    564:         {
                    565:                // CSI 7 ; 37 m みたいにセミコロンで区切ってパラメータを複数書ける。
                    566:                // パラメータには 38:2:rr:gg:bb みたいにコロンで区切ったひとかたまり
                    567:                // もある。
                    568:                const char *ap = arg.c_str();
                    569:                for (;;) {
                    570:                        int n = atoi(ap);
                    571:                        switch (n) {
                    572:                         case 0:                        // すべての属性を解除
                    573:                                SetAttr(0);
                    574:                                break;
                    575:                         case 1:                        // ボールドをセット
                    576:                                SetAttr(cur_attr | ATTR_BOLD);
                    577:                                break;
                    578:                         case 2:                        // 低輝度をセット (対応予定なし)
                    579:                                break;
                    580:                         case 3:                        // イタリックをセット
                    581:                                SetAttr(cur_attr | ATTR_ITALIC);
                    582:                                break;
                    583:                         case 4:                        // 下線をセット
                    584:                                SetAttr(cur_attr | ATTR_UNDERLINE);
                    585:                                break;
                    586:                         case 5:                        // 低速点滅をセット (対応予定なし)
                    587:                                break;
                    588:                         case 6:                        // 高速点滅をセット (対応予定なし)
                    589:                                break;
                    590:                         case 7:                        // 反転をセット
                    591:                                SetAttr(cur_attr | ATTR_REVERSE);
                    592:                                break;
                    593:                         case 8:                        // 文字色を背景色と同じにする
                    594:                                break;
                    595:                         case 9:                        // 打ち消し線をセット
                    596:                                SetAttr(cur_attr | ATTR_STRIKE);
                    597:                                break;
                    598:                         case 10 ... 20:        // フォントセットの設定?
                    599:                                break;
                    600:                         case 21:                       // 二重下線をセット (対応予定なし)
                    601:                                break;
                    602:                         case 22:                       // ボールド(と低輝度)を解除
                    603:                                SetAttr(cur_attr & ~ATTR_BOLD);
                    604:                                break;
                    605:                         case 23:                       // イタリックを解除
                    606:                                SetAttr(cur_attr & ~ATTR_ITALIC);
                    607:                                break;
                    608:                         case 24:                       // 下線を解除
                    609:                                SetAttr(cur_attr & ~ATTR_UNDERLINE);
                    610:                                break;
                    611:                         case 25:                       // 点滅を解除
                    612:                                break;
                    613:                         case 26:                       // ?
                    614:                                break;
                    615:                         case 27:                       // 反転を解除
                    616:                                SetAttr(cur_attr & ~ATTR_REVERSE);
                    617:                                break;
                    618:                         case 28:                       // シークレットを解除
                    619:                                break;
                    620:                         case 29:                       // 打ち消し線を解除
                    621:                                SetAttr(cur_attr & ~ATTR_STRIKE);
                    622:                                break;
                    623:                         case 30 ... 37:        // 文字色の設定
                    624:                                break;
                    625:                         case 38:                       // 文字色(拡張)を設定
                    626:                                break;
                    627:                         case 39:                       // 文字色をデフォルトに戻す
                    628:                                break;
                    629:                         case 40 ... 47:        // 背景色を設定
                    630:                                break;
                    631:                         case 48:                       // 背景色(拡張)を設定
                    632:                                break;
                    633:                         case 49:                       // 背景色をデフォルトに戻す
                    634:                                break;
                    635:                         case 51:                       // □を重ねる (対応予定なし)
                    636:                                break;
                    637:                         case 52:                       // ○を重ねる (対応予定なし)
                    638:                                break;
                    639:                         case 53:                       // 上線をセット
                    640:                                SetAttr(cur_attr | ATTR_OVERLINE);
                    641:                                break;
                    642:                         case 54:                       // □○を取り消し
                    643:                                break;
                    644:                         case 55:                       // 上線を取り消し
                    645:                                SetAttr(cur_attr & ~ATTR_OVERLINE);
                    646:                                break;
                    647:                         case 60 ... 63:        // 縦線 (対応予定なし)
                    648:                                break;
                    649:                         case 64:                       // 二重打ち消し線 (対応予定なし)
                    650:                                break;
                    651:                         case 65:                       // 60-64 を取り消し
                    652:                                break;
                    653:                         case 90 ... 97:        // 文字色(高輝度)を設定
                    654:                                break;
                    655:                         case 100 ... 107:      // 背景色(高輝度)を設定
                    656:                                break;
                    657:                         default:
                    658:                                // 無視
                    659:                                break;
                    660:                        }
                    661: 
                    662:                        if (*ap == '\0') {
                    663:                                break;
                    664:                        }
                    665:                        ap = strchr(ap + 1, ';');
                    666:                        if (ap == NULL) {
                    667:                                break;
                    668:                        }
                    669:                        ap++;
                    670:                }
                    671: 
                    672:                ResetState();
                    673:                return true;
                    674:         }
                    675: 
                    676:         case 'r':
                    677:         {
                    678:                // CSI <t> ; <b> r。<t> 省略時は 1。<b> 省略時は画面最下行。
                    679:                int top = atoi(arg.c_str());
                    680:                int btm = height;
                    681:                const char *p = strchr(arg.c_str(), ';');
                    682:                if (p) {
                    683:                        btm = atoi(p + 1);
                    684:                }
                    685:                if (top > 0) {
                    686:                        top--;
                    687:                }
                    688:                if (btm > 0) {
                    689:                        btm--;
                    690:                }
                    691:                scroll_top = top;
                    692:                scroll_btm = btm;
                    693:                ResetState();
                    694:                return true;
                    695:         }
                    696: 
                    697:         case '?':
                    698:                seq.push_back(ch);
                    699:                state = ch;
                    700:                return true;
                    701: 
                    702:         default:
                    703:                return false;
                    704:        }
                    705: }
                    706: 
                    707: // CSI '?' の次の文字を処理する。
                    708: // 処理すれば true、知らないシーケンスなので中止する場合は false を返す。
                    709: bool
                    710: ConsoleDevice::PutcharCSIQ(uint32 ch)
                    711: {
                    712:        switch (ch) {
                    713:         case '0':
                    714:         case '1':
                    715:         case '2':
                    716:         case '3':
                    717:         case '4':
                    718:         case '5':
                    719:         case '6':
                    720:         case '7':
                    721:         case '8':
                    722:         case '9':
                    723:         case ';':
                    724:         case '\"':
                    725:         case '$':
                    726:         case '>':
                    727:                seq.push_back(ch);
                    728:                arg.push_back(ch);
                    729:                return true;
                    730: 
                    731:         case 'h':      // 拡張オプションを設定
                    732:         case 'l':      // 拡張オプションを解除
                    733:                // CSI '?' <n> h
                    734:                // CSI '?' <n> l
                    735:                // 全部未対応。
                    736:                putlog(2, "Ignored:%s", Dump(ch).c_str());
                    737:                ResetState();
                    738:                return true;
                    739: 
                    740:         default:
                    741:                return false;
                    742:        }
                    743: }
                    744: 
                    745: // 現在の seq を表示用文字列にして返す。
                    746: std::string
                    747: ConsoleDevice::Dump() const
                    748: {
                    749:        return Dump(seq);
                    750: }
                    751: 
                    752: // 現在の seq と ch を表示用文字列にして返す。
                    753: // 大抵の場合最後の1文字はまだ seq に入っていないのでこの形式があると便利。
                    754: std::string
                    755: ConsoleDevice::Dump(uint32 ch) const
                    756: {
                    757:        std::vector<uint8> tmp = seq;
                    758:        tmp.push_back(ch);
                    759:        return Dump(tmp);
                    760: }
                    761: 
                    762: // エスケープシーケンスを表示用文字列にして返す。
                    763: // 戻り文字列には先頭に空白が入っている。
                    764: /*static*/ std::string
                    765: ConsoleDevice::Dump(const std::vector<uint8>& src)
                    766: {
                    767:        std::string dst;
                    768: 
                    769:        for (auto ch : src) {
                    770:                if (ch == ESC) {
                    771:                        dst += " ESC";
                    772:                } else if (ch < ' ' || ch >= 0x7f) {
                    773:                        dst += string_format(" \\x%02x", ch);
                    774:                } else if (ch == ' ') {
                    775:                        dst += " ' '";
                    776:                } else {
                    777:                        dst += ' ';
                    778:                        dst += (char)ch;
                    779:                }
                    780:        }
                    781:        return dst;
                    782: }
                    783: 
                    784: // 画面を消去する。
                    785: // カーソル位置は変わらない。属性もクリアされない。
                    786: void
                    787: ConsoleDevice::Clear()
                    788: {
                    789:        std::fill(screen.begin(), screen.end(), ' ' | cur_attr);
                    790:        std::fill(dirty.begin(), dirty.end(), true);
                    791: }
                    792: 
                    793: // カーソルの X 座標を移動。(画面をはみ出さないようにクリップされる)
                    794: void
                    795: ConsoleDevice::LocateX(int x)
                    796: {
                    797:        if (__predict_false(x < 0)) {
                    798:                x = 0;
                    799:        }
                    800:        if (__predict_false(x > width - 1)) {
                    801:                x = width - 1;
                    802:        }
                    803:        cur_x = x;
                    804:        dirty[cur_y] = true;
                    805: }
                    806: 
                    807: // カーソルの Y 座標を移動。(画面をはみ出さないようにクリップされる)
                    808: void
                    809: ConsoleDevice::LocateY(int y)
                    810: {
                    811:        if (__predict_false(y < 0)) {
                    812:                y = 0;
                    813:        }
                    814:        if (__predict_false(y > height - 1)) {
                    815:                y = height - 1;
                    816:        }
                    817:        dirty[cur_y] = true;
                    818:        cur_y = y;
                    819:        dirty[cur_y] = true;
                    820: }
                    821: 
                    822: // 文字出力後のカーソル移動。
                    823: void
                    824: ConsoleDevice::Ascend()
                    825: {
                    826:        cur_x++;
                    827:        dirty[cur_y] = true;
                    828:        if (cur_x >= width) {
                    829:                CRLF();
                    830:        }
                    831: }
                    832: 
                    833: // 復帰。
                    834: void
                    835: ConsoleDevice::CR()
                    836: {
                    837:        LocateX(0);
                    838: }
                    839: 
                    840: // 改行。(DECSTBM の影響を受ける)
                    841: void
                    842: ConsoleDevice::LF()
                    843: {
                    844:        dirty[cur_y] = true;
                    845:        cur_y++;
                    846:        if (cur_y >= scroll_btm) {
                    847:                ScrollUp();
                    848:                cur_y = scroll_btm;
                    849:        }
                    850:        dirty[cur_y] = true;
                    851: }
                    852: 
                    853: // 全画面を1行上にスクロール。(DECSTBM の影響を受ける)
                    854: // カーソル位置は移動しない。
                    855: void
                    856: ConsoleDevice::ScrollUp()
                    857: {
                    858:        int dst = scroll_top * width;
                    859:        int lines = scroll_btm - scroll_top;
                    860:        memmove(&screen[dst], &screen[dst + width],
                    861:                lines * width * sizeof(screen[0]));
                    862:        uint32 ch = ' ' | cur_attr;
                    863:        for (int x = 0; x < width; x++) {
                    864:                Setc(x, scroll_btm, ch);
                    865:        }
                    866:        std::fill(dirty.begin(), dirty.end(), true);
                    867: }
                    868: 
                    869: // 全画面を1行下にスクロール。(DECSTBM の影響を受ける)
                    870: // カーソル位置は移動しない。
                    871: void
                    872: ConsoleDevice::ScrollDown()
                    873: {
                    874:        int src = scroll_top * width;
                    875:        int lines = scroll_btm - scroll_top;
                    876:        memmove(&screen[src + width], &screen[src],
                    877:                lines * width * sizeof(screen[0]));
                    878:        uint32 ch = ' ' | cur_attr;
                    879:        for (int x = 0; x < width; x++) {
                    880:                Setc(x, scroll_top, ch);
                    881:        }
                    882:        std::fill(dirty.begin(), dirty.end(), true);
                    883: }
                    884: 
                    885: // 現在位置に、現在の属性で文字 ch を出力する。
                    886: // 出力後カーソルは移動する。
                    887: void
                    888: ConsoleDevice::Putc(uint32 ch)
                    889: {
                    890:        if (ch == '\n') {
                    891:                CR();
                    892:                LF();
                    893:                return;
                    894:        }
                    895: 
                    896:        Setc(cur_x, cur_y, ch | cur_attr);
                    897:        Ascend();
                    898: }
                    899: 
                    900: // (x, y) の位置に chattr を出力する。
                    901: // 出力後カーソルは移動しない。
                    902: // 現在の attr は参照しない (呼び出す側が指定すること)。
                    903: void
                    904: ConsoleDevice::Setc(int x, int y, uint32 chattr)
                    905: {
                    906:        int pos = y * width + x;
                    907:        assert(pos >= 0);
                    908:        assert(pos < width * height);
                    909:        screen[pos] = chattr;
                    910: }
                    911: 
                    912: // 現在の属性を設定する。
                    913: // ほぼログ出力のため。
                    914: void
                    915: ConsoleDevice::SetAttr(uint32 new_attr)
                    916: {
                    917:        if (cur_attr == new_attr) {
                    918:                return;
                    919:        }
                    920:        cur_attr = new_attr;
                    921: 
                    922:        if (log) {
                    923:                std::string buf;
                    924:                if ((cur_attr & ATTR_BOLD)) {
                    925:                        buf += ",ATTR_BOLD";
                    926:                }
                    927:                if ((cur_attr & ATTR_ITALIC)) {
                    928:                        buf += ",ATTR_ITALIC";
                    929:                }
                    930:                if ((cur_attr & ATTR_UNDERLINE)) {
                    931:                        buf += ",ATTR_UNDERLINE";
                    932:                }
                    933:                if ((cur_attr & ATTR_STRIKE)) {
                    934:                        buf += ",ATTR_STRIKE";
                    935:                }
                    936:                if ((cur_attr & ATTR_OVERLINE)) {
                    937:                        buf += ",ATTR_OVERLINE";
                    938:                }
                    939:                if ((cur_attr & ATTR_DECSG)) {
                    940:                        buf += ",ATTR_DECSG";
                    941:                }
                    942:                if ((cur_attr & ATTR_REVERSE)) {
                    943:                        buf += ",ATTR_REVERSE";
                    944:                }
                    945: 
                    946:                if (buf.empty()) {
                    947:                        buf = "<ATTR_NORMAL>";
                    948:                } else {
                    949:                        buf[0] = '<';
                    950:                        buf += '>';
                    951:                }
                    952:                fputs(buf.c_str(), log);
                    953:                fflush(log);
                    954:        }
                    955: }
                    956: 
                    957: // 画面合成。
                    958: // レンダリングスレッドから呼ばれる。
                    959: bool
                    960: ConsoleDevice::Render(BitmapRGBX& dst)
                    961: {
                    962:        if (comdriver == NULL) {
                    963:                return false;
                    964:        }
                    965: 
                    966:        bool updated = false;
                    967: 
                    968:        // フチも含めて再描画。
                    969:        if (__predict_false(init_screen)) {
                    970:                init_screen = false;
                    971:                dst.Fill(palette[0]);
                    972:                updated = true;
                    973:        }
                    974: 
                    975:        // 行ごとに更新があるか調べる。
                    976:        std::vector<bool> modified(height);
                    977:        {
                    978:                std::unique_lock<std::mutex> lock(mtx);
                    979:                modified = pending;
                    980:                std::fill(pending.begin(), pending.end(), false);
                    981:        }
                    982:        updated |= AnyOf(modified);
                    983: 
                    984:        const uint8 *cgrom8x16 = Builtin::CGROM8x16(0);
                    985:        for (uint y = 0; y < height; y++) {
                    986:                if (__predict_false(modified[y])) {
                    987:                        uint py = Padding + y * font_height;
                    988:                        const uint32 *s = &screen[y * width];
                    989:                        for (uint x = 0; x < width; x++) {
                    990:                                uint px = Padding + x * font_width;
                    991:                                uint32 attr = *s++;
                    992:                                // とりあえず上半分(G1)も無視。
                    993:                                uint32 ch = attr & 0x7f;
                    994:                                // 属性による反転。
                    995:                                int paloff = 0;
                    996:                                if ((attr & ATTR_REVERSE) != 0) {
                    997:                                        paloff ^= 1;
                    998:                                }
                    999:                                // カーソル位置は更に反転。
                   1000:                                if (x == cur_x && y == cur_y) {
                   1001:                                        paloff ^= 1;
                   1002:                                }
                   1003: 
                   1004:                                const uint8 *font;
                   1005:                                if ((attr & ATTR_DECSG) && ('j' <= ch && ch <= 'x')) {
                   1006:                                        font = &decsg8x16[(ch - 'j') * font_height];
                   1007:                                } else {
                   1008:                                        font = &cgrom8x16[ch * font_height];
                   1009:                                }
                   1010:                                BitmapI1 bc1(font, font_width, font_height);
                   1011:                                if (__predict_false((attr & ATTR_ITALIC))) {
                   1012:                                        bc1 = bc1.ConvertToItalic();
                   1013:                                }
                   1014:                                if (__predict_false((attr & ATTR_BOLD))) {
                   1015:                                        bc1 = bc1.ConvertToBold();
                   1016:                                }
                   1017: 
                   1018:                                dst.DrawBitmapI1(px, py, bc1, &palette[paloff]);
                   1019: 
                   1020:                                // 下線、上線、取り消し線
                   1021:                                if (__predict_false((attr & ATTR_LINEMASK))) {
                   1022:                                        Color fg = palette[paloff ^ 1];
                   1023:                                        if ((attr & ATTR_OVERLINE)) {
                   1024:                                                dst.DrawLineH(fg, px, py + 0, px + font_width);
                   1025:                                        }
                   1026:                                        if ((attr & ATTR_STRIKE)) {
                   1027:                                                dst.DrawLineH(fg, px, py + 9, px + font_width);
                   1028:                                        }
                   1029:                                        if ((attr & ATTR_UNDERLINE)) {
                   1030:                                                dst.DrawLineH(fg, px, py + 14, px + font_width);
                   1031:                                        }
                   1032:                                }
                   1033:                        }
                   1034:                }
                   1035:        }
                   1036: 
                   1037:        return updated;
                   1038: }
                   1039: 
                   1040: #define B(x)   (0b##x)
                   1041: #define B2(x)  (B(x) >> 8), (B(x) & 0xff)
                   1042: 
                   1043: // DEC Special Graphics Character Set フォント。(罫線のみ)
                   1044: /*static*/ const uint8 ConsoleDevice::decsg8x16[15 * font_height] = {
                   1045:        B(00010000),    // [0] j:┘
                   1046:        B(00010000),
                   1047:        B(00010000),
                   1048:        B(00010000),
                   1049:        B(00010000),
                   1050:        B(00010000),
                   1051:        B(00010000),
                   1052:        B(11110000),
                   1053:        B(00000000),
                   1054:        B(00000000),
                   1055:        B(00000000),
                   1056:        B(00000000),
                   1057:        B(00000000),
                   1058:        B(00000000),
                   1059:        B(00000000),
                   1060:        B(00000000),
                   1061: 
                   1062:        B(00000000),    // [1] k:┐
                   1063:        B(00000000),
                   1064:        B(00000000),
                   1065:        B(00000000),
                   1066:        B(00000000),
                   1067:        B(00000000),
                   1068:        B(00000000),
                   1069:        B(11110000),
                   1070:        B(00010000),
                   1071:        B(00010000),
                   1072:        B(00010000),
                   1073:        B(00010000),
                   1074:        B(00010000),
                   1075:        B(00010000),
                   1076:        B(00010000),
                   1077:        B(00010000),
                   1078: 
                   1079:        B(00000000),    // [2] l:┌
                   1080:        B(00000000),
                   1081:        B(00000000),
                   1082:        B(00000000),
                   1083:        B(00000000),
                   1084:        B(00000000),
                   1085:        B(00000000),
                   1086:        B(00011111),
                   1087:        B(00010000),
                   1088:        B(00010000),
                   1089:        B(00010000),
                   1090:        B(00010000),
                   1091:        B(00010000),
                   1092:        B(00010000),
                   1093:        B(00010000),
                   1094:        B(00010000),
                   1095: 
                   1096:        B(00010000),    // [3] m:└
                   1097:        B(00010000),
                   1098:        B(00010000),
                   1099:        B(00010000),
                   1100:        B(00010000),
                   1101:        B(00010000),
                   1102:        B(00010000),
                   1103:        B(00011111),
                   1104:        B(00000000),
                   1105:        B(00000000),
                   1106:        B(00000000),
                   1107:        B(00000000),
                   1108:        B(00000000),
                   1109:        B(00000000),
                   1110:        B(00000000),
                   1111:        B(00000000),
                   1112: 
                   1113:        B(00010000),    // [4] n:┼
                   1114:        B(00010000),
                   1115:        B(00010000),
                   1116:        B(00010000),
                   1117:        B(00010000),
                   1118:        B(00010000),
                   1119:        B(00010000),
                   1120:        B(11111111),
                   1121:        B(00010000),
                   1122:        B(00010000),
                   1123:        B(00010000),
                   1124:        B(00010000),
                   1125:        B(00010000),
                   1126:        B(00010000),
                   1127:        B(00010000),
                   1128:        B(00010000),
                   1129: 
                   1130:        B(00000000),    // [5] o:─(Scan1)
                   1131:        B(11111111),
                   1132:        B(00000000),
                   1133:        B(00000000),
                   1134:        B(00000000),
                   1135:        B(00000000),
                   1136:        B(00000000),
                   1137:        B(00000000),
                   1138:        B(00000000),
                   1139:        B(00000000),
                   1140:        B(00000000),
                   1141:        B(00000000),
                   1142:        B(00000000),
                   1143:        B(00000000),
                   1144:        B(00000000),
                   1145:        B(00000000),
                   1146: 
                   1147:        B(00000000),    // [6] p:─(Scan3)
                   1148:        B(00000000),
                   1149:        B(00000000),
                   1150:        B(00000000),
                   1151:        B(11111111),
                   1152:        B(00000000),
                   1153:        B(00000000),
                   1154:        B(00000000),
                   1155:        B(00000000),
                   1156:        B(00000000),
                   1157:        B(00000000),
                   1158:        B(00000000),
                   1159:        B(00000000),
                   1160:        B(00000000),
                   1161:        B(00000000),
                   1162:        B(00000000),
                   1163: 
                   1164:        B(00000000),    // [7] q:─(Scan5)
                   1165:        B(00000000),
                   1166:        B(00000000),
                   1167:        B(00000000),
                   1168:        B(00000000),
                   1169:        B(00000000),
                   1170:        B(00000000),
                   1171:        B(11111111),
                   1172:        B(00000000),
                   1173:        B(00000000),
                   1174:        B(00000000),
                   1175:        B(00000000),
                   1176:        B(00000000),
                   1177:        B(00000000),
                   1178:        B(00000000),
                   1179:        B(00000000),
                   1180: 
                   1181:        B(00000000),    // [8] r:─(Scan7)
                   1182:        B(00000000),
                   1183:        B(00000000),
                   1184:        B(00000000),
                   1185:        B(00000000),
                   1186:        B(00000000),
                   1187:        B(00000000),
                   1188:        B(00000000),
                   1189:        B(00000000),
                   1190:        B(00000000),
                   1191:        B(11111111),
                   1192:        B(00000000),
                   1193:        B(00000000),
                   1194:        B(00000000),
                   1195:        B(00000000),
                   1196:        B(00000000),
                   1197: 
                   1198:        B(00000000),    // [9] s:─(Scan9)
                   1199:        B(00000000),
                   1200:        B(00000000),
                   1201:        B(00000000),
                   1202:        B(00000000),
                   1203:        B(00000000),
                   1204:        B(00000000),
                   1205:        B(00000000),
                   1206:        B(00000000),
                   1207:        B(00000000),
                   1208:        B(00000000),
                   1209:        B(00000000),
                   1210:        B(00000000),
                   1211:        B(11111111),
                   1212:        B(00000000),
                   1213:        B(00000000),
                   1214: 
                   1215:        B(00010000),    // [10] t:├
                   1216:        B(00010000),
                   1217:        B(00010000),
                   1218:        B(00010000),
                   1219:        B(00010000),
                   1220:        B(00010000),
                   1221:        B(00010000),
                   1222:        B(00011111),
                   1223:        B(00010000),
                   1224:        B(00010000),
                   1225:        B(00010000),
                   1226:        B(00010000),
                   1227:        B(00010000),
                   1228:        B(00010000),
                   1229:        B(00010000),
                   1230:        B(00010000),
                   1231: 
                   1232:        B(00010000),    // [11] u:┤
                   1233:        B(00010000),
                   1234:        B(00010000),
                   1235:        B(00010000),
                   1236:        B(00010000),
                   1237:        B(00010000),
                   1238:        B(00010000),
                   1239:        B(11110000),
                   1240:        B(00010000),
                   1241:        B(00010000),
                   1242:        B(00010000),
                   1243:        B(00010000),
                   1244:        B(00010000),
                   1245:        B(00010000),
                   1246:        B(00010000),
                   1247:        B(00010000),
                   1248: 
                   1249:        B(00010000),    // [12] v:┴
                   1250:        B(00010000),
                   1251:        B(00010000),
                   1252:        B(00010000),
                   1253:        B(00010000),
                   1254:        B(00010000),
                   1255:        B(00010000),
                   1256:        B(11111111),
                   1257:        B(00000000),
                   1258:        B(00000000),
                   1259:        B(00000000),
                   1260:        B(00000000),
                   1261:        B(00000000),
                   1262:        B(00000000),
                   1263:        B(00000000),
                   1264:        B(00000000),
                   1265: 
                   1266:        B(00000000),    // [13] w:┬
                   1267:        B(00000000),
                   1268:        B(00000000),
                   1269:        B(00000000),
                   1270:        B(00000000),
                   1271:        B(00000000),
                   1272:        B(00000000),
                   1273:        B(11111111),
                   1274:        B(00010000),
                   1275:        B(00010000),
                   1276:        B(00010000),
                   1277:        B(00010000),
                   1278:        B(00010000),
                   1279:        B(00010000),
                   1280:        B(00010000),
                   1281:        B(00010000),
                   1282: 
                   1283:        B(00010000),    // [14] x:│
                   1284:        B(00010000),
                   1285:        B(00010000),
                   1286:        B(00010000),
                   1287:        B(00010000),
                   1288:        B(00010000),
                   1289:        B(00010000),
                   1290:        B(00010000),
                   1291:        B(00010000),
                   1292:        B(00010000),
                   1293:        B(00010000),
                   1294:        B(00010000),
                   1295:        B(00010000),
                   1296:        B(00010000),
                   1297:        B(00010000),
                   1298:        B(00010000),
                   1299: };
                   1300: 
                   1301: // パレット。
                   1302: // [0] からだと通常色、[1] からだと反転色になる。
                   1303: /*static*/ const Color ConsoleDevice::palette[3] = {
                   1304:        UD_LIGHT_GREY,  // BG
                   1305:        UD_BLACK,               // FG
                   1306:        UD_LIGHT_GREY,  // BG
                   1307: };
                   1308: 
                   1309: 
                   1310: //
                   1311: // 入力担当デバイス
                   1312: //
                   1313: 
                   1314: // コンストラクタ
                   1315: ConsoleKeyboard::ConsoleKeyboard()
                   1316:        : inherited()
                   1317: {
                   1318: }
                   1319: 
                   1320: // デストラクタ
                   1321: ConsoleKeyboard::~ConsoleKeyboard()
                   1322: {
                   1323: }
                   1324: 
                   1325: // COM ドライバを接続。
                   1326: // (HostCOM の cons ドライバが呼ぶ)
                   1327: void
                   1328: ConsoleKeyboard::Attach(COMDriverCons *comdriver_)
                   1329: {
                   1330:        comdriver = comdriver_;
                   1331: }
                   1332: 
                   1333: // 文字入力。
                   1334: // WXMainView から呼ばれる。
                   1335: void
                   1336: ConsoleKeyboard::CharInput(uint charcode)
                   1337: {
                   1338:        if (comdriver == NULL) {
                   1339:                return;
                   1340:        }
                   1341: 
                   1342:        // charcode は 0x80 以上を独自に使っているので (keyboard.h 参照)、
                   1343:        // それらをシリアルコンソールのエスケープに置き換えて送り込む。
                   1344:        switch (charcode) {
                   1345:         case CC_NUL:
                   1346:                comdriver->EnqueueChar(0);
                   1347:                break;
                   1348: 
                   1349:         case CC_F1 ... CC_F10:
                   1350:                break;
                   1351: 
                   1352:         case CC_up:
                   1353:                comdriver->EnqueueChar(ESC);
                   1354:                comdriver->EnqueueChar('[');
                   1355:                comdriver->EnqueueChar('A');
                   1356:                break;
                   1357: 
                   1358:         case CC_down:
                   1359:                comdriver->EnqueueChar(ESC);
                   1360:                comdriver->EnqueueChar('[');
                   1361:                comdriver->EnqueueChar('B');
                   1362:                break;
                   1363: 
                   1364:         case CC_right:
                   1365:                comdriver->EnqueueChar(ESC);
                   1366:                comdriver->EnqueueChar('[');
                   1367:                comdriver->EnqueueChar('C');
                   1368:                break;
                   1369: 
                   1370:         case CC_left:
                   1371:                comdriver->EnqueueChar(ESC);
                   1372:                comdriver->EnqueueChar('[');
                   1373:                comdriver->EnqueueChar('D');
                   1374:                break;
                   1375: 
                   1376:         default:
                   1377:                comdriver->EnqueueChar(charcode);
                   1378:                break;
                   1379:        }
                   1380: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.