Annotation of nono/wx/wxsoftkey.cpp, revision 1.1.1.13

1.1       root        1: //
                      2: // nono
1.1.1.4   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.11  root        7: //
                      8: // ソフトウェアキーボード
                      9: //
                     10: 
1.1       root       11: #include "wxsoftkey.h"
1.1.1.11  root       12: #include "fontmanager.h"
1.1.1.4   root       13: #include "wxcolor.h"
1.1.1.13! root       14: #include "wxmainframe.h"
1.1.1.6   root       15: #include "wxmainview.h"
1.1.1.8   root       16: #include "wxuimessage.h"
1.1.1.4   root       17: #include "sram.h"
1.1       root       18: 
                     19: //
1.1.1.4   root       20: // ソフトウェアキーボード (パネル) 共通部分
1.1       root       21: //
                     22: 
1.1.1.4   root       23: // エンター記号。
                     24: // 描画の際にキー刻印文字列の半角文字数から描画幅を決定しており、
                     25: // エンター記号は半角2文字幅で描いているので実際の文字列も2文字にしておく。
                     26: // そうすると "\\n" が意味的にもちょうどいい。
                     27: // これは幅を算出するのに使うだけで表示はされない。
                     28: #define EnterMark      "\\n"
                     29: 
1.1       root       30: // イベントテーブル
1.1.1.4   root       31: wxBEGIN_EVENT_TABLE(WXSoftKeyPanel, inherited)
                     32:        EVT_LEFT_DOWN(WXSoftKeyPanel::OnLeftDown)
                     33:        EVT_LEFT_UP(WXSoftKeyPanel::OnLeftUp)
                     34:        EVT_LEFT_DCLICK(WXSoftKeyPanel::OnLeftDClick)
                     35:        EVT_RIGHT_DOWN(WXSoftKeyPanel::OnRightDown)
1.1.1.9   root       36:        EVT_TIMER(wxID_ANY, WXSoftKeyPanel::OnTimer)
1.1       root       37: wxEND_EVENT_TABLE()
                     38: 
                     39: // コンストラクタ
1.1.1.4   root       40: WXSoftKeyPanel::WXSoftKeyPanel(wxWindow *parent,
1.1.1.6   root       41:        const std::vector<keydata_t>& keydata_, int u_width_, int u_height_)
1.1       root       42:        : inherited(parent)
1.1.1.6   root       43:        , keydata(keydata_)
1.1       root       44: {
1.1.1.13! root       45:        // デバイスを取得
        !            46:        keyboard = GetKeyboard();
        !            47: 
1.1.1.9   root       48:        timer.SetOwner(this);
                     49: 
1.1.1.4   root       50:        u_width  = u_width_;
                     51:        u_height = u_height_;
1.1.1.6   root       52: 
1.1.1.11  root       53:        FontChanged();
1.1.1.7   root       54: 
1.1.1.10  root       55:        // トグル動作にするキー
                     56:        toggle.emplace(KC_SHIFT, 0);
                     57:        toggle.emplace(KC_SHIFT_L, 0);
                     58:        toggle.emplace(KC_SHIFT_R, 0);
                     59:        toggle.emplace(KC_CTRL, 0);
                     60: 
1.1.1.9   root       61:        // 残光の初期化。
                     62:        // persistence は keydata 分の配列ではなく共通キーコード分の配列。
                     63:        persistence.resize(KC_max);
                     64:        std::fill(persistence.begin(), persistence.end(), 0);
                     65: 
1.1.1.6   root       66:        // このパネルへのキー入力はメインビューへのキー入力と同じ。
1.1.1.13! root       67:        auto mainframe = dynamic_cast<WXMainFrame*>(GetParent()->GetParent());
        !            68:        auto mainview = mainframe->GetMainView();
1.1.1.9   root       69:        Connect(wxEVT_CHAR, wxCharEventHandler(WXMainView::OnChar), NULL,
1.1.1.13! root       70:                mainview);
1.1.1.6   root       71:        Connect(wxEVT_KEY_UP, wxKeyEventHandler(WXMainView::OnKeyUp), NULL,
1.1.1.13! root       72:                mainview);
1.1.1.6   root       73:        Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(WXMainView::OnKeyDown), NULL,
1.1.1.13! root       74:                mainview);
1.1.1.6   root       75: 
1.1.1.8   root       76:        // VM からの通知を受け取る
                     77:        WXUIMessage::Connect(UIMessage::KEYBOARD, this,
                     78:                wxCommandEventHandler(WXSoftKeyPanel::OnKeyChanged));
1.1.1.11  root       79: 
                     80:        // 初期タイトルを保存しといて..
                     81:        title = dynamic_cast<wxFrame*>(parent)->GetTitle();
                     82:        // キーボードの接続状況でタイトルを更新する
                     83:        UpdateTitle();
1.1       root       84: }
                     85: 
                     86: // デストラクタ
1.1.1.4   root       87: WXSoftKeyPanel::~WXSoftKeyPanel()
1.1       root       88: {
1.1.1.10  root       89:        // ウィンドウクローズでトグルキーのワンショットは開放する
1.1.1.9   root       90:        // (長押しは開放しない)
1.1.1.10  root       91:        for (const auto& k : toggle) {
                     92:                auto code = k.second;
                     93:                if (code) {
                     94:                        KeyUp(code);
                     95:                }
                     96:        }
1.1.1.9   root       97: 
                     98:        timer.Stop();
                     99: 
1.1.1.13! root      100:        WXUIMessage::Disconnect(UIMessage::KEYBOARD, this,
1.1.1.8   root      101:                wxCommandEventHandler(WXSoftKeyPanel::OnKeyChanged));
1.1       root      102: }
                    103: 
1.1.1.11  root      104: // キーボードの接続状況によって親フレームのタイトルを更新する。
                    105: // ついでにメンバ変数を更新する。
                    106: void
                    107: WXSoftKeyPanel::UpdateTitle()
                    108: {
                    109:        auto parent = dynamic_cast<WXSoftKeyWindow *>(GetParent());
                    110:        assert(parent);
                    111: 
                    112:        // 次回比較用にメンバ変数に覚えておく
1.1.1.13! root      113:        connected = keyboard->IsConnected();
1.1.1.11  root      114: 
                    115:        if (connected) {
                    116:                parent->SetTitle(title);
                    117:        } else {
                    118:                parent->SetTitle(title + _(" (disconnected)"));
                    119:        }
                    120: }
                    121: 
1.1.1.9   root      122: // color.Keytop の初期化(補間)。
                    123: // num はキートップの種類の数。1 か 2
                    124: void
                    125: WXSoftKeyPanel::InitColorKeytop(int num)
                    126: {
1.1.1.11  root      127:        Color pressed = UD_BLUE;
1.1.1.9   root      128: 
                    129:        auto f = [](int a, int b, int x) {
                    130:                return a * x / 100 + b * (100 - x) / 100;
                    131:        };
                    132: 
                    133:        // Keytop[i][9] は押されたときの色
                    134:        // Keytop[i][0] は押されていないときの色
                    135:        for (int i = 0; i < num; i++) {
                    136:                for (int j = 1; j < 10; j++) {
                    137:                        int n = j * 100 / 9;
1.1.1.11  root      138:                        color.Keytop[i][j] = Color(
                    139:                                f(pressed.r, color.Keytop[i][0].r, n),
                    140:                                f(pressed.g, color.Keytop[i][0].g, n),
                    141:                                f(pressed.b, color.Keytop[i][0].b, n));
1.1.1.9   root      142:                }
                    143:        }
                    144: }
                    145: 
1.1.1.11  root      146: // フォントサイズ変更
1.1       root      147: void
1.1.1.11  root      148: WXSoftKeyPanel::FontChanged()
1.1       root      149: {
1.1.1.11  root      150:        inherited::FontChanged();
1.1       root      151: 
                    152:        // このパネル内の描画の基本単位
                    153:        unit = font_height / 4;
                    154: 
                    155:        // エンターキーだけ矩形でないのでここでリージョンを計算。
                    156:        // unit が確定したところで一回行う。
1.1.1.6   root      157:        // ただし SHIFT_R のキーコードはちょっと使いづらいので、ここでは SHIFT_R
                    158:        // を使わず [_] キーで代用する。
                    159:        //
                    160:        //   |   ^   |   \   |   BS  |
                    161:        //   |       |       |       |
                    162:        // --+---+---+--(A)--+------(B)
                    163:        //       |       |           |
1.1.1.11  root      164:        //       |   [   |   Enter   |
                    165:        //       |       |           |
                    166:        // --+---+---+--(F)-(E) - - (G)
1.1.1.6   root      167:        //   |       |       |       |
                    168:        //   |   :   |   ]   |       |
                    169:        //   |       |       |       |
                    170:        // --+---+---+------(D)-----(C)
                    171:        //       |                   |
                    172:        //   _   |      SHIFT        |
1.1       root      173:        //
1.1.1.11  root      174:        // Enter キーの上半分 A-B-G-F を enter_top。F-G の線分を含む。
                    175:        // Enter キーの下半分 E-G-C-D を enter_btm。E-G の線分を含む。
1.1       root      176:        const keydata_t& keybs = FindKeydata(KC_BS);
                    177:        const keydata_t& keyleft = FindKeydata(KC_bracketleft);
                    178:        const keydata_t& keyright = FindKeydata(KC_bracketright);
1.1.1.6   root      179:        const keydata_t& keyscore = FindKeydata(KC_underscore);
1.1.1.11  root      180:        enter_top.SetLTRB(
                    181:                keyleft.right() * unit, keyleft.y * unit,
                    182:                keybs.right() * unit, keyright.y * unit);
                    183:        enter_btm.SetLTRB(
                    184:                keyright.right() * unit, keyright.y * unit,
                    185:                keybs.right() * unit, keyscore.y * unit);
1.1       root      186: 
1.1.1.13! root      187:        // アイコンを変更。参照順序の関係で下のほうにおいてある…。
        !           188:        InitIcon();
        !           189: 
        !           190:        // バックバッファのサイズを固定する
1.1.1.4   root      191:        wxSize size(u_width * unit, u_height * unit);
1.1.1.13! root      192:        SetFixedSize(size);
        !           193: 
        !           194:        // コントロールの大きさを変更
1.1       root      195:        SetClientSize(size);
1.1.1.6   root      196:        SetMinClientSize(size);
1.1       root      197: }
                    198: 
1.1.1.9   root      199: void
                    200: WXSoftKeyPanel::OnTimer(wxTimerEvent& event)
                    201: {
                    202:        Refresh();
                    203: }
                    204: 
1.1.1.8   root      205: // キー状態変更イベント (UIMessage)
1.1.1.9   root      206: //
                    207: // キー状態変更イベントは、キーの状態が変わるたびに都度通知される。
                    208: // ソフトウェアキーボード入力とパススルーモードの入力では、どのキーに変化
                    209: // (押下 or 開放)があったかの情報は付属しない。各キーの押下状態は全キーを
                    210: // 逐一調査することで判定する。人間時間で起きる事象なのでこの計算量は許容。
                    211: // Char 入力モードの場合は、イベントのパラメータ引数 (GetInt() で取得可) に
                    212: // 入力のあったキーの共通キーコードが入っている (複数のキーが同時に押される
                    213: // 場合はキーの回数分のイベントが飛んでくる)。Char 入力モードにはキー開放
                    214: // という概念はない。
1.1.1.6   root      215: void
1.1.1.8   root      216: WXSoftKeyPanel::OnKeyChanged(wxCommandEvent& event)
1.1.1.6   root      217: {
1.1.1.9   root      218:        // Char 入力モードでキーが押された場合は、共通キーコードが送られてくるので、
                    219:        // persistence[] をここでセットする。
                    220:        // Char 入力モードでは、キーの Make/Break が一瞬で終わるため、このイベント
                    221:        // を受け取って Refresh() を発行 -> OnPaint() -> Draw() 内で IsPressed()
                    222:        // を調べた頃にはタイミング問題でもうキーが離されている可能性があるので、
                    223:        // 描画時に全キーを調べる方法は使えない。
                    224:        uint keycode = event.GetInt();
                    225:        if (keycode != 0) {
                    226:                assert(keycode < persistence.size());
                    227:                // 9 が減光時の初期値 (10 は減光しない点灯)
                    228:                persistence[keycode] = 9;
1.1.1.6   root      229:        }
1.1.1.9   root      230: 
1.1.1.10  root      231:        // トグルキーが開放されていたらトグル情報をクリアする。
                    232:        // ハードウェアキーボードを含む VM 側で開放された場合と、
                    233:        // ソフトウェアキーボードの KeyUp() で開放された場合のどちらも
                    234:        // ここでクリア。
                    235:        for (auto& k : toggle) {
1.1.1.13! root      236:                if (keyboard->IsPressed(k.first) == false) {
1.1.1.10  root      237:                        k.second = 0;
                    238:                }
                    239:        }
                    240: 
1.1.1.11  root      241:        // 接続状況が変わっていたらタイトルを更新。
1.1.1.13! root      242:        if (keyboard->IsConnected() != connected) {
1.1.1.11  root      243:                UpdateTitle();
                    244:        }
1.1.1.6   root      245: 
1.1.1.11  root      246:        Refresh();
1.1       root      247: }
                    248: 
                    249: // 描画本体
                    250: void
1.1.1.11  root      251: WXSoftKeyPanel::Draw()
1.1       root      252: {
1.1.1.9   root      253:        bool timer_start = false;
                    254: 
                    255:        // キー刻印の表示更新用に修飾キーの状態を更新。
                    256:        // 本来は IsShift() だけで判定すべきだが、Char 入力モードでいずれかの
                    257:        // SHIFT キーが減光中は SHIFT 刻印を継続してみるのはどうか。
                    258:        // 0 まで待つとうちの環境だと消灯した少し後に刻印が戻るように見えるため、
                    259:        // ある程度暗くなったところでもう切り替えてみる。閾値は適当。
                    260:        if ((2 < persistence[KC_SHIFT_L] && persistence[KC_SHIFT_L] < 10) ||
                    261:            (2 < persistence[KC_SHIFT_R] && persistence[KC_SHIFT_R] < 10) ||
                    262:                (2 < persistence[KC_SHIFT]   && persistence[KC_SHIFT]   < 10) ||
1.1.1.13! root      263:                keyboard->IsShift())
1.1.1.9   root      264:        {
                    265:                modifier = ModShift;
                    266:        } else {
                    267:                modifier = ModNormal;
                    268:        }
                    269: 
1.1.1.11  root      270:        auto text_color = color.Text;
                    271: 
                    272:        // キーボードが接続されていないときは刻印をグレーにしておく
1.1.1.13! root      273:        if (keyboard->IsConnected() == false) {
1.1.1.11  root      274:                text_color = UD_GREY;
                    275:        }
                    276:        SetTextForeColor(text_color);
1.1       root      277: 
1.1.1.6   root      278:        for (const auto& key : keydata) {
1.1.1.9   root      279:                int c = persistence[key.keycode];
                    280:                if (0 < c && c < 10) {
                    281:                        // Char 入力モードで減光中
                    282:                        c--;
                    283:                        timer_start = true;
1.1       root      284:                } else {
1.1.1.9   root      285:                        // そうでない場合に限り、現在の状態を問い合わせる
1.1.1.13! root      286:                        bool is_pressed = keyboard->IsPressed(key.keycode);
1.1.1.9   root      287:                        if (is_pressed) {
                    288:                                // 押されている
                    289:                                c = 10;
                    290:                        } else {
                    291:                                // 押されていない
                    292:                                c = 0;
                    293:                        }
                    294:                }
                    295:                // persistence[] は 10 が(減光しない)点灯、9..1 が減光中を示す。
                    296:                persistence[key.keycode] = c;
                    297:                // ただし色配列は 0..9 で 9 が最大点灯色
                    298:                if (c > 9) {
                    299:                        c = 9;
1.1       root      300:                }
                    301: 
1.1.1.9   root      302:                SetTextBackColor(color.Keytop[key.coltype][c]);
                    303: 
1.1.1.13! root      304:                // エンターキーとブザー表示は描き方が違うので別処理
        !           305:                if (__predict_false(key.keycode == KC_enter)) {
1.1.1.11  root      306:                        DrawEnterKey();
1.1.1.13! root      307:                } else if (__predict_false(key.keycode == KC_buzzer)) {
        !           308:                        DrawBuzzer(key);
1.1       root      309:                } else {
1.1.1.11  root      310:                        DrawKey(key);
1.1       root      311:                }
                    312:        }
                    313: 
1.1.1.9   root      314:        if (timer_start) {
                    315:                timer.Start(25);
                    316:        } else {
                    317:                timer.Stop();
                    318:        }
1.1       root      319: }
                    320: 
                    321: // 指定のキーを一つ (枠から刻印まで) 描画する。
                    322: void
1.1.1.11  root      323: WXSoftKeyPanel::DrawKey(const keydata_t& key)
1.1       root      324: {
1.1.1.10  root      325:        uint attr = TA::Normal;
                    326: 
1.1       root      327:        // 枠
1.1.1.11  root      328:        Rect rect(
                    329:                key.x * unit,     key.y * unit,
                    330:                key.w * unit + 1, key.h * unit + 1);
                    331:        bitmap.FillRect(palette[0], rect);
                    332:        bitmap.DrawRect(color.Text, rect);
1.1       root      333: 
                    334:        // 刻印を選択
                    335:        const char *disp = key.disp[modifier];
                    336:        if (disp == NULL) {
                    337:                disp = key.disp[0];
                    338:        }
                    339: 
1.1.1.10  root      340:        // トグルキーのワンショット押しは太字で表示を区別したい
                    341:        const auto it = toggle.find(key.keycode);
                    342:        if (it != toggle.end()) {
                    343:                if (it->second) {
                    344:                        attr = TA::Em;
                    345:                }
                    346:        }
                    347: 
1.1       root      348:        // Shift_JIS に変換
                    349:        wxString utfstr(disp, wxConvUTF8);
1.1.1.11  root      350:        // mb_str() をキャストせずに一度保持しておく必要がある (scan-build 対策)
                    351:        auto mbstr = utfstr.mb_str(conv);
                    352:        const char *sjis = (const char *)mbstr;
1.1.1.4   root      353:        // 改行があれば2行に分割
                    354:        char sjis1[8] {};
                    355:        char sjis2[8] {};
                    356:        int sjislen;
                    357:        int row;
                    358:        const char *lf = strchr(sjis, '\n');
                    359:        if (lf == NULL) {
                    360:                // 1行なら、Shift_JIS での文字数は半角換算の文字数と一致する。
                    361:                sjislen = strlen(sjis);
                    362:                row = 1;
                    363:        } else {
                    364:                // 2行に分割。センタリングは1行目の長さだけで調べる。
                    365:                strncpy(sjis1, sjis, lf - sjis);
                    366:                strcpy(sjis2, lf + 1);
                    367:                sjislen = strlen(sjis1);
                    368:                row = 2;
                    369:        }
1.1       root      370: 
                    371:        // センタリング
                    372:        int x = key.x + (key.w - sjislen * 2) / 2;
1.1.1.4   root      373:        int y = key.y + (key.h - row * 4) / 2;
1.1       root      374: 
1.1.1.4   root      375:        // LED を描画 (機種によって色々違うので個別クラス側で処理)
                    376:        if (key.led >= 0) {
1.1.1.11  root      377:                y += DrawLED(key);
1.1       root      378:        }
                    379: 
                    380:        // 文字を描画
1.1.1.11  root      381:        x = x * unit + 1;
                    382:        y = y * unit + 1;
1.1.1.4   root      383:        if (strcmp(disp, EnterMark) == 0) {
1.1.1.13! root      384:                bitmap.DrawBitmap(x, y, *enter_icon, palette);
1.1       root      385:        } else {
1.1.1.4   root      386:                if (lf == NULL) {
                    387:                        // 1行の場合
1.1.1.11  root      388:                        DrawStringSJIS(x, y, sjis, attr);
1.1.1.4   root      389:                } else {
                    390:                        // 2行の場合
1.1.1.11  root      391:                        DrawStringSJIS(x, y, sjis1);
                    392:                        y += 4 * unit;
                    393:                        DrawStringSJIS(x, y, sjis2);
1.1.1.4   root      394:                }
1.1       root      395:        }
                    396: }
                    397: 
                    398: // エンターキー
                    399: void
1.1.1.11  root      400: WXSoftKeyPanel::DrawEnterKey()
1.1       root      401: {
1.1.1.11  root      402:        // 矩形の内側を背景色で塗りつぶす。
                    403:        bitmap.FillRect(palette[0], enter_top);
                    404:        bitmap.FillRect(palette[0], enter_btm);
                    405: 
                    406:        // 周囲の線分
                    407:        // (A)-(B)
                    408:        bitmap.DrawLineH(color.Text,
                    409:                enter_top.x, enter_top.y, enter_top.GetRight());
                    410:        // (B)-(C)
                    411:        bitmap.DrawLineV(color.Text,
                    412:                enter_top.GetRight(), enter_top.y, enter_btm.GetBottom());
                    413:        // (C)-(D)
                    414:        bitmap.DrawLineH(color.Text,
                    415:                enter_btm.GetRight(), enter_btm.GetBottom(), enter_btm.x);
                    416:        // (D)-(E)
                    417:        bitmap.DrawLineV(color.Text,
                    418:                enter_btm.x, enter_btm.GetBottom(), enter_btm.y);
                    419:        // (E)-(F)
                    420:        bitmap.DrawLineH(color.Text,
                    421:                enter_btm.x, enter_top.GetBottom(), enter_top.x);
                    422:        // (F)-(A)
                    423:        bitmap.DrawLineV(color.Text,
                    424:                enter_top.x, enter_top.GetBottom(), enter_top.y);
1.1       root      425: 
                    426:        // エンター記号を描画
1.1.1.13! root      427:        bitmap.DrawBitmap(
1.1.1.11  root      428:                (enter_top.x + enter_top.GetRight())  / 2 - (4 / 2),
1.1.1.13! root      429:                (enter_top.y + enter_btm.GetBottom()) / 2 - (4 / 2),
        !           430:                *enter_icon, palette);
1.1.1.11  root      431: }
                    432: 
1.1.1.13! root      433: // ブザー表示(キーに相当)を描画
        !           434: void
        !           435: WXSoftKeyPanel::DrawBuzzer(const keydata_t& key)
        !           436: {
        !           437:        Color fg;
        !           438: 
        !           439:        // 枠。キーではないので薄くしておく。
        !           440:        Rect rect(
        !           441:                key.x * unit,     key.y * unit,
        !           442:                key.w * unit + 1, key.h * unit + 1);
        !           443:        bitmap.FillRect(palette[0], rect);
        !           444:        bitmap.DrawRect(UD_GREY, rect);
        !           445: 
        !           446:        // テキスト色は本来呼び出し元の DrawKey() で設定してあるが、
        !           447:        // ここはキーではないので非発声時の文字色だけ薄くしたい。
        !           448:        // 発声時はキー押下と同じにする。
        !           449:        fg = GetTextForeColor();
        !           450:        if (persistence[key.keycode] == 0) {
        !           451:                SetTextForeColor(UD_GREY);
        !           452:        }
1.1.1.11  root      453: 
1.1.1.13! root      454:        // 刻印 (モディファイヤの影響を受けないと分かっているので常に [0])
        !           455:        const char *disp = key.disp[0];
        !           456:        assert(disp);
        !           457: 
        !           458:        // センタリング
        !           459:        int x = key.x + (key.w - strlen(disp) * 2) / 2;
        !           460:        int y = key.y + (key.h - 4) / 2;
        !           461: 
        !           462:        // 文字を描画
        !           463:        x = x * unit + 1;
        !           464:        y = y * unit + 1;
        !           465:        DrawStringSJIS(x, y, disp, TA::Normal);
        !           466: 
        !           467:        // 前景色を元に戻す
        !           468:        SetTextForeColor(fg);
        !           469: }
        !           470: 
        !           471: #define B(x)   (0b##x)
        !           472: #define B2(x)  (B(x) >> 8), (B(x) & 0xff)
        !           473: #define B3(x)  (B(x) >> 16), ((B(x) >> 8) & 0xff), (B(x) & 0xff)
        !           474: 
        !           475: static const uint8 EnterIcon12[] = {   // 12x12
        !           476:        B2(000000000000'0000),  // 0
        !           477:        B2(000000001110'0000),  // 1
        !           478:        B2(000000001010'0000),  // 2
        !           479:        B2(000000001010'0000),  // 3
        !           480:        B2(000000001010'0000),  // 4
        !           481:        B2(001100001010'0000),  // 5
        !           482:        B2(010111110010'0000),  // 6
        !           483:        B2(100000000010'0000),  // 7
        !           484:        B2(010111111100'0000),  // 8
        !           485:        B2(001100000000'0000),  // 9
        !           486:        B2(000000000000'0000),  // a
        !           487:        B2(000000000000'0000),  // b
1.1.1.11  root      488: };
1.1.1.13! root      489: 
        !           490: static const uint8 EnterIcon16[] = {   // 16x16
        !           491:        B2(0000000000111110),   // 0
        !           492:        B2(0000000000100010),   // 1
        !           493:        B2(0000000000100010),   // 2
        !           494:        B2(0000000000100010),   // 3
        !           495:        B2(0000000000100010),   // 4
        !           496:        B2(0000000000100010),   // 5
        !           497:        B2(0000000000100010),   // 6
        !           498:        B2(0000110000100010),   // 7
        !           499:        B2(0001010000100010),   // 8
        !           500:        B2(0010011111000010),   // 9
        !           501:        B2(0100000000000010),   // a
        !           502:        B2(1000000000000010),   // b
        !           503:        B2(0100000000000010),   // c
        !           504:        B2(0010011111111100),   // d
        !           505:        B2(0001010000000000),   // e
        !           506:        B2(0000110000000000),   // f
1.1.1.11  root      507: };
1.1       root      508: 
1.1.1.13! root      509: static const uint8 EnterIcon24[] = {   // 24x24
        !           510:        B3(00000000'00000001'11111100), // 0
        !           511:        B3(00000000'00000001'11111100), // 1
        !           512:        B3(00000000'00000001'10001100), // 2
        !           513:        B3(00000000'00000001'10001100), // 3
        !           514:        B3(00000000'00000001'10001100), // 4
        !           515:        B3(00000000'00000001'10001100), // 5
        !           516:        B3(00000000'00000001'10001100), // 6
        !           517:        B3(00000000'00000001'10001100), // 7
        !           518:        B3(00000000'00000001'10001100), // 8
        !           519:        B3(00000000'11000001'10001100), // 9
        !           520:        B3(00000001'11000001'10001100), // 10
        !           521:        B3(00000011'11000001'10001100), // 11
        !           522:        B3(00000110'11000001'10001100), // 12
        !           523:        B3(00001100'11111111'10001100), // 13
        !           524:        B3(00011000'11111111'10001100), // 14
        !           525:        B3(00110000'00000000'00001100), // 15
        !           526:        B3(01100000'00000000'00001100), // 16
        !           527:        B3(00110000'00000000'00001100), // 17
        !           528:        B3(00011000'11111111'11111100), // 18
        !           529:        B3(00001100'11111111'11111000), // 19
        !           530:        B3(00000110'11000000'00000000), // 20
        !           531:        B3(00000011'11000000'00000000), // 21
        !           532:        B3(00000001'11000000'00000000), // 22
        !           533:        B3(00000000'11000000'00000000), // 23
        !           534: };
        !           535: 
        !           536: // アイコンを初期化する。FontChanged() から呼ばれる。
        !           537: // ソース先頭のほうにデータの羅列を置きたくないが、
        !           538: // 容量不詳の配列の解決が面倒なのでこれだけ下のほうのここに置いてある。
1.1       root      539: void
1.1.1.13! root      540: WXSoftKeyPanel::InitIcon()
1.1       root      541: {
1.1.1.13! root      542:        const int width  = font_width;
        !           543:        const int height = font_height;
        !           544:        const uint8 *icon;
1.1.1.11  root      545: 
1.1.1.13! root      546:        switch (height) {
1.1.1.11  root      547:         case 12:
1.1.1.13! root      548:                icon = EnterIcon12;
1.1.1.11  root      549:                break;
                    550:         case 16:
1.1.1.13! root      551:                icon = EnterIcon16;
        !           552:                break;
        !           553:         case 24:
        !           554:                icon = EnterIcon24;
1.1.1.11  root      555:                break;
                    556:         default:
1.1.1.13! root      557:                PANIC("Unexpected font_height=%d", height);
1.1       root      558:        }
1.1.1.13! root      559: 
        !           560:        enter_icon.reset(new BitmapI1(icon, width * 2, height));
1.1       root      561: }
                    562: 
                    563: // keycode に対応する keydata を返す
                    564: const keydata_t&
1.1.1.4   root      565: WXSoftKeyPanel::FindKeydata(uint keycode) const
1.1       root      566: {
1.1.1.6   root      567:        for (const auto& key : keydata) {
1.1       root      568:                if (key.keycode == keycode) {
                    569:                        return key;
                    570:                }
                    571:        }
                    572:        // 見付からないはずはない
1.1.1.11  root      573:        PANIC("keycode %d not found", keycode);
1.1       root      574: }
                    575: 
                    576: // マウス左クリック (Down) イベント
                    577: void
1.1.1.4   root      578: WXSoftKeyPanel::OnLeftDown(wxMouseEvent& event)
1.1       root      579: {
1.1.1.5   root      580:        const wxPoint& pt = event.GetPosition();
1.1.1.4   root      581:        const keydata_t *key = GetKeydataFromPoint(pt);
1.1       root      582: 
1.1.1.9   root      583:        if (key != NULL) {
1.1.1.10  root      584:                DoLeftDown(key->keycode);
1.1.1.9   root      585:        }
1.1       root      586: }
                    587: 
                    588: // マウス左クリック (Down) 処理
                    589: void
1.1.1.10  root      590: WXSoftKeyPanel::DoLeftDown(uint code)
1.1       root      591: {
1.1.1.10  root      592:        auto it = toggle.find(code);
                    593:        if (it != toggle.end()) {
                    594:                // トグルキーはここで完結。LeftUp では何もしない。
                    595:                // second のクリアは KeyUp() からコールバックされる OnKeyChanged()
                    596:                // で行っている。
1.1.1.13! root      597:                if (keyboard->IsPressed(code)) {
1.1.1.10  root      598:                        KeyUp(code);
1.1.1.9   root      599:                } else {
1.1.1.10  root      600:                        KeyDown(code);
                    601:                        it->second = code;
1.1.1.9   root      602:                }
1.1.1.10  root      603:                leftdown_key = KC_none;
1.1.1.9   root      604:        } else {
1.1.1.10  root      605:                // トグルでない通常キーはここで押下して LeftUp のために覚えておく
                    606:                KeyDown(code);
                    607:                leftdown_key = code;
1.1       root      608:        }
                    609: }
                    610: 
                    611: // マウス左クリック (Up) イベント
                    612: void
1.1.1.4   root      613: WXSoftKeyPanel::OnLeftUp(wxMouseEvent& event)
1.1       root      614: {
                    615:        // Up 時は、これが起きた地点のキーコードではなく
                    616:        // 直近に LeftDown したキーコードをターゲットにする。
1.1.1.10  root      617:        uint code = leftdown_key;
1.1       root      618: 
1.1.1.10  root      619:        if (code != KC_none) {
                    620:                KeyUp(code);
1.1.1.9   root      621: 
1.1.1.10  root      622:                // 通常キーが離されたら、トグルキーはすべて開放
                    623:                for (const auto& k : toggle) {
                    624:                        auto tcode = k.second;
                    625:                        if (tcode) {
                    626:                                KeyUp(tcode);
1.1.1.9   root      627:                        }
                    628:                }
1.1       root      629:        }
1.1.1.9   root      630: 
1.1.1.10  root      631:        leftdown_key = KC_none;
1.1       root      632: }
                    633: 
                    634: // マウス左ダブルクリックイベント
                    635: // ダブルクリックという操作に特別何かを割り当ててはいないが、
                    636: // キーを連打するとその間隔によってはダブルクリックと扱われるため、
                    637: // 受け取ってここで処理する。
                    638: //
                    639: // DClick イベントは LeftDown、LeftUp、LeftDClick、LeftUp の順で
                    640: // 飛んでくるので、ここでは2回目の押下だけ処理すればよい。というか
                    641: // 処理自体は LeftDown とまったく同じになるので、イベントテーブルで
                    642: // 直接 EVT_LEFT_DCLICK => OnLeftDown に割り付けることも出来そうだが
                    643: // デバッグが紛らわしくなりそうなので独立したイベントとしておく。
                    644: void
1.1.1.4   root      645: WXSoftKeyPanel::OnLeftDClick(wxMouseEvent& event)
1.1       root      646: {
1.1.1.5   root      647:        const wxPoint& pt = event.GetPosition();
1.1.1.4   root      648:        const keydata_t *key = GetKeydataFromPoint(pt);
1.1       root      649: 
1.1.1.9   root      650:        if (key != NULL) {
1.1.1.10  root      651:                DoLeftDown(key->keycode);
1.1.1.9   root      652:        }
1.1       root      653: }
                    654: 
                    655: // マウス右クリック (Down) イベント
                    656: // 長押し開始/解除。
                    657: // 右クリックのほうは Down だけで Up は使わない。
                    658: void
1.1.1.4   root      659: WXSoftKeyPanel::OnRightDown(wxMouseEvent& event)
1.1       root      660: {
1.1.1.5   root      661:        const wxPoint& pt = event.GetPosition();
1.1.1.4   root      662:        const keydata_t *key = GetKeydataFromPoint(pt);
1.1       root      663: 
1.1.1.4   root      664:        if (key != NULL) {
                    665:                uint code = key->keycode;
1.1.1.13! root      666:                if (keyboard->IsPressed(code)) {
1.1       root      667:                        // 押されていたら開放
1.1.1.10  root      668:                        KeyUp(code);
1.1       root      669:                } else {
                    670:                        // 押されてなければ長押し開始
1.1.1.10  root      671:                        KeyDown(code);
1.1       root      672:                }
                    673:        }
                    674: }
                    675: 
1.1.1.4   root      676: // 座標からキーデータを返す。
                    677: // キーに当たっていなければ NULL を返す。
                    678: const keydata_t *
                    679: WXSoftKeyPanel::GetKeydataFromPoint(const wxPoint& pt) const
1.1       root      680: {
1.1.1.4   root      681:        // エンターキーだけ先に別判定
1.1.1.11  root      682:        if (enter_top.Contains(pt.x, pt.y) || enter_btm.Contains(pt.x, pt.y)) {
1.1.1.4   root      683:                return &FindKeydata(KC_enter);
                    684:        }
1.1       root      685: 
1.1.1.6   root      686:        for (const auto& key : keydata) {
1.1.1.4   root      687:                if (key.x < 0) {
                    688:                        continue;
1.1       root      689:                }
1.1.1.4   root      690:                // 始点と幅の +1/-1 は罫線の分
                    691:                wxRect rect(
                    692:                        (key.x * unit) + 1,
                    693:                        (key.y * unit) + 1,
                    694:                        (key.w * unit) - 1,
                    695:                        (key.h * unit) - 1);
                    696:                if (rect.Contains(pt)) {
                    697:                        return &key;
1.1       root      698:                }
1.1.1.4   root      699:        }
                    700:        return NULL;
                    701: }
                    702: 
1.1.1.6   root      703: // このキーが押された処理
                    704: void
1.1.1.10  root      705: WXSoftKeyPanel::KeyDown(uint code)
1.1.1.6   root      706: {
1.1.1.9   root      707:        // VM に通知 (Keyboard がホストに通知する)
1.1.1.13! root      708:        keyboard->MakeKey(code);
1.1.1.6   root      709: }
                    710: 
                    711: // このキーが放された処理
                    712: void
1.1.1.10  root      713: WXSoftKeyPanel::KeyUp(uint code)
1.1.1.6   root      714: {
1.1.1.9   root      715:        // VM に通知 (Keyboard がホストに通知する)
1.1.1.13! root      716:        keyboard->BreakKey(code);
1.1.1.6   root      717: }
                    718: 
                    719: 
1.1.1.4   root      720: //
                    721: // LUNA ソフトウェアキーボード (パネル)
                    722: //
                    723: 
                    724: // コンストラクタ
                    725: WXLunaSoftKeyPanel::WXLunaSoftKeyPanel(wxWindow *parent)
1.1.1.6   root      726:        : inherited(parent, keydata, 226, 54)
1.1.1.4   root      727: {
                    728:        // LUNA では
                    729:        // BS キーの左隣 (0x5c) は円記号ではなくバックスラッシュ。
                    730:        // それを SHIFT したやつ(0x7c) は破線でないパイプ。
                    731:        // そのもう一つ左隣 (0x7e) はオーバーラインではなくチルダ。
1.1.1.11  root      732:        gFontManager->SetGlyph5C(true);
                    733:        gFontManager->SetGlyph7E(true);
1.1.1.4   root      734: 
1.1.1.9   root      735:        // 白黒モデル共通
1.1.1.11  root      736:        color.Border = UD_BLACK;
1.1.1.9   root      737:        color.LED[0] = UD_RED;
                    738: 
1.1.1.4   root      739:        // キートップの濃淡はユニバーサルデザインの推奨色ではないけど
                    740:        // ここは見分けを付けるためではなくただのデザインなので。
                    741:        if (1) {
                    742:                // 白モデル
1.1.1.9   root      743:                color.Background        = UD_LIGHT_GREY;        // 現物新品は何色だったんだろう
1.1.1.11  root      744:                color.Text                      = UD_BLACK;
                    745:                color.Keytop[0][0]      = UD_WHITE;
                    746:                color.Keytop[1][0]      = Color(200, 200, 203);
1.1.1.4   root      747:        } else {
                    748:                // 黒モデル
1.1.1.11  root      749:                color.Background        = UD_BLACK;
                    750:                color.Text                      = UD_WHITE;
                    751:                color.Keytop[0][0]      = Color(50, 50, 53);
                    752:                color.Keytop[1][0]      = UD_BLACK;
1.1.1.4   root      753:        }
1.1.1.9   root      754:        InitColorKeytop(2);
1.1.1.11  root      755: 
                    756:        SetBitmapBGColor(color.Background);
1.1.1.13! root      757:        Fill();
1.1.1.4   root      758: }
                    759: 
                    760: // デストラクタ
                    761: WXLunaSoftKeyPanel::~WXLunaSoftKeyPanel()
                    762: {
                    763: }
                    764: 
                    765: // LED を描画して刻印描画のための y offset を返す。
                    766: int
1.1.1.11  root      767: WXLunaSoftKeyPanel::DrawLED(const keydata_t& key)
1.1.1.4   root      768: {
1.1.1.13! root      769:        const std::vector<bool>& led = keyboard->GetLED();
1.1.1.11  root      770:        Color fg;
                    771:        Color bg;
1.1.1.4   root      772: 
                    773:        if (led[key.led]) {
                    774:                // 点灯時は赤、枠は黒
1.1.1.11  root      775:                fg = color.Border;
                    776:                bg = color.LED[0];
1.1       root      777:        } else {
1.1.1.4   root      778:                // 消灯時は元のキートップの色で、枠は薄めにしたい
1.1.1.6   root      779:                // (枠の色は今の所全モデル共通なので ColorPalette に含めていない)
1.1.1.11  root      780:                fg = UD_GREY;
                    781:                bg = color.Keytop[key.coltype][0];
1.1       root      782:        }
                    783: 
1.1.1.4   root      784:        // LED を左肩に描く
1.1.1.11  root      785:        Rect rect(key.x * unit + 2, key.y * unit + 2, 4 * unit - 2, 3 * unit - 2);
                    786:        bitmap.FillRect(bg, rect);
                    787:        bitmap.DrawRect(fg, rect);
1.1.1.4   root      788: 
                    789:        // そのため文字は少し下げる
                    790:        return +1;
                    791: }
                    792: 
1.1       root      793: // キーデータ
                    794: #define H       (8)    // キーの高さ
                    795: #define L0      (2)    // ファンクションキーの行
                    796: #define L1     (12)    // ESC の行
                    797: #define L2     (20)    // TAB の行
                    798: #define L3     (28)    // CTRL の行
                    799: #define L4     (36)    // SHIFT の行
                    800: #define L5     (44)    // space の行
                    801: /*static*/ std::vector<keydata_t>
                    802: WXLunaSoftKeyPanel::keydata {
1.1.1.4   root      803:        //                +---- キートップの色(1:濃)
                    804:        //                |  +- 0 以上なら LED 番号
                    805:        //  X   Y   W  H  C  L  KeyCode                         通常  SHIFT
                    806:        {   2, L0, 15, H, 1,-1, KC_F1,                          { "PF1" } },
                    807:        {  17, L0, 15, H, 1,-1, KC_F2,                          { "PF2" } },
                    808:        {  32, L0, 15, H, 1,-1, KC_F3,                          { "PF3" } },
                    809:        {  47, L0, 15, H, 1,-1, KC_F4,                          { "PF4" } },
                    810:        {  62, L0, 15, H, 1,-1, KC_F5,                          { "PF5" } },
                    811:        {  81, L0, 15, H, 1,-1, KC_F6,                          { "PF6" } },
                    812:        {  96, L0, 15, H, 1,-1, KC_F7,                          { "PF7" } },
                    813:        { 111, L0, 15, H, 1,-1, KC_F8,                          { "PF8" } },
                    814:        { 126, L0, 15, H, 1,-1, KC_F9,                          { "PF9" } },
                    815:        { 141, L0, 15, H, 1,-1, KC_F10,                         { "PF10" } },
1.1.1.13! root      816:        { 210, L0+1, 14, H-2, 1,-1, KC_buzzer,          { "Buzzer" } },
1.1.1.4   root      817: 
                    818:        {   2, L1, 12, H, 1,-1, KC_ESC,                         { "ESC" } },
                    819:        {  14, L1, 10, H, 0,-1, KC_1,                           { "1",  "!" } },
                    820:        {  24, L1, 10, H, 0,-1, KC_2,                           { "2",  "\"" } },
                    821:        {  34, L1, 10, H, 0,-1, KC_3,                           { "3",  "#" } },
                    822:        {  44, L1, 10, H, 0,-1, KC_4,                           { "4",  "$" } },
                    823:        {  54, L1, 10, H, 0,-1, KC_5,                           { "5",  "%" } },
                    824:        {  64, L1, 10, H, 0,-1, KC_6,                           { "6",  "&" } },
                    825:        {  74, L1, 10, H, 0,-1, KC_7,                           { "7",  "'" } },
                    826:        {  84, L1, 10, H, 0,-1, KC_8,                           { "8",  "(" } },
                    827:        {  94, L1, 10, H, 0,-1, KC_9,                           { "9",  ")" } },
                    828:        { 104, L1, 10, H, 0,-1, KC_0,                           { "0",  " " } },
                    829:        { 114, L1, 10, H, 0,-1, KC_minus,                       { "-",  "=" } },
                    830:        { 124, L1, 10, H, 0,-1, KC_circum,                      { "^",  "~" } },
                    831:        { 134, L1, 10, H, 0,-1, KC_backslash,           { "\\", "|" } },
                    832:        { 144, L1, 12, H, 1,-1, KC_BS,                          { "BS" } },
                    833: 
                    834:        {   2, L2, 17, H, 1,-1, KC_TAB,                         { "TAB" } },
                    835:        {  19, L2, 10, H, 0,-1, KC_Q,                           { "q",  "Q" } },
                    836:        {  29, L2, 10, H, 0,-1, KC_W,                           { "w",  "W" } },
                    837:        {  39, L2, 10, H, 0,-1, KC_E,                           { "e",  "E" } },
                    838:        {  49, L2, 10, H, 0,-1, KC_R,                           { "r",  "R" } },
                    839:        {  59, L2, 10, H, 0,-1, KC_T,                           { "t",  "T" } },
                    840:        {  69, L2, 10, H, 0,-1, KC_Y,                           { "y",  "Y" } },
                    841:        {  79, L2, 10, H, 0,-1, KC_U,                           { "u",  "U" } },
                    842:        {  89, L2, 10, H, 0,-1, KC_I,                           { "i",  "I" } },
                    843:        {  99, L2, 10, H, 0,-1, KC_O,                           { "o",  "O" } },
                    844:        { 109, L2, 10, H, 0,-1, KC_P,                           { "p",  "P" } },
                    845:        { 119, L2, 10, H, 0,-1, KC_at,                          { "@",  "`" } },
                    846:        { 129, L2, 10, H, 0,-1, KC_bracketleft,         { "[",  "{" } },
                    847: 
                    848:        {   2, L3, 20, H, 1,-1, KC_CTRL,                        { "CTRL" } },
                    849:        {  22, L3, 10, H, 0,-1, KC_A,                           { "a",  "A" } },
                    850:        {  32, L3, 10, H, 0,-1, KC_S,                           { "s",  "S" } },
                    851:        {  42, L3, 10, H, 0,-1, KC_D,                           { "d",  "D" } },
                    852:        {  52, L3, 10, H, 0,-1, KC_F,                           { "f",  "F" } },
                    853:        {  62, L3, 10, H, 0,-1, KC_G,                           { "g",  "G" } },
                    854:        {  72, L3, 10, H, 0,-1, KC_H,                           { "h",  "H" } },
                    855:        {  82, L3, 10, H, 0,-1, KC_J,                           { "j",  "J" } },
                    856:        {  92, L3, 10, H, 0,-1, KC_K,                           { "k",  "K" } },
                    857:        { 102, L3, 10, H, 0,-1, KC_L,                           { "l",  "L" } },
                    858:        { 112, L3, 10, H, 0,-1, KC_semicolon,           { ";",  "+" } },
                    859:        { 122, L3, 10, H, 0,-1, KC_colon,                       { ":",  "*" } },
                    860:        { 132, L3, 10, H, 0,-1, KC_bracketright,        { "]",  "}" } },
                    861: 
                    862:        {   2, L4, 25, H, 1,-1, KC_SHIFT_L,                     { "SHIFT" } },
                    863:        {  27, L4, 10, H, 0,-1, KC_Z,                           { "z",  "Z" } },
                    864:        {  37, L4, 10, H, 0,-1, KC_X,                           { "x",  "X" } },
                    865:        {  47, L4, 10, H, 0,-1, KC_C,                           { "c",  "C" } },
                    866:        {  57, L4, 10, H, 0,-1, KC_V,                           { "v",  "V" } },
                    867:        {  67, L4, 10, H, 0,-1, KC_B,                           { "b",  "B" } },
                    868:        {  77, L4, 10, H, 0,-1, KC_N,                           { "n",  "N" } },
                    869:        {  87, L4, 10, H, 0,-1, KC_M,                           { "m",  "M" } },
                    870:        {  97, L4, 10, H, 0,-1, KC_comma,                       { ",",  "<" } },
                    871:        { 107, L4, 10, H, 0,-1, KC_period,                      { ".",  ">" } },
                    872:        { 117, L4, 10, H, 0,-1, KC_slash,                       { "/",  "?" } },
                    873:        { 127, L4, 10, H, 0,-1, KC_underscore,          { " ",  "_" } },
                    874:        { 137, L4, 19, H, 1,-1, KC_SHIFT_R,                     { "SHIFT" } },
                    875: 
                    876:        {   2, L5, 20, H, 1,-1, KC_VALID,                       { "確定" } },
                    877:        {  22, L5, 10, H, 1,-1, KC_SF,                          { "前面" } },
                    878:        {  32, L5, 10, H, 1, 1, KC_CAPS,                        { "CAP" } },
                    879:        {  42, L5, 80, H, 0,-1, KC_space,                       { " " } },
                    880:        { 122, L5, 10, H, 1, 0, KC_kana,                        { "かな" } },
                    881:        { 132, L5, 24, H, 1,-1, KC_XFER,                        { "変換" } },
1.1       root      882: 
                    883:        // カーソルキー島
1.1.1.4   root      884:        { 160, L1, 10, H, 1,-1, KC_PF11,                        { "消去" } },
                    885:        { 170, L1, 10, H, 1,-1, KC_PF12,                        { "呼出" } },
                    886:        { 160, L2, 10, H, 1,-1, KC_PF13,                        { "文節\n←" } },
                    887:        { 170, L2, 10, H, 1,-1, KC_PF14,                        { "文節\n→" } },
                    888:        { 160, L3, 20, H, 1,-1, KC_up,                          { "↑" } },
                    889:        { 160, L4, 10, H, 1,-1, KC_left,                        { "←" } },
                    890:        { 170, L4, 10, H, 1,-1, KC_right,                       { "→" } },
                    891:        { 160, L5, 20, H, 1,-1, KC_down,                        { "↓" } },
1.1       root      892: 
                    893:        // テンキー島
1.1.1.4   root      894:        { 184, L1, 10, H, 1,-1, KC_DEL,                         { "DEL" } },
                    895:        { 194, L1, 10, H, 1,-1, KC_PAD_plus,            { "+" } },
                    896:        { 204, L1, 10, H, 1,-1, KC_PAD_minus,           { "-" } },
                    897:        { 214, L1, 10, H, 1,-1, KC_PAD_multiply,        { "*" } },
                    898: 
                    899:        { 184, L2, 10, H, 0,-1, KC_PAD_7,                       { "7" } },
                    900:        { 194, L2, 10, H, 0,-1, KC_PAD_8,                       { "8" } },
                    901:        { 204, L2, 10, H, 0,-1, KC_PAD_9,                       { "9" } },
                    902:        { 214, L2, 10, H, 1,-1, KC_PAD_divide,          { "/" } },
                    903: 
                    904:        { 184, L3, 10, H, 0,-1, KC_PAD_4,                       { "4" } },
                    905:        { 194, L3, 10, H, 0,-1, KC_PAD_5,                       { "5" } },
                    906:        { 204, L3, 10, H, 0,-1, KC_PAD_6,                       { "6" } },
                    907:        { 214, L3, 10, H, 1,-1, KC_PAD_equal,           { "=" } },
                    908: 
                    909:        { 184, L4, 10, H, 0,-1, KC_PAD_1,                       { "1" } },
                    910:        { 194, L4, 10, H, 0,-1, KC_PAD_2,                       { "2" } },
                    911:        { 204, L4, 10, H, 0,-1, KC_PAD_3,                       { "3" } },
                    912:        { 214, L4, 10, H, 1,-1, KC_PAD_comma,           { "," } },
                    913: 
                    914:        { 184, L5, 10, H, 0,-1, KC_PAD_0,                       { "0" } },
                    915:        { 194, L5, 10, H, 0,-1, KC_PAD_decimal,         { "." } },
                    916:        { 204, L5, 20, H, 1,-1, KC_PAD_enter,           { EnterMark } },
1.1       root      917: 
                    918:        // Enter だけ矩形でないので別処理するが
                    919:        // この構造体には全部のキー情報が統一的に並んでいるほうがよかろう。
1.1.1.4   root      920:        { -1, -1, -1, -1, 1,-1, KC_enter,                       { EnterMark } },
1.1       root      921: };
                    922: 
                    923: 
                    924: //
1.1.1.4   root      925: // X68k ソフトウェアキーボード (パネル)
                    926: //
                    927: 
                    928: // コンストラクタ
                    929: WXX68kSoftKeyPanel::WXX68kSoftKeyPanel(wxWindow *parent)
1.1.1.6   root      930:        : inherited(parent, keydata, 235, 54)
1.1.1.4   root      931: {
                    932:        // X68k では SRAM 設定に同期させる。
1.1.1.13! root      933:        const auto sram = GetSRAMDevice();
        !           934:        uint8 sw = sram->Peek8(0xed0059);
1.1.1.11  root      935:        gFontManager->SetGlyph5C((sw & 0x01));
                    936:        gFontManager->SetGlyph7E((sw & 0x02));
                    937:        gFontManager->SetGlyph7C((sw & 0x04));
1.1.1.4   root      938: 
                    939:        // とりあえず黒のみ
1.1.1.11  root      940:        color.Background        = Color(50, 50, 53);
                    941:        color.Text                      = UD_WHITE;
                    942:        color.Border            = UD_BLACK;
1.1.1.9   root      943:        color.LED[0]            = UD_RED;
                    944:        color.LED[1]            = UD_YELLOW_GREEN;
1.1.1.11  root      945:        color.Keytop[0][0]      = UD_BLACK;
1.1.1.9   root      946:        InitColorKeytop(1);
1.1.1.11  root      947: 
                    948:        SetBitmapBGColor(color.Background);
1.1.1.13! root      949:        Fill();
1.1.1.4   root      950: }
                    951: 
                    952: // デストラクタ
                    953: WXX68kSoftKeyPanel::~WXX68kSoftKeyPanel()
                    954: {
                    955: }
                    956: 
                    957: // LED を描画して刻印描画のための y offset を返す。
                    958: int
1.1.1.11  root      959: WXX68kSoftKeyPanel::DrawLED(const keydata_t& key)
1.1.1.4   root      960: {
1.1.1.13! root      961:        const std::vector<bool>& led = keyboard->GetLED();
1.1.1.11  root      962:        Color fg;
                    963:        Color bg;
1.1.1.4   root      964: 
                    965:        // 色を選択
                    966:        // idx  刻印  色
                    967:        // ----------------
                    968:        //  0   かな  赤
                    969:        //  1   ローマ       赤
                    970:        //  2   コード       赤
                    971:        //  3   CAPS    赤
                    972:        //  4   INS             赤
                    973:        //  5   ひら  緑
                    974:        //  6   全角  緑
                    975:        if (led[key.led]) {
                    976:                int n = (key.led < 5) ? 0 : 1;
1.1.1.11  root      977:                fg = color.LED[n];
                    978:                bg = color.LED[n];
1.1.1.4   root      979:        } else {
                    980:                // 消灯時は元のキートップの色で、枠は薄めにしたい
1.1.1.6   root      981:                // (枠の色は今の所全モデル共通なので ColorPalette に含めていない)
1.1.1.11  root      982:                fg = UD_GREY;
                    983:                bg = color.Keytop[key.coltype][0];
1.1.1.4   root      984:        }
                    985: 
                    986:        // LED は中央前方(画面でいうと下)
1.1.1.11  root      987:        Rect rect((key.x + 3) * unit, (key.y + key.h - 2) * unit,
                    988:                4 * unit, 2 * unit);
                    989:        bitmap.FillRect(bg, rect);
                    990:        bitmap.DrawRect(fg, rect);
1.1.1.4   root      991: 
                    992:        // そのため文字は少し上げる
                    993:        return -1;
                    994: }
                    995: 
                    996: #define LF (L0 + 2)            // ファンクションキーは少し低い(横長い)
                    997: #define HT (H * 2)             // 縦2倍角のキー
                    998: /*static*/ std::vector<keydata_t>
                    999: WXX68kSoftKeyPanel::keydata {
                   1000:        //                   +- 0以上なら LED 番号
                   1001:        //  X   Y   W  H  C  L  KeyCode                         通常  SHIFT
1.1.1.7   root     1002:        {   2, L0, 10, H, 0,-1, KC_BREAK,                       { "\x4\x5\x6\x7" } },
1.1.1.4   root     1003:        {  15, L0, 10, H, 0,-1, KC_COPY,                        { "COPY" } },
                   1004:        {  29, LF, 12, 6, 0,-1, KC_F1,                          { "F1" } },
                   1005:        {  41, LF, 12, 6, 0,-1, KC_F2,                          { "F2" } },
                   1006:        {  53, LF, 12, 6, 0,-1, KC_F3,                          { "F3" } },
                   1007:        {  65, LF, 12, 6, 0,-1, KC_F4,                          { "F4" } },
                   1008:        {  77, LF, 13, 6, 0,-1, KC_F5,                          { "F5" } },
                   1009:        {  94, LF, 13, 6, 0,-1, KC_F6,                          { "F6" } },
                   1010:        { 106, LF, 12, 6, 0,-1, KC_F7,                          { "F7" } },
                   1011:        { 118, LF, 12, 6, 0,-1, KC_F8,                          { "F8" } },
                   1012:        { 130, LF, 12, 6, 0,-1, KC_F9,                          { "F9" } },
                   1013:        { 142, LF, 13, 6, 0,-1, KC_F10,                         { "F10" } },
                   1014: 
                   1015:        {   2, L1, 10, H, 0,-1, KC_ESC,                         { "ESC" } },
                   1016:        {  12, L1, 10, H, 0,-1, KC_1,                           { "1",  "!" } },
                   1017:        {  22, L1, 10, H, 0,-1, KC_2,                           { "2",  "\"" } },
                   1018:        {  32, L1, 10, H, 0,-1, KC_3,                           { "3",  "#" } },
                   1019:        {  42, L1, 10, H, 0,-1, KC_4,                           { "4",  "$" } },
                   1020:        {  52, L1, 10, H, 0,-1, KC_5,                           { "5",  "%" } },
                   1021:        {  62, L1, 10, H, 0,-1, KC_6,                           { "6",  "&" } },
                   1022:        {  72, L1, 10, H, 0,-1, KC_7,                           { "7",  "'" } },
                   1023:        {  82, L1, 10, H, 0,-1, KC_8,                           { "8",  "(" } },
                   1024:        {  92, L1, 10, H, 0,-1, KC_9,                           { "9",  ")" } },
                   1025:        { 102, L1, 10, H, 0,-1, KC_0,                           { "0",  " " } },
                   1026:        { 112, L1, 10, H, 0,-1, KC_minus,                       { "-",  "=" } },
                   1027:        { 122, L1, 10, H, 0,-1, KC_circum,                      { "^",  "~" } },
                   1028:        { 132, L1, 10, H, 0,-1, KC_backslash,           { "\\", "|" } },
                   1029:        { 142, L1, 13, H, 0,-1, KC_BS,                          { "BS" } },
                   1030: 
                   1031:        {   2, L2, 16, H, 0,-1, KC_TAB,                         { "TAB" } },
                   1032:        {  18, L2, 10, H, 0,-1, KC_Q,                           { "q",  "Q" } },
                   1033:        {  28, L2, 10, H, 0,-1, KC_W,                           { "w",  "W" } },
                   1034:        {  38, L2, 10, H, 0,-1, KC_E,                           { "e",  "E" } },
                   1035:        {  48, L2, 10, H, 0,-1, KC_R,                           { "r",  "R" } },
                   1036:        {  58, L2, 10, H, 0,-1, KC_T,                           { "t",  "T" } },
                   1037:        {  68, L2, 10, H, 0,-1, KC_Y,                           { "y",  "Y" } },
                   1038:        {  78, L2, 10, H, 0,-1, KC_U,                           { "u",  "U" } },
                   1039:        {  88, L2, 10, H, 0,-1, KC_I,                           { "i",  "I" } },
                   1040:        {  98, L2, 10, H, 0,-1, KC_O,                           { "o",  "O" } },
                   1041:        { 108, L2, 10, H, 0,-1, KC_P,                           { "p",  "P" } },
                   1042:        { 118, L2, 10, H, 0,-1, KC_at,                          { "@",  "`" } },
                   1043:        { 128, L2, 10, H, 0,-1, KC_bracketleft,         { "[",  "{" } },
                   1044: 
                   1045:        {   2, L3, 19, H, 0,-1, KC_CTRL,                        { "CTRL" } },
                   1046:        {  21, L3, 10, H, 0,-1, KC_A,                           { "a",  "A" } },
                   1047:        {  31, L3, 10, H, 0,-1, KC_S,                           { "s",  "S" } },
                   1048:        {  41, L3, 10, H, 0,-1, KC_D,                           { "d",  "D" } },
                   1049:        {  51, L3, 10, H, 0,-1, KC_F,                           { "f",  "F" } },
                   1050:        {  61, L3, 10, H, 0,-1, KC_G,                           { "g",  "G" } },
                   1051:        {  71, L3, 10, H, 0,-1, KC_H,                           { "h",  "H" } },
                   1052:        {  81, L3, 10, H, 0,-1, KC_J,                           { "j",  "J" } },
                   1053:        {  91, L3, 10, H, 0,-1, KC_K,                           { "k",  "K" } },
                   1054:        { 101, L3, 10, H, 0,-1, KC_L,                           { "l",  "L" } },
                   1055:        { 111, L3, 10, H, 0,-1, KC_semicolon,           { ";",  "+" } },
                   1056:        { 121, L3, 10, H, 0,-1, KC_colon,                       { ":",  "*" } },
                   1057:        { 131, L3, 10, H, 0,-1, KC_bracketright,        { "]",  "}" } },
                   1058: 
1.1.1.6   root     1059:        {   2, L4, 24, H, 0,-1, KC_SHIFT,                       { "SHIFT" } },
1.1.1.4   root     1060:        {  26, L4, 10, H, 0,-1, KC_Z,                           { "z",  "Z" } },
                   1061:        {  36, L4, 10, H, 0,-1, KC_X,                           { "x",  "X" } },
                   1062:        {  46, L4, 10, H, 0,-1, KC_C,                           { "c",  "C" } },
                   1063:        {  56, L4, 10, H, 0,-1, KC_V,                           { "v",  "V" } },
                   1064:        {  66, L4, 10, H, 0,-1, KC_B,                           { "b",  "B" } },
                   1065:        {  76, L4, 10, H, 0,-1, KC_N,                           { "n",  "N" } },
                   1066:        {  86, L4, 10, H, 0,-1, KC_M,                           { "m",  "M" } },
                   1067:        {  96, L4, 10, H, 0,-1, KC_comma,                       { ",",  "<" } },
                   1068:        { 106, L4, 10, H, 0,-1, KC_period,                      { ".",  ">" } },
                   1069:        { 116, L4, 10, H, 0,-1, KC_slash,                       { "/",  "?" } },
                   1070:        { 126, L4, 10, H, 0,-1, KC_underscore,          { " ",  "_" } },
1.1.1.6   root     1071:        { 136, L4, 19, H, 0,-1, KC_SHIFT,                       { "SHIFT" } },
1.1.1.4   root     1072: 
                   1073:        {  21, L5, 10, H, 0, 5, KC_hira,                        { "ひら" } },
                   1074:        {  31, L5, 12, H, 0,-1, KC_XF1,                         { "XF1" } },
                   1075:        {  43, L5, 13, H, 0,-1, KC_XF2,                         { "XF2" } },
                   1076:        {  56, L5, 36, H, 0,-1, KC_space,                       { " " } },
                   1077:        {  92, L5, 12, H, 0,-1, KC_XF3,                         { "XF3" } },
                   1078:        { 104, L5, 12, H, 0,-1, KC_XF4,                         { "XF4" } },
                   1079:        { 116, L5, 12, H, 0,-1, KC_XF5,                         { "XF5" } },
                   1080:        { 128, L5, 10, H, 0, 6, KC_zenkaku,                     { "全角" } },
                   1081: 
                   1082:        // カーソルキー島
                   1083:        { 159, L0, 10, H, 0, 0, KC_kana,                        { "かな" } },
                   1084:        { 169, L0, 10, H, 0, 1, KC_romaji,                      { "ローマ" } },
                   1085:        { 179, L0, 10, H, 0, 2, KC_code,                        { "コード" } },
                   1086:        { 159, L1, 10, H, 0,-1, KC_HOME,                        { "HOME" } },
                   1087:        { 169, L1, 10, H, 0, 4, KC_INS,                         { "INS" } },
                   1088:        { 179, L1, 10, H, 0,-1, KC_DEL,                         { "DEL" } },
                   1089:        { 159, L2, 10, H, 0,-1, KC_ROLLUP,                      { "ROLL\n UP" } },
                   1090:        { 169, L2, 10, H, 0,-1, KC_ROLLDOWN,            { "ROLL\nDOWN" } },
                   1091:        { 179, L2, 10, H, 0,-1, KC_UNDO,                        { "UNDO" } },
                   1092:        { 169, L3, 10, H, 0,-1, KC_up,                          { "↑" } },
                   1093:        { 159, L3, 10, HT,0,-1, KC_left,                        { "←" } },
                   1094:        { 179, L3, 10, HT,0,-1, KC_right,                       { "→" } },
                   1095:        { 169, L4, 10, H, 0,-1, KC_down,                        { "↓" } },
                   1096:        { 159, L5, 15, H, 0,-1, KC_OPT1,                        { "OPT.1" } },
                   1097:        { 174, L5, 15, H, 0,-1, KC_OPT2,                        { "OPT.2" } },
                   1098: 
                   1099:        // テンキー島
                   1100:        { 193, L0, 10, H, 0, 3, KC_CAPS,                        { "CAPS" } },
                   1101:        { 203, L0, 10, H, 0,-1, KC_kigou,                       { "記号" } },
                   1102:        { 213, L0, 10, H, 0,-1, KC_touroku,                     { "登録" } },
                   1103:        { 223, L0, 10, H, 0,-1, KC_HELP,                        { "HELP" } },
                   1104:        { 193, L1, 10, H, 0,-1, KC_PAD_CLR,                     { "CLR" } },
                   1105:        { 203, L1, 10, H, 0,-1, KC_PAD_divide,          { "/" } },
                   1106:        { 213, L1, 10, H, 0,-1, KC_PAD_multiply,        { "*" } },
                   1107:        { 223, L1, 10, H, 0,-1, KC_PAD_minus,           { "-" } },
                   1108:        { 193, L2, 10, H, 0,-1, KC_PAD_7,                       { "7" } },
                   1109:        { 203, L2, 10, H, 0,-1, KC_PAD_8,                       { "8" } },
                   1110:        { 213, L2, 10, H, 0,-1, KC_PAD_9,                       { "9" } },
                   1111:        { 223, L2, 10, H, 0,-1, KC_PAD_plus,            { "+" } },
                   1112:        { 193, L3, 10, H, 0,-1, KC_PAD_4,                       { "4" } },
                   1113:        { 203, L3, 10, H, 0,-1, KC_PAD_5,                       { "5" } },
                   1114:        { 213, L3, 10, H, 0,-1, KC_PAD_6,                       { "6" } },
                   1115:        { 223, L3, 10, H, 0,-1, KC_PAD_equal,           { "=" } },
                   1116:        { 193, L4, 10, H, 0,-1, KC_PAD_1,                       { "1" } },
                   1117:        { 203, L4, 10, H, 0,-1, KC_PAD_2,                       { "2" } },
                   1118:        { 213, L4, 10, H, 0,-1, KC_PAD_3,                       { "3" } },
1.1.1.13! root     1119:        { 223, L4, 10, HT,0,-1, KC_PAD_enter,           { "\xb\xc\xe\xf" } },
1.1.1.4   root     1120:        { 193, L5, 10, H, 0,-1, KC_PAD_0,                       { "0" } },
                   1121:        { 203, L5, 10, H, 0,-1, KC_PAD_comma,           { "," } },
                   1122:        { 213, L5, 10, H, 0,-1, KC_PAD_decimal,         { "." } },
                   1123: 
                   1124:        // Enter だけ矩形でないので別処理するが
                   1125:        // この構造体には全部のキー情報が統一的に並んでいるほうがよかろう。
                   1126:        { -1, -1, -1, -1, 0,-1, KC_enter,                       { EnterMark } },
                   1127: };
                   1128: 
                   1129: //
1.1.1.6   root     1130: // ソフトウェアキーボード (ウィンドウ)
1.1.1.4   root     1131: //
                   1132: 
                   1133: // コンストラクタ
1.1.1.12  root     1134: WXSoftKeyWindow::WXSoftKeyWindow(wxWindow *parent, VMType vmtype)
1.1.1.7   root     1135:        : inherited(parent, wxID_ANY, _("Software Keyboard"))
1.1.1.4   root     1136: {
1.1.1.12  root     1137:        if (vmtype == VMType::X68030) {
1.1.1.6   root     1138:                panel = new WXX68kSoftKeyPanel(this);
                   1139:        } else {
                   1140:                panel = new WXLunaSoftKeyPanel(this);
                   1141:        }
1.1.1.4   root     1142: 
1.1.1.11  root     1143:        DoSize();
1.1.1.4   root     1144: }
                   1145: 
                   1146: // デストラクタ
1.1.1.6   root     1147: WXSoftKeyWindow::~WXSoftKeyWindow()
1.1.1.4   root     1148: {
                   1149: }

unix.superglobalmegacorp.com

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