Annotation of nono/vm/console.cpp, revision 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.