Russian Keyboard support

プーシキン見出語電子コンコーダンス Конкорданс к тексту А. С. Пушкина に,Russian Pseudo-Keyboard ロシア語疑似キーボード機能を追加した。画面のキリル文字をクリックすると,当該文字が単語式テキスト入力エリアに挿入される。OS のインプットメソッドにロシア語を追加していないユーザでも,サービスが利用できるようになる。下図の通り,клавиатура ボタンをクリックすると,疑似キーボード・ウィンドウがオープンする。

20120512-rkb.png
ロシア語疑似キーボード

この疑似キーボード自体は,コンコーダンスの旧版で拵えたもので,今回は Wt C++ Web Toolkit でいかに実現するかが課題だった。取りかかってみると,リンク付加オブジェクトで簡単にできてしまった。今日はそのメモ。

Wt::WPushButton でボタン・オブジェクトを追加し,setLink(link) 関数によって,ロシア語キーボード画面を開く JavaScript リンクをボタンに付与した。それだけのことだった。

// ロシア語疑似キーボードボタン
WPushButton* button2 = new WPushButton(L"клавиатура", con);
WString kblink(WString::tr("kblink"));
button2->setLink(kblink.toUTF8());
// ロシア語疑似キーボードボタンで入力エリアにフォーカス
button2->clicked().connect(expEdit, &WFormWidget::setFocus);

3, 4 行目で,外部 XML ファイルの message ID kblink に記述した JavaScript リンク(実際は javascript:window.open('kbd.html', null, 'width=420, height=210, menubar=no, toolbar=no, scrollbars=yes');void(0);)を引っ張って来て,ボタンにリンクを付加している。kbd.html とそこから呼ばれる JavaScriptrkbd.js とによって疑似キーボード機能を実現している。

キリル文字のボタンをキーボード配列でレイアウトしておき,そのボタンが押されたらそれに紐づいているキリル文字で,ID に対応したテキスト入力エリアの value を書き換える。仕掛けはこんなチンケなものである。だけど,同じような課題を持つ方もいるかも知れないので,これらのコードを以下に掲げておく。スタイルシートは割愛。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
  <!-- -*- coding: utf-8; -*- -->
  <!-- $Id: insomnia.txt 222 2014-03-27 11:23:12Z isao $ -->
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="description" content="Russian Keyboard for Concordance." />
    <link rel="shortcut icon" href="favicon.ico" />
    <link rel="stylesheet" type="text/css" href="kbd.css" />
    <script type="text/javascript" language="JavaScript" 
        src="rkbd.js"></script>
    <title>Russian keyboard</title>
  </head>
 
  <body>
    <center>
      <table class="key">
        <tr>
          <td width="20" align="center">
            <input type="button" id="k00" value="я" 
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k01" value="ш" 
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k02" value="е" 
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k03" value="р"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k04" value="т"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k05" value="ы"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k06" value="у"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k07" value="и"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k08" value="о"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k09" value="п"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k0a" value="ю"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k0b" value="щ"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k0c" value="э"
                   onClick="cin(this.value)" />
          </td>
        </tr>
      </table>
    </center>
 
    <center>
      <table class="key">
        <tr>
          <td width="10" align="center">
             
          </td>
          <td width="20" align="center">
            <input type="button" id="k10" value="а"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k11" value="с"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k12" value="д"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k13" value="ф"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k14" value="г"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k15" value="х"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k16" value="й"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k17" value="к"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k18" value="л"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k19" value="ч"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k1a" value="ж"
                   onClick="cin(this.value)" />
          </td>
          <td width="30" align="center">
             
          </td>
        </tr>
      </table>
    </center>
 
    <center>
      <table class="key">
        <tr>
          <td width="20" align="center">
             
          </td>
          <td width="20" align="center">
            <input type="button" id="k20" value="з"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k21" value="ь"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k22" value="ц"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k23" value="в"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k24" value="б"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k25" value="н"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k26" value="м"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k27" value="" 
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k28" value="ъ"
                   onClick="cin(this.value)" />
          </td>
          <td width="20" align="center">
            <input type="button" id="k29" value="ё"
                   onClick="cin(this.value)" />
          </td>
          <td width="40" align="center">
             
          </td>
        </tr>
      </table>
    </center>
 
    <center>
      <table class="opt">
        <tr>
          <td width="350" align="center" valign="middle">
            <span class="lbl">Регистр: </span> 
            <input type="radio" name="case" checked="checked" 
                   onClick="cin('+')" />
            <span class="lbl">Верхний</span>
            <input type="radio" name="case" onClick="cin('-')" />
            <span class="lbl">Нижний</span>
          </td>
        </tr>
        <tr>
          <td width="350" align="center" valign="middle">
            <span class="lbl">Переменить раскладку к</span>
            <input type="button" id="kt" value="Йцукен" 
                   onClick="chkb()" />
          </td>
        </tr>
        <tr>
          <td width="350" align="center" valign="middle">
            <input type="button" id="kc" value="Стирание" 
                   onClick="cin('*')" /> 
            <input type="button" value="Закрывать" 
                   onClick="window.close()" />
          </td>
        </tr>
      </table>
      <div class="copy">
        Copyright © 2001-2012, yasuda, All Rights Reserved.
      </div>
    </center>
  </body>
</html>
// -*- coding: utf-8; mode: javascript; -*- 
// Russian Pseudo-Keyboard
// Copyright(c) 2001-2012, isao yasuda, All Rights Reserved.
 
var RKstr   = opener.document.getElementById("Exps").value;
var RKc     = "";
var RKupper = false; // 大文字小文字選択
var RKtype  = true;  // キーボード配列
 
function cin(simvol) {  //set character
    RKstr = opener.document.getElementById("Exps").value;
    RKc = simvol;
    // 渡される文字によって文字挿入,オプションを切り分ける
    switch(RKc) {
    case "+":       //upper case 大文字挿入に切り替え
        RKupper = true;
        return;
    case "-":       //lower case 小文字挿入に切り替え
        RKupper = false;
        return;
    case "*":       //clear バッファのクリア
        RKstr = "";
        opener.document.getElementById("Exps").value = RKstr;
        return;
    default:        //russian symbol
        if (RKupper == true) {
            RKc = RKc.toUpperCase();
        }
        // キリル文字を入力エリアに挿入
        RKstr = RKstr + RKc;
        opener.document.getElementById("Exps").value = RKstr;
        return;
    }
}
 
function chkb() {  // キーボード配列の切り替え
    if (RKtype == false) { // qwerty (phometic)
        document.getElementById("k00").value="я";
        document.getElementById("k01").value="ш";
        document.getElementById("k02").value="е";
        document.getElementById("k03").value="р";
        document.getElementById("k04").value="т";
        document.getElementById("k05").value="ы";
        document.getElementById("k06").value="у";
        document.getElementById("k07").value="и";
        document.getElementById("k08").value="о";
        document.getElementById("k09").value="п";
        document.getElementById("k0a").value="ю";
        document.getElementById("k0b").value="щ";
        document.getElementById("k0c").value="э";
        document.getElementById("k10").value="а";
        document.getElementById("k11").value="с";
        document.getElementById("k12").value="д";
        document.getElementById("k13").value="ф";
        document.getElementById("k14").value="г";
        document.getElementById("k15").value="х";
        document.getElementById("k16").value="й";
        document.getElementById("k17").value="к";
        document.getElementById("k18").value="л";
        document.getElementById("k19").value="ч";
        document.getElementById("k1a").value="ж";
        document.getElementById("k20").value="з";
        document.getElementById("k21").value="ь";
        document.getElementById("k22").value="ц";
        document.getElementById("k23").value="в";
        document.getElementById("k24").value="б";
        document.getElementById("k25").value="н";
        document.getElementById("k26").value="м";
        document.getElementById("k27").value="";
        document.getElementById("k28").value="ъ";
        document.getElementById("k29").value="ё";
        RKtype = true;
        document.getElementById("kt").value = "Йцукен";
    } else {          // jcuken (ロシア標準配列)
        document.getElementById("k00").value="й";
        document.getElementById("k01").value="ц";
        document.getElementById("k02").value="у";
        document.getElementById("k03").value="к";
        document.getElementById("k04").value="е";
        document.getElementById("k05").value="н";
        document.getElementById("k06").value="г";
        document.getElementById("k07").value="ш";
        document.getElementById("k08").value="щ";
        document.getElementById("k09").value="з";
        document.getElementById("k0a").value="х";
        document.getElementById("k0b").value="ъ";
        document.getElementById("k0c").value="";
        document.getElementById("k10").value="ф";
        document.getElementById("k11").value="ы";
        document.getElementById("k12").value="в";
        document.getElementById("k13").value="а";
        document.getElementById("k14").value="п";
        document.getElementById("k15").value="р";
        document.getElementById("k16").value="о";
        document.getElementById("k17").value="л";
        document.getElementById("k18").value="д";
        document.getElementById("k19").value="ж";
        document.getElementById("k1a").value="э";
        document.getElementById("k20").value="я";
        document.getElementById("k21").value="ч";
        document.getElementById("k22").value="с";
        document.getElementById("k23").value="м";
        document.getElementById("k24").value="и";
        document.getElementById("k25").value="т";
        document.getElementById("k26").value="ь";
        document.getElementById("k27").value="б";
        document.getElementById("k28").value="ю";
        document.getElementById("k29").value="ё";
        RKtype = false;
        document.getElementById("kt").value = "Яшерты";
    }
    return;
}

私は Mac OS X を愛用しているので,Windows ユーザのことをあんまり考えないで Web アプリを書いている。Safari が試験ブラウザである。このコンコーダンス・プログラムを Windows 7 Ultimate IE-9 で見てみたら,機能的には問題なくても,レイアウトがボロボロ。ちょっと手直しした。IE-6, 7, 8 やその他わんさかあるブラウザではどうなのか皆目不明で,恥ずかしいページを出している可能性大である。ま,切りがないので,対処はそのうち考えるということで。