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

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:        if (inherited::Init() == false) {
                     61:                return false;
                     62:        }
                     63: 
                     64:        renderer = GetRenderer();
                     65: 
                     66:        // ログファイル。
                     67:        if (gMainApp.console_logfile) {
                     68:                log = fopen(gMainApp.console_logfile, "w");
                     69:                if (log == NULL) {
                     70:                        warn("console logfile '%s'", gMainApp.console_logfile);
                     71:                        return false;
                     72:                }
                     73:        }
                     74: 
                     75:        vsync_event.func = ToEventCallback(&ConsoleDevice::VSyncCallback);
                     76:        vsync_event.time = 16666.667_usec;
                     77:        vsync_event.SetName("Console V-Sync");
                     78:        scheduler->RegistEvent(vsync_event);
                     79: 
                     80:        return true;
                     81: }
                     82: 
                     83: // COM ドライバを接続。
                     84: // NULL を指定すると解除。
                     85: // (HostCOM の cons ドライバが呼ぶ)
                     86: void
                     87: ConsoleDevice::Attach(COMDriver *comdriver_)
                     88: {
                     89:        comdriver = comdriver_;
                     90: }
                     91: 
                     92: void
                     93: ConsoleDevice::ResetHard(bool poweron)
                     94: {
                     95:        if (poweron) {
                     96:                // 最初に一回フチを含めて描画する。
                     97:                init_screen = true;
                     98: 
                     99:                // シリアルコンソールなのでリセットには反応しない。
                    100:                Clear();
                    101:                Locate(0, 0);
                    102:        }
                    103: 
                    104:        if (comdriver) {
                    105:                scheduler->RestartEvent(vsync_event);
                    106:        }
                    107: 
                    108:        ResetTerminal();
                    109: }
                    110: 
                    111: void
                    112: ConsoleDevice::VSyncCallback(Event& ev)
                    113: {
                    114:        bool update_needed;
                    115: 
                    116:        // 更新 (dirty[]) があれば pending[] に重ねる。
                    117:        {
                    118:                std::unique_lock<std::mutex> lock(mtx);
                    119:                for (int y = 0; y < height; y++) {
                    120:                        // std::vector<bool> には operator|=() がない。
                    121:                        if (__predict_false(dirty[y])) {
                    122:                                pending[y] = true;
                    123:                                dirty[y] = false;
                    124:                        }
                    125:                }
                    126: 
                    127:                update_needed = AnyOf(pending);
                    128:        }
                    129: 
                    130:        // 更新の必要があれば Render に作画指示。
                    131:        if (update_needed) {
                    132:                renderer->NotifyRender();
                    133:        }
                    134: 
                    135:        scheduler->StartEvent(ev);
                    136: }
                    137: 
                    138: // 端末の状態をリセットする。
                    139: // (画面のクリアはここではしない?)
                    140: void
                    141: ConsoleDevice::ResetTerminal()
                    142: {
                    143:        ResetState();
                    144:        SetAttr(0);
                    145:        scroll_top = 0;
                    146:        scroll_btm = height - 1;
                    147:        save_curx = 0;
                    148:        save_cury = 0;
                    149: }
                    150: 
                    151: // エスケープシーケンスの状態を初期化する。
                    152: void
                    153: ConsoleDevice::ResetState()
                    154: {
                    155:        state = 0;
                    156:        seq.clear();
                    157:        arg.clear();
                    158: }
                    159: 
                    160: // ch をログ出力する。
                    161: void
                    162: ConsoleDevice::PutcharDebug(uint32 ch)
                    163: {
                    164:        if (ch == '\n') {
                    165:                // 改行が来たらログも改行する。
                    166:                fputs("\\n\n", log);
                    167:                log_newline = true;
                    168:        } else {
                    169:                if (ch == ESC) {
                    170:                        // 読みやすさのため ESC の前で改行したい。
                    171:                        if (log_newline == false) {
                    172:                                fputc('\n', log);
                    173:                        }
                    174:                        fputs("ESC", log);
                    175:                } else if (ch == '\r') {
                    176:                        fputs("\\r", log);
                    177:                } else if (ch == '\t') {
                    178:                        fputs("\\t", log);
                    179:                } else if (ch < 0x20 || ch >= 0x7f) {
                    180:                        fprintf(log, "\\x%02x", ch);
                    181:                } else {
                    182:                        fputc(ch, log);
                    183:                }
                    184:                log_newline = false;
                    185:        }
                    186:        fflush(log);
                    187: }
                    188: 
                    189: // シリアルコンソールから来る出力。
                    190: // ホストドライバスレッドから呼ばれる。
                    191: void
                    192: ConsoleDevice::Putchar(uint32 ch)
                    193: {
                    194:        if (__predict_false(log)) {
                    195:                PutcharDebug(ch);
                    196:        }
                    197: 
                    198:        switch (state) {
                    199:         case ESC:
                    200:                if (PutcharESC(ch)) {
                    201:                        return;
                    202:                }
                    203:                break;
                    204: 
                    205:         case CSI:
                    206:                if (PutcharCSI(ch)) {
                    207:                        return;
                    208:                }
                    209:                break;
                    210: 
                    211:         case '(':      // G0
                    212:                switch (ch) {
                    213:                 case '0':              // DEC 特殊記号
                    214:                        SetAttr(cur_attr | ATTR_DECSG);
                    215:                        break;
                    216:                 case 'B':              // ASCII
                    217:                 default:
                    218:                        SetAttr(cur_attr & ~ATTR_DECSG);
                    219:                        break;
                    220:                }
                    221:                ResetState();
                    222:                return;
                    223: 
                    224:         case ')':      // G1
                    225:         case '$':      // 94 multibyte
                    226:         case '#':
                    227:                // とりあえず何もしない。
                    228:                ResetState();
                    229:                return;
                    230: 
                    231:         case '?':      // CSI '?'
                    232:                if (PutcharCSIQ(ch)) {
                    233:                        return;
                    234:                }
                    235:                break;
                    236: 
                    237:         default:
                    238:                PutcharPlain(ch);
                    239:                return;
                    240:        }
                    241: 
                    242:        // シーケンスを破棄。ここまでのを表示して平文に戻る。
                    243:        putlog(0, "Unknown Sequence:%s", Dump(ch).c_str());
                    244:        for (auto c : seq) {
                    245:                Putc(c);
                    246:        }
                    247:        Putc(ch);
                    248:        ResetState();
                    249: }
                    250: 
                    251: // 何のシーケンスでもない1文字を表示する。
                    252: void
                    253: ConsoleDevice::PutcharPlain(uint32 ch)
                    254: {
                    255:        switch (ch) {
                    256:         case '\x00':   // NUL
                    257:         case '\x01':   // SOH
                    258:         case '\x02':   // STX
                    259:         case '\x03':   // ETX
                    260:         case '\x04':   // EOT
                    261:         case '\x05':   // ENQ
                    262:         case '\x06':   // ACK
                    263:                break;
                    264:         case '\x07':   // BEL
                    265:                // とりあえず無視。
                    266:                break;
                    267: 
                    268:         case '\x08':   // BS
                    269:                LocateX(cur_x - 1);
                    270:                return;
                    271: 
                    272:         case '\t':             // TAB
                    273:                // XXX 右端どうなる?
                    274:                LocateX(roundup(cur_x, 8));
                    275:                return;
                    276: 
                    277:         case '\n':             // LF
                    278:         case '\x0b':   // VT
                    279:         case '\x0c':   // FF
                    280:                LF();
                    281:                return;
                    282: 
                    283:         case '\r':     // CR
                    284:                CR();
                    285:                return;
                    286: 
                    287:         case '\x0e':   // SO
                    288:         case '\x0f':   // SI
                    289:                // Change GL
                    290:                break;
                    291: 
                    292:         case '\x10':   // DLE
                    293:         case '\x11':   // DC1/XON
                    294:         case '\x12':   // DC2
                    295:         case '\x13':   // DC3/XOFF
                    296:         case '\x14':   // DC4
                    297:         case '\x15':   // NAK
                    298:         case '\x16':   // SYN
                    299:         case '\x17':   // ETB
                    300:                break;
                    301: 
                    302:         case '\x18':   // CAN
                    303:                // Cancel
                    304:                ResetState();
                    305:                return;
                    306: 
                    307:         case '\x19':   // EM
                    308:                break;
                    309: 
                    310:         case '\x1a':   // SUB
                    311:                ResetState();
                    312:                return;
                    313: 
                    314:         case ESC:
                    315:                seq.push_back(ch);
                    316:                state = ch;
                    317:                return;
                    318: 
                    319:         case '\x1c':   // FS
                    320:         case '\x1d':   // GS
                    321:         case '\x1e':   // RS
                    322:         case '\x1f':   // US
                    323:                break;
                    324: 
                    325:         default:
                    326:                if (ch < 0x80) {
                    327:                        // ここが通常の1文字出力。
                    328:                        Putc(ch);
                    329:                        return;
                    330:                }
                    331:                // 8ビットシーケンスは無視?
                    332:                break;
                    333:        }
                    334:        putlog(2, "Ignore: \\x%02x", ch);
                    335: }
                    336: 
                    337: // ESC の次の文字を処理する。
                    338: // 処理すれば true、知らないシーケンスなので中止する場合は false を返す。
                    339: bool
                    340: ConsoleDevice::PutcharESC(uint32 ch)
                    341: {
                    342:        switch (ch) {
                    343:         case '[':              // CSI
                    344:         case '(':              // G0
                    345:         case ')':              // G1
                    346:         case '$':              // 94 multibyte
                    347:         case '#':              // Font width/height control
                    348:                seq.push_back(ch);
                    349:                state = ch;
                    350:                return true;
                    351: 
                    352:         case '\\':             // ST
                    353:                break;
                    354: 
                    355:         case '7':              // カーソル位置保存
                    356:                save_curx = cur_x;
                    357:                save_cury = cur_y;
                    358:                break;
                    359: 
                    360:         case '8':              // カーソル位置復帰
                    361:                Locate(save_curx, save_cury);
                    362:                break;
                    363: 
                    364:         case 'c':              // Hard terminal reset
                    365:                Clear();
                    366:                ResetTerminal();
                    367:                Locate(0, 0);
                    368:                break;
                    369: 
                    370:         case 'M':              // 1行上に移動 (画面を1行下にスクロール)
                    371:                ScrollDown();
                    372:                Locate(0, 0);
                    373:                break;
                    374: 
                    375:         case '*':              // G2
                    376:         case '+':              // G3
                    377:         case 'B':              // ASCII
                    378:         case 'A':              // ISO Latin 1
                    379:         case '<':              //
                    380:         case '0':              // DEC special graphics
                    381:         case '-':              // G1 (96)
                    382:         case '.':              // G2
                    383:         case '/':              // G3
                    384:         case '4':              // Dutch
                    385:         case '5':
                    386:         case '6':              // Norwegian/Danish
                    387:         case 'C':              // Finnish
                    388:         case 'R':              // French
                    389:         case 'Q':              // French canadian
                    390:         case 'K':              // German
                    391:         case 'Y':              // Italian
                    392:         // "%5" とかの2文字のやつは NetBSD/x68k ite も未対応。
                    393:         case '`':
                    394:         case 'n':
                    395:         case '}':
                    396:         case 'o':
                    397:         case '|':
                    398:         case '~':
                    399:         case '=':
                    400:         case '>':
                    401:                putlog(2, "Ignore:%s", Dump(ch).c_str());
                    402:                break;
                    403: 
                    404:         case 'Z':              // 端末属性を応答する。
                    405:         default:
                    406:                return false;
                    407:        }
                    408: 
                    409:        ResetState();
                    410:        return true;
                    411: }
                    412: 
                    413: // CSI の次の文字を処理する。
                    414: // 処理すれば true、知らないシーケンスなので中止する場合は false を返す。
                    415: bool
                    416: ConsoleDevice::PutcharCSI(uint32 ch)
                    417: {
                    418:        switch (ch) {
                    419:         case '0':
                    420:         case '1':
                    421:         case '2':
                    422:         case '3':
                    423:         case '4':
                    424:         case '5':
                    425:         case '6':
                    426:         case '7':
                    427:         case '8':
                    428:         case '9':
                    429:         case ';':
                    430:         case '\"':
                    431:         case '$':
                    432:         case '>':
                    433:                seq.push_back(ch);
                    434:                arg.push_back(ch);
                    435:                return true;
                    436: 
                    437:         case 'A':
                    438:         {
                    439:                int n = atoi(arg.c_str());
                    440:                if (n == 0) {
                    441:                        n = 1;
                    442:                }
                    443:                LocateY(cur_y - n);
                    444:                ResetState();
                    445:                return true;
                    446:         }
                    447: 
                    448:         case 'B':
                    449:         {
                    450:                int n = atoi(arg.c_str());
                    451:                if (n == 0) {
                    452:                        n = 1;
                    453:                }
                    454:                LocateY(cur_y + n);
                    455:                ResetState();
                    456:                return true;
                    457:         }
                    458: 
                    459:         case 'C':
                    460:         {
                    461:                int n = atoi(arg.c_str());
                    462:                if (n == 0) {
                    463:                        n = 1;
                    464:                }
                    465:                LocateX(cur_x + n);
                    466:                ResetState();
                    467:                return true;
                    468:         }
                    469: 
                    470:         case 'D':
                    471:         {
                    472:                int n = atoi(arg.c_str());
                    473:                if (n == 0) {
                    474:                        n = 1;
                    475:                }
                    476:                LocateX(cur_x - n);
                    477:                ResetState();
                    478:                return true;
                    479:         }
                    480: 
                    481:         case 'H':
                    482:         {
                    483:                // CSI <y> ; <x> H … (x-1, y-1) にカーソルを移動。
                    484:                int y = atoi(arg.c_str());
                    485:                int x = 0;
                    486:                const char *p = strchr(arg.c_str(), ';');
                    487:                if (p) {
                    488:                        x = atoi(p + 1);
                    489:                }
                    490:                if (x > 0) {
                    491:                        x--;
                    492:                }
                    493:                if (y > 0) {
                    494:                        y--;
                    495:                }
                    496:                Locate(x, y);
                    497:                ResetState();
                    498:                return true;
                    499:         }
                    500: 
                    501:         case 'J':
                    502:         {
                    503:                // CSI [<n>] J
                    504:                // <n> が 0 か省略なら、カーソル位置から右下までを消去。
                    505:                // <n> が 1 なら、カーソル位置から左上までを消去。
                    506:                // <n> が 2 なら、全画面消去。
                    507:                // XXX SPA と ERM は未対応。
                    508:                int n = atoi(arg.c_str());
                    509:                switch (n) {
                    510:                 default:       // 知らんけど
                    511:                 case 0:
                    512:                        for (int y = cur_y; y < height - 1; y++) {
                    513:                                int x = (y == cur_y) ? cur_x : 0;
                    514:                                for (; x < width; x++) {
                    515:                                        Setc(x, y, ' ' | cur_attr);
                    516:                                }
                    517:                        }
                    518:                        break;
                    519:                 case 1:
                    520:                        for (int y = 0; y <= cur_y; y++) {
                    521:                                int xend = (y == cur_y) ? cur_x : (width - 1);
                    522:                                for (int x = 0; x <= xend; x++) {
                    523:                                        Setc(x, y, ' ' | cur_attr);
                    524:                                }
                    525:                        }
                    526:                        break;
                    527:                 case 2:
                    528:                        // カーソル位置は移動しないまま?
                    529:                        Clear();
                    530:                        break;
                    531:                }
                    532:                ResetState();
                    533:                return true;
                    534:         }
                    535: 
                    536:         case 'K':
                    537:         {
                    538:                // CSI [<n>] K
                    539:                // <n> が 0 か省略なら、カーソル位置の右側を消去。
                    540:                // <n> が 1 なら、カーソル位置の左側を消去。
                    541:                // <n> が 2 なら、カーソル行を消去。
                    542:                int n = atoi(arg.c_str());
                    543:                int x0;
                    544:                int x1;
                    545:                switch (n) {
                    546:                 default:       // 知らんけど
                    547:                 case 0:
                    548:                        x0 = cur_x;
                    549:                        x1 = width - 1;
                    550:                        break;
                    551:                 case 1:
                    552:                        x0 = 0;
                    553:                        x1 = cur_x;
                    554:                        break;
                    555:                 case 2:
                    556:                        x0 = 0;
                    557:                        x1 = width - 1;
                    558:                        break;
                    559:                }
                    560:                for (int x = x0; x <= x1; x++) {
                    561:                        Setc(x, cur_y, ' ' | cur_attr);
                    562:                }
                    563:                ResetState();
                    564:                return true;
                    565:         }
                    566: 
                    567:         case 'm':
                    568:         {
                    569:                // CSI 7 ; 37 m みたいにセミコロンで区切ってパラメータを複数書ける。
                    570:                // パラメータには 38:2:rr:gg:bb みたいにコロンで区切ったひとかたまり
                    571:                // もある。
                    572:                const char *ap = arg.c_str();
                    573:                for (;;) {
                    574:                        int n = atoi(ap);
                    575:                        switch (n) {
                    576:                         case 0:                        // すべての属性を解除
                    577:                                SetAttr(0);
                    578:                                break;
                    579:                         case 1:                        // ボールドをセット
                    580:                                SetAttr(cur_attr | ATTR_BOLD);
                    581:                                break;
                    582:                         case 2:                        // 低輝度をセット (対応予定なし)
                    583:                                break;
                    584:                         case 3:                        // イタリックをセット
                    585:                                SetAttr(cur_attr | ATTR_ITALIC);
                    586:                                break;
                    587:                         case 4:                        // 下線をセット
                    588:                                SetAttr(cur_attr | ATTR_UNDERLINE);
                    589:                                break;
                    590:                         case 5:                        // 低速点滅をセット (対応予定なし)
                    591:                                break;
                    592:                         case 6:                        // 高速点滅をセット (対応予定なし)
                    593:                                break;
                    594:                         case 7:                        // 反転をセット
                    595:                                SetAttr(cur_attr | ATTR_REVERSE);
                    596:                                break;
                    597:                         case 8:                        // 文字色を背景色と同じにする
                    598:                                break;
                    599:                         case 9:                        // 打ち消し線をセット
                    600:                                SetAttr(cur_attr | ATTR_STRIKE);
                    601:                                break;
                    602:                         case 10 ... 20:        // フォントセットの設定?
                    603:                                break;
                    604:                         case 21:                       // 二重下線をセット (対応予定なし)
                    605:                                break;
                    606:                         case 22:                       // ボールド(と低輝度)を解除
                    607:                                SetAttr(cur_attr & ~ATTR_BOLD);
                    608:                                break;
                    609:                         case 23:                       // イタリックを解除
                    610:                                SetAttr(cur_attr & ~ATTR_ITALIC);
                    611:                                break;
                    612:                         case 24:                       // 下線を解除
                    613:                                SetAttr(cur_attr & ~ATTR_UNDERLINE);
                    614:                                break;
                    615:                         case 25:                       // 点滅を解除
                    616:                                break;
                    617:                         case 26:                       // ?
                    618:                                break;
                    619:                         case 27:                       // 反転を解除
                    620:                                SetAttr(cur_attr & ~ATTR_REVERSE);
                    621:                                break;
                    622:                         case 28:                       // シークレットを解除
                    623:                                break;
                    624:                         case 29:                       // 打ち消し線を解除
                    625:                                SetAttr(cur_attr & ~ATTR_STRIKE);
                    626:                                break;
                    627:                         case 30 ... 37:        // 文字色の設定
                    628:                                break;
                    629:                         case 38:                       // 文字色(拡張)を設定
                    630:                                break;
                    631:                         case 39:                       // 文字色をデフォルトに戻す
                    632:                                break;
                    633:                         case 40 ... 47:        // 背景色を設定
                    634:                                break;
                    635:                         case 48:                       // 背景色(拡張)を設定
                    636:                                break;
                    637:                         case 49:                       // 背景色をデフォルトに戻す
                    638:                                break;
                    639:                         case 51:                       // □を重ねる (対応予定なし)
                    640:                                break;
                    641:                         case 52:                       // ○を重ねる (対応予定なし)
                    642:                                break;
                    643:                         case 53:                       // 上線をセット
                    644:                                SetAttr(cur_attr | ATTR_OVERLINE);
                    645:                                break;
                    646:                         case 54:                       // □○を取り消し
                    647:                                break;
                    648:                         case 55:                       // 上線を取り消し
                    649:                                SetAttr(cur_attr & ~ATTR_OVERLINE);
                    650:                                break;
                    651:                         case 60 ... 63:        // 縦線 (対応予定なし)
                    652:                                break;
                    653:                         case 64:                       // 二重打ち消し線 (対応予定なし)
                    654:                                break;
                    655:                         case 65:                       // 60-64 を取り消し
                    656:                                break;
                    657:                         case 90 ... 97:        // 文字色(高輝度)を設定
                    658:                                break;
                    659:                         case 100 ... 107:      // 背景色(高輝度)を設定
                    660:                                break;
                    661:                         default:
                    662:                                // 無視
                    663:                                break;
                    664:                        }
                    665: 
                    666:                        if (*ap == '\0') {
                    667:                                break;
                    668:                        }
                    669:                        ap = strchr(ap + 1, ';');
                    670:                        if (ap == NULL) {
                    671:                                break;
                    672:                        }
                    673:                        ap++;
                    674:                }
                    675: 
                    676:                ResetState();
                    677:                return true;
                    678:         }
                    679: 
                    680:         case 'r':
                    681:         {
                    682:                // CSI <t> ; <b> r。<t> 省略時は 1。<b> 省略時は画面最下行。
                    683:                int top = atoi(arg.c_str());
                    684:                int btm = height;
                    685:                const char *p = strchr(arg.c_str(), ';');
                    686:                if (p) {
                    687:                        btm = atoi(p + 1);
                    688:                }
                    689:                if (top > 0) {
                    690:                        top--;
                    691:                }
                    692:                if (btm > 0) {
                    693:                        btm--;
                    694:                }
                    695:                scroll_top = top;
                    696:                scroll_btm = btm;
                    697:                ResetState();
                    698:                return true;
                    699:         }
                    700: 
                    701:         case '?':
                    702:                seq.push_back(ch);
                    703:                state = ch;
                    704:                return true;
                    705: 
                    706:         default:
                    707:                return false;
                    708:        }
                    709: }
                    710: 
                    711: // CSI '?' の次の文字を処理する。
                    712: // 処理すれば true、知らないシーケンスなので中止する場合は false を返す。
                    713: bool
                    714: ConsoleDevice::PutcharCSIQ(uint32 ch)
                    715: {
                    716:        switch (ch) {
                    717:         case '0':
                    718:         case '1':
                    719:         case '2':
                    720:         case '3':
                    721:         case '4':
                    722:         case '5':
                    723:         case '6':
                    724:         case '7':
                    725:         case '8':
                    726:         case '9':
                    727:         case ';':
                    728:         case '\"':
                    729:         case '$':
                    730:         case '>':
                    731:                seq.push_back(ch);
                    732:                arg.push_back(ch);
                    733:                return true;
                    734: 
                    735:         case 'h':      // 拡張オプションを設定
                    736:         case 'l':      // 拡張オプションを解除
                    737:                // CSI '?' <n> h
                    738:                // CSI '?' <n> l
                    739:                // 全部未対応。
                    740:                putlog(2, "Ignored:%s", Dump(ch).c_str());
                    741:                ResetState();
                    742:                return true;
                    743: 
                    744:         default:
                    745:                return false;
                    746:        }
                    747: }
                    748: 
                    749: // 現在の seq を表示用文字列にして返す。
                    750: std::string
                    751: ConsoleDevice::Dump() const
                    752: {
                    753:        return Dump(seq);
                    754: }
                    755: 
                    756: // 現在の seq と ch を表示用文字列にして返す。
                    757: // 大抵の場合最後の1文字はまだ seq に入っていないのでこの形式があると便利。
                    758: std::string
                    759: ConsoleDevice::Dump(uint32 ch) const
                    760: {
                    761:        std::vector<uint8> tmp = seq;
                    762:        tmp.push_back(ch);
                    763:        return Dump(tmp);
                    764: }
                    765: 
                    766: // エスケープシーケンスを表示用文字列にして返す。
                    767: // 戻り文字列には先頭に空白が入っている。
                    768: /*static*/ std::string
                    769: ConsoleDevice::Dump(const std::vector<uint8>& src)
                    770: {
                    771:        std::string dst;
                    772: 
                    773:        for (auto ch : src) {
                    774:                if (ch == ESC) {
                    775:                        dst += " ESC";
                    776:                } else if (ch < ' ' || ch >= 0x7f) {
                    777:                        dst += string_format(" \\x%02x", ch);
                    778:                } else if (ch == ' ') {
                    779:                        dst += " ' '";
                    780:                } else {
                    781:                        dst += ' ';
                    782:                        dst += (char)ch;
                    783:                }
                    784:        }
                    785:        return dst;
                    786: }
                    787: 
                    788: // 画面を消去する。
                    789: // カーソル位置は変わらない。属性もクリアされない。
                    790: void
                    791: ConsoleDevice::Clear()
                    792: {
                    793:        std::fill(screen.begin(), screen.end(), ' ' | cur_attr);
                    794:        std::fill(dirty.begin(), dirty.end(), true);
                    795: }
                    796: 
                    797: // カーソルの X 座標を移動。(画面をはみ出さないようにクリップされる)
                    798: void
                    799: ConsoleDevice::LocateX(int x)
                    800: {
                    801:        if (__predict_false(x < 0)) {
                    802:                x = 0;
                    803:        }
                    804:        if (__predict_false(x > width - 1)) {
                    805:                x = width - 1;
                    806:        }
                    807:        cur_x = x;
                    808:        dirty[cur_y] = true;
                    809: }
                    810: 
                    811: // カーソルの Y 座標を移動。(画面をはみ出さないようにクリップされる)
                    812: void
                    813: ConsoleDevice::LocateY(int y)
                    814: {
                    815:        if (__predict_false(y < 0)) {
                    816:                y = 0;
                    817:        }
                    818:        if (__predict_false(y > height - 1)) {
                    819:                y = height - 1;
                    820:        }
                    821:        dirty[cur_y] = true;
                    822:        cur_y = y;
                    823:        dirty[cur_y] = true;
                    824: }
                    825: 
                    826: // 文字出力後のカーソル移動。
                    827: void
                    828: ConsoleDevice::Ascend()
                    829: {
                    830:        cur_x++;
                    831:        dirty[cur_y] = true;
                    832:        if (cur_x >= width) {
                    833:                CRLF();
                    834:        }
                    835: }
                    836: 
                    837: // 復帰。
                    838: void
                    839: ConsoleDevice::CR()
                    840: {
                    841:        LocateX(0);
                    842: }
                    843: 
                    844: // 改行。(DECSTBM の影響を受ける)
                    845: void
                    846: ConsoleDevice::LF()
                    847: {
                    848:        dirty[cur_y] = true;
                    849:        cur_y++;
                    850:        if (cur_y >= scroll_btm) {
                    851:                ScrollUp();
                    852:                cur_y = scroll_btm;
                    853:        }
                    854:        dirty[cur_y] = true;
                    855: }
                    856: 
                    857: // 全画面を1行上にスクロール。(DECSTBM の影響を受ける)
                    858: // カーソル位置は移動しない。
                    859: void
                    860: ConsoleDevice::ScrollUp()
                    861: {
                    862:        int dst = scroll_top * width;
                    863:        int lines = scroll_btm - scroll_top;
                    864:        memmove(&screen[dst], &screen[dst + width],
                    865:                lines * width * sizeof(screen[0]));
                    866:        uint32 ch = ' ' | cur_attr;
                    867:        for (int x = 0; x < width; x++) {
                    868:                Setc(x, scroll_btm, ch);
                    869:        }
                    870:        std::fill(dirty.begin(), dirty.end(), true);
                    871: }
                    872: 
                    873: // 全画面を1行下にスクロール。(DECSTBM の影響を受ける)
                    874: // カーソル位置は移動しない。
                    875: void
                    876: ConsoleDevice::ScrollDown()
                    877: {
                    878:        int src = scroll_top * width;
                    879:        int lines = scroll_btm - scroll_top;
                    880:        memmove(&screen[src + width], &screen[src],
                    881:                lines * width * sizeof(screen[0]));
                    882:        uint32 ch = ' ' | cur_attr;
                    883:        for (int x = 0; x < width; x++) {
                    884:                Setc(x, scroll_top, ch);
                    885:        }
                    886:        std::fill(dirty.begin(), dirty.end(), true);
                    887: }
                    888: 
                    889: // 現在位置に、現在の属性で文字 ch を出力する。
                    890: // 出力後カーソルは移動する。
                    891: void
                    892: ConsoleDevice::Putc(uint32 ch)
                    893: {
                    894:        if (ch == '\n') {
                    895:                CR();
                    896:                LF();
                    897:                return;
                    898:        }
                    899: 
                    900:        Setc(cur_x, cur_y, ch | cur_attr);
                    901:        Ascend();
                    902: }
                    903: 
                    904: // (x, y) の位置に chattr を出力する。
                    905: // 出力後カーソルは移動しない。
                    906: // 現在の attr は参照しない (呼び出す側が指定すること)。
                    907: void
                    908: ConsoleDevice::Setc(int x, int y, uint32 chattr)
                    909: {
                    910:        int pos = y * width + x;
                    911:        assert(pos >= 0);
                    912:        assert(pos < width * height);
                    913:        screen[pos] = chattr;
                    914: }
                    915: 
                    916: // 現在の属性を設定する。
                    917: // ほぼログ出力のため。
                    918: void
                    919: ConsoleDevice::SetAttr(uint32 new_attr)
                    920: {
                    921:        if (cur_attr == new_attr) {
                    922:                return;
                    923:        }
                    924:        cur_attr = new_attr;
                    925: 
                    926:        if (log) {
                    927:                std::string buf;
                    928:                if ((cur_attr & ATTR_BOLD)) {
                    929:                        buf += ",ATTR_BOLD";
                    930:                }
                    931:                if ((cur_attr & ATTR_ITALIC)) {
                    932:                        buf += ",ATTR_ITALIC";
                    933:                }
                    934:                if ((cur_attr & ATTR_UNDERLINE)) {
                    935:                        buf += ",ATTR_UNDERLINE";
                    936:                }
                    937:                if ((cur_attr & ATTR_STRIKE)) {
                    938:                        buf += ",ATTR_STRIKE";
                    939:                }
                    940:                if ((cur_attr & ATTR_OVERLINE)) {
                    941:                        buf += ",ATTR_OVERLINE";
                    942:                }
                    943:                if ((cur_attr & ATTR_DECSG)) {
                    944:                        buf += ",ATTR_DECSG";
                    945:                }
                    946:                if ((cur_attr & ATTR_REVERSE)) {
                    947:                        buf += ",ATTR_REVERSE";
                    948:                }
                    949: 
                    950:                if (buf.empty()) {
                    951:                        buf = "<ATTR_NORMAL>";
                    952:                } else {
                    953:                        buf[0] = '<';
                    954:                        buf += '>';
                    955:                }
                    956:                fputs(buf.c_str(), log);
                    957:                fflush(log);
                    958:        }
                    959: }
                    960: 
                    961: // 画面合成。
                    962: // レンダリングスレッドから呼ばれる。
                    963: bool
                    964: ConsoleDevice::Render(BitmapRGBX& dst)
                    965: {
                    966:        if (comdriver == NULL) {
                    967:                return false;
                    968:        }
                    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:        // 行ごとに更新があるか調べる。
                    980:        std::vector<bool> modified(height);
                    981:        {
                    982:                std::unique_lock<std::mutex> lock(mtx);
                    983:                modified = pending;
                    984:                std::fill(pending.begin(), pending.end(), false);
                    985:        }
                    986:        updated |= AnyOf(modified);
                    987: 
                    988:        const uint8 *cgrom8x16 = Builtin::CGROM8x16(0);
                    989:        for (uint y = 0; y < height; y++) {
                    990:                if (__predict_false(modified[y])) {
                    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: // [0] からだと通常色、[1] からだと反転色になる。
                   1307: /*static*/ const Color ConsoleDevice::palette[3] = {
                   1308:        UD_LIGHT_GREY,  // BG
                   1309:        UD_BLACK,               // FG
                   1310:        UD_LIGHT_GREY,  // BG
                   1311: };
                   1312: 
                   1313: 
                   1314: //
                   1315: // 入力担当デバイス
                   1316: //
                   1317: 
                   1318: // コンストラクタ
                   1319: ConsoleKeyboard::ConsoleKeyboard()
                   1320:        : inherited()
                   1321: {
                   1322: }
                   1323: 
                   1324: // デストラクタ
                   1325: ConsoleKeyboard::~ConsoleKeyboard()
                   1326: {
                   1327: }
                   1328: 
                   1329: // COM ドライバを接続。
                   1330: // (HostCOM の cons ドライバが呼ぶ)
                   1331: void
                   1332: ConsoleKeyboard::Attach(COMDriverCons *comdriver_)
                   1333: {
                   1334:        comdriver = comdriver_;
                   1335: }
                   1336: 
                   1337: // 文字入力。
                   1338: // WXMainView から呼ばれる。
                   1339: void
                   1340: ConsoleKeyboard::CharInput(uint charcode)
                   1341: {
                   1342:        if (comdriver == NULL) {
                   1343:                return;
                   1344:        }
                   1345: 
                   1346:        // charcode は 0x80 以上を独自に使っているので (keyboard.h 参照)、
                   1347:        // それらをシリアルコンソールのエスケープに置き換えて送り込む。
                   1348:        switch (charcode) {
                   1349:         case CC_NUL:
                   1350:                comdriver->EnqueueChar(0);
                   1351:                break;
                   1352: 
                   1353:         case CC_F1 ... CC_F10:
                   1354:                break;
                   1355: 
                   1356:         case CC_up:
                   1357:                comdriver->EnqueueChar(ESC);
                   1358:                comdriver->EnqueueChar('[');
                   1359:                comdriver->EnqueueChar('A');
                   1360:                break;
                   1361: 
                   1362:         case CC_down:
                   1363:                comdriver->EnqueueChar(ESC);
                   1364:                comdriver->EnqueueChar('[');
                   1365:                comdriver->EnqueueChar('B');
                   1366:                break;
                   1367: 
                   1368:         case CC_right:
                   1369:                comdriver->EnqueueChar(ESC);
                   1370:                comdriver->EnqueueChar('[');
                   1371:                comdriver->EnqueueChar('C');
                   1372:                break;
                   1373: 
                   1374:         case CC_left:
                   1375:                comdriver->EnqueueChar(ESC);
                   1376:                comdriver->EnqueueChar('[');
                   1377:                comdriver->EnqueueChar('D');
                   1378:                break;
                   1379: 
                   1380:         default:
                   1381:                comdriver->EnqueueChar(charcode);
                   1382:                break;
                   1383:        }
                   1384: }

unix.superglobalmegacorp.com

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