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

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

unix.superglobalmegacorp.com

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