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

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

unix.superglobalmegacorp.com

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