かな入力の薙刀式を練習するために、JavaScriptでタイピングソフトを作ってみました。
薙刀式とは
かな入力の配列の一つです。よく出る表現を楽に打つことを目的とした配列です。
薙刀式を考案された大岡さんのページはこちらです。
http://oookaworks.seesaa.net/article/456099128.html
かな入力配列はほかにもありますので、良かったら調べてみてください。(タイピング速度最速は新下駄配列だといわれています。)
作成したタイピングソフト
QWERTY配列のままタイピングすると薙刀式のかなが入力されるようにしています。実際に配列を変えるのは設定変更が面倒くさく、ハードルになると思うので、このソフトで体験してもらいたいと考えて作りました。実際に良いと思い、慣れてきたら実際に配列変更していただくとよいと思います。
このサイトのタイピングゲームの基本機能部分を参考にさせていただきました。ありがとうございます。
https://www.pazru.net/js/key/3.html
コードはこちらです。
薙刀式の押下されたキーの組み合わせで入力される文字を返す関数
function reaction(keyStatus){ //入力された文字の判定 
    if(keyStatus[32]){//シフト同時押し
        if(keyStatus[70]){//シフトと左手濁音キー(f)押し
            if(keyStatus[81]) return "ヴ";//q
            if(keyStatus[87]) return "み";//w
            if(keyStatus[69]) return "り";//e
            if(keyStatus[82]) return "め";//r
            if(keyStatus[85]) return "ざ";//u
            if(keyStatus[73]) return "よ";//i
            if(keyStatus[79]) return "ゆ";//o
            if(keyStatus[80]) return "え";//p
            if(keyStatus[65]) return "せ";//a
            if(keyStatus[83]) return "ね";//s
            if(keyStatus[68]) return "に";//d
            if(keyStatus[71]) return "ち";//g
            if(keyStatus[72]) return "わ";//h
            if(keyStatus[74]) return "の";//j
            if(keyStatus[75]) return "も";//k
            if(keyStatus[76]) return "づ";//l
            if(keyStatus[186]) return "や";//;
            if(keyStatus[90]) return "ほ";//z
            if(keyStatus[88]) return "ひ";//x
            if(keyStatus[67]) return "を";//c
            if(keyStatus[86]) return "、";//v
            if(keyStatus[66]) return "ぬ";//b
            if(keyStatus[78]) return "お";//n
            if(keyStatus[77]) return "。";//m
            if(keyStatus[188]) return "む";//,
            if(keyStatus[190]) return "ぶ";//.
            if(keyStatus[191]) return "れ";///
            return "ま";//f
        }
        if(keyStatus[74]){//シフトと右手濁音キー(j)押し
            if(keyStatus[81]) return "ヴ";//q
            if(keyStatus[87]) return "み";//w
            if(keyStatus[69]) {
                if(keyStatus[79]) return "でゅ";
                return "り";//e
            }
            if(keyStatus[82]) {
                if(keyStatus[186]) return "じゃ";
                if(keyStatus[79]) return "じゅ";
                if(keyStatus[80]) return "じぇ";//p
                if(keyStatus[73]) return "じょ";
                return "め";//r
            }
            if(keyStatus[85]) return "さ";//u
            if(keyStatus[73]) return "よ";//i
            if(keyStatus[79]) return "ゆ";//o
            if(keyStatus[80]) return "え";//p
            if(keyStatus[65]) return "ぜ";//a
            if(keyStatus[83]) {
                if(keyStatus[186]) return "ぎゃ";
                if(keyStatus[79]) return "ぎゅ";
                if(keyStatus[73]) return "ぎょ";
                return "ね";//s
            }
            if(keyStatus[68]) return "に";//d
            if(keyStatus[70]) return "ま";//f
            if(keyStatus[71]) {
                if(keyStatus[186]) return "ぢゃ";
                if(keyStatus[79]) return "ぢゅ";
                if(keyStatus[73]) return "ぢょ";
                if(keyStatus[80]) return "ぢぇ";//p
                return "ぢ";//g
            }
            if(keyStatus[72]) return "わ";//h 
            if(keyStatus[75]) return "も";//k
            if(keyStatus[76]) return "つ";//l
            if(keyStatus[186]) return "や";//;
            if(keyStatus[90]) return "ぼ";//z
            if(keyStatus[88]) {
                if(keyStatus[186]) return "びゃ";
                if(keyStatus[79]) return "びゅ";
                if(keyStatus[73]) return "びょ";
                return "び";//x
            }
            if(keyStatus[67]) return "を";//c
            if(keyStatus[86]) return "、";//v
            if(keyStatus[66]) return "ぬ";//b
            if(keyStatus[78]) return "お";//n
            if(keyStatus[77]) return "。";//m
            if(keyStatus[188]) return "む";//,
            if(keyStatus[190]) return "ふ";//.
            if(keyStatus[191]) return "れ";///
            return "の";//j
        }
        if(keyStatus[86]){//シフトと左手半濁音キー(v)押し//右手は存在しない
            if(keyStatus[81]) return "ヴ";//q
            if(keyStatus[87]) return "み";//w
            if(keyStatus[69]) return "り";//e
            if(keyStatus[82]) return "め";//r
            if(keyStatus[85]) return "さ";//u
            if(keyStatus[73]) return "ょ";//i
            if(keyStatus[79]) return "ゅ";//o
            if(keyStatus[80]) return "ぇ";//p
            if(keyStatus[65]) return "せ";//a
            if(keyStatus[83]) return "ね";//s
            if(keyStatus[68]) return "に";//d
            if(keyStatus[70]) return "ま";//f
            if(keyStatus[71]) return "ち";//g
            if(keyStatus[72]) return "ゎ";//h
            if(keyStatus[74]) return "ぁ";//j
            if(keyStatus[75]) return "ぃ";//k
            if(keyStatus[76]) return "ぅ";//l
            if(keyStatus[186]) return "ゃ";//;
            if(keyStatus[90]) return "ほ";//z
            if(keyStatus[88]) return "ひ";//x
            if(keyStatus[67]) return "を";//c 
            if(keyStatus[66]) return "ぬ";//b
            if(keyStatus[78]) return "ぉ ";//n
            if(keyStatus[77]) return "。";//m
            if(keyStatus[188]) return "む";//,
            if(keyStatus[190]) return "ぷ";//.
            if(keyStatus[191]) return "れ";///
            return "、";//v
        }
        //清音
        if(keyStatus[81]) {
            if(keyStatus[80]) return "ヴぇ";
            if(keyStatus[78]) return "ヴぉ";
            if(keyStatus[79]) return "ヴゅ";
            return "ヴ";//q
        }
        if(keyStatus[87]) {
            if(keyStatus[186]) return "みゃ";
            if(keyStatus[79]) return "みゅ";
            if(keyStatus[73]) return "みょ";
            return "み";//w
        }
        if(keyStatus[69]) {
            if(keyStatus[186]) return "りゃ";
            if(keyStatus[79]) return "りゅ";
            if(keyStatus[73]) return "りょ";
            return "り";//e
        }
        if(keyStatus[82]) {
            if(keyStatus[186]) return "しゃ";
            if(keyStatus[80]) return "しぇ";
            if(keyStatus[79]) return "しゅ";
            if(keyStatus[73]) return "しょ";
            return "め";//r
        }
        if(keyStatus[85]) return "さ";//u       
        if(keyStatus[83]) {
            if(keyStatus[186]) return "きゃ";
            if(keyStatus[79]) return "きゅ";
            if(keyStatus[73]) return "きょ";
            return "ね";//s
        }
        if(keyStatus[65]) return "せ";//a
        if(keyStatus[68]) {
            if(keyStatus[186]) return "にゃ";
            if(keyStatus[79]) return "にゅ";
            if(keyStatus[73]) return "にょ";
            return "に";//d
        }
        if(keyStatus[70]) return "ま";//f
        if(keyStatus[71]) {
            if(keyStatus[186]) return "ちゃ";
            if(keyStatus[79]) return "ちゅ";
            if(keyStatus[80]) return "ちぇ"
            if(keyStatus[73]) return "ちょ";
            return "ち";//g
        }
        if(keyStatus[72]) return "わ";//h
        if(keyStatus[74]) {
            if(keyStatus[76]) return "つぁ";
            if(keyStatus[75]) return "つぃ";
            return "の";//j
        }
        if(keyStatus[75]) return "も";//k
        if(keyStatus[76]) {
            if(keyStatus[80]) return "つぇ";
            if(keyStatus[78]) return "つぉ";
            return "つ";//l
        }
        
        if(keyStatus[90]) return "ほ";//z
        if(keyStatus[88]) {
            if(keyStatus[186]) return "ひゃ";
            if(keyStatus[79]) return "ひゅ";
            if(keyStatus[73]) return "ひょ";
            return "ひ";//x
        }
        if(keyStatus[80]) return "え";//p
        if(keyStatus[67]) return "を";//c
        if(keyStatus[86]) return "、";//v
        if(keyStatus[66]) return "ぬ";//b
        if(keyStatus[78]) return "お";//n
        if(keyStatus[77]) return "。";//m
        if(keyStatus[188]) return "む";//,
        if(keyStatus[190]) {
            if(keyStatus[74]) return "ふぁ";
            if(keyStatus[75]) return "ふぃ";
            if(keyStatus[80]) return "ふぇ";
            if(keyStatus[78]) return "ふぉ";
            if(keyStatus[79]) return "ふゅ";
            return "ふ";//.
        }
        if(keyStatus[191]) return "れ";///
        if(keyStatus[186]) return "や";//;
        if(keyStatus[79]) return "ゆ";//o
        if(keyStatus[73]) return "よ";//i
    }
    else{//シフトなし
        if(keyStatus[74]){//右手濁音キー(j)押し
            if(keyStatus[81]) return "ヴ";//q
            if(keyStatus[87]) return "ば";//w
            if(keyStatus[69]) {
                if(keyStatus[75]) return "でぃ";
                return "で";//e
            }
            if(keyStatus[82]) return "じ";//r
            if(keyStatus[73]) return "る";//i
            if(keyStatus[79]) return "す";//o
            if(keyStatus[80]) return "へ";//p
            if(keyStatus[65]) return "ろ";//a
            if(keyStatus[83]) return "ぎ";//s
            if(keyStatus[68]) {
                if(keyStatus[76]) return "どぅ";
                return "ど";//d
            }
            if(keyStatus[70]) return "が";//f
            if(keyStatus[71]) return "っ";//g
            if(keyStatus[72]) return "く";//h
            if(keyStatus[75]) return "い";//k
            if(keyStatus[76]) return "う";//l
            if(keyStatus[186]) return "ー";//;
            if(keyStatus[90]) return "ぼ";//z
            if(keyStatus[88]) return "び";//x
            if(keyStatus[67]) return "げ";//c
            if(keyStatus[86]) return "ご";//v
            if(keyStatus[66]) return "ぞ";//b
            if(keyStatus[78]) return "た";//n
            if(keyStatus[77]) return "な";//m
            if(keyStatus[188]) return "ん";//,
            if(keyStatus[190]) return "ら";//.
            if(keyStatus[191]) return "れ";///
            return "あ";//j
        }
        if(keyStatus[70]){//左手濁音キー(f)押し
            if(keyStatus[81]) return "ヴ";//q
            if(keyStatus[87]) return "は";//w
            if(keyStatus[69]) return "て";//e
            if(keyStatus[82]) return "し";//r
            if(keyStatus[73]) return "る";//i
            if(keyStatus[79]) return "ず";//o
            if(keyStatus[80]) return "べ";//p
            if(keyStatus[65]) return "ろ";//a
            if(keyStatus[83]) return "き";//s
            if(keyStatus[68]) return "と";//d
            if(keyStatus[71]) return "っ";//g
            if(keyStatus[72]) return "ぐ";//h
            if(keyStatus[74]) return "あ";//j
            if(keyStatus[75]) return "い";//k
            if(keyStatus[76]) return "う";//l
            if(keyStatus[186]) return "ー";//;
            if(keyStatus[90]) return "ほ";//z
            if(keyStatus[88]) return "ひ";//x
            if(keyStatus[67]) return "け";//c
            if(keyStatus[86]) return "こ";//v
            if(keyStatus[66]) return "そ";//b
            if(keyStatus[78]) return "だ";//n
            if(keyStatus[77]) return "な";//m
            if(keyStatus[188]) return "ん";//,
            if(keyStatus[190]) return "ら";//.
            if(keyStatus[191]) return "れ";///
            return "か";//f
        }
        if(keyStatus[86]){//左手半濁音キー(v)押し
            if(keyStatus[81]) return "ヴ";//q
            if(keyStatus[87]) return "は";//w
            if(keyStatus[69]) return "て";//e
            if(keyStatus[82]) return "し";//r
            if(keyStatus[73]) return "る";//i
            if(keyStatus[79]) return "す";//o
            if(keyStatus[80]) return "ぺ";//p
            if(keyStatus[65]) return "ろ";//a
            if(keyStatus[83]) return "き";//s
            if(keyStatus[68]) return "と";//d
            if(keyStatus[70]) return "か";//f
            if(keyStatus[71]) return "っ";//g
            if(keyStatus[72]) return "く";//h
            if(keyStatus[74]) return "あ";//j
            if(keyStatus[75]) return "い";//k
            if(keyStatus[76]) return "う";//l
            if(keyStatus[186]) return "ー";//;
            if(keyStatus[90]) return "ほ";//z
            if(keyStatus[88]) return "ひ";//x
            if(keyStatus[67]) return "け";//c
            if(keyStatus[66]) return "そ";//b
            if(keyStatus[78]) return "た";//n
            if(keyStatus[77]) return "な";//m
            if(keyStatus[188]) return "ん";//,
            if(keyStatus[190]) return "ら";//.
            if(keyStatus[191]) return "れ";///
            return "こ";//v
        }
        if(keyStatus[77]){//右手半濁音キー(m)押し
            if(keyStatus[81]) return "ヴ";//q
            if(keyStatus[87]) return "ぱ";//w
            if(keyStatus[69]) return "て";//e
            if(keyStatus[82]) return "し";//r
            if(keyStatus[73]) return "る";//i
            if(keyStatus[79]) return "す";//o
            if(keyStatus[80]) return "へ";//p
            if(keyStatus[65]) return "ろ";//a
            if(keyStatus[83]) return "き";//s
            if(keyStatus[68]) return "と";//d
            if(keyStatus[70]) return "か";//f
            if(keyStatus[71]) return "っ";//g
            if(keyStatus[72]) return "く";//h
            if(keyStatus[74]) return "あ";//j
            if(keyStatus[75]) return "い";//k
            if(keyStatus[76]) return "う";//l
            if(keyStatus[186]) return "ー";//;
            if(keyStatus[90]) return "ぽ";//z
            if(keyStatus[88]) return "ぴ";//x
            if(keyStatus[67]) return "け";//c
            if(keyStatus[86]) return "こ";//v
            if(keyStatus[66]) return "そ";//b
            if(keyStatus[78]) return "た";//n
            if(keyStatus[188]) return "ん";//,
            if(keyStatus[190]) return "ら";//.
            if(keyStatus[191]) return "れ";///
            return "な";//m
        }
        if(keyStatus[81]) {
            if(keyStatus[74]) return "ヴぁ";
            if(keyStatus[75]) return "ヴぃ"
            return "ヴ";//q
        }
        if(keyStatus[87]) return "は";//w
        if(keyStatus[69]) {
            if(keyStatus[75]) return "てぃ";
            return "て";//e
        }
        if(keyStatus[82]) return "し";//r
        if(keyStatus[73]) return "る";//i
        if(keyStatus[79]) return "す";//o
        if(keyStatus[80]) return "へ";//p
        if(keyStatus[65]) return "ろ";//a
        if(keyStatus[83]) return "き";//s
        if(keyStatus[68]) {
            if(keyStatus[76]) return "とぅ"
            return "と";//d
        }
        if(keyStatus[70]) return "か";//f
        if(keyStatus[71]) return "っ";//g
        if(keyStatus[72]) return "く";//h
        if(keyStatus[74]) return "あ";//j
        if(keyStatus[75]) return "い";//k
        if(keyStatus[76]) return "う";//l
        if(keyStatus[186]) return "ー";//;
        if(keyStatus[90]) return "ほ";//z
        if(keyStatus[88]) return "ひ";//x
        if(keyStatus[67]) return "け";//c
        if(keyStatus[86]) return "こ";//v
        if(keyStatus[66]) return "そ";//b
        if(keyStatus[78]) return "た";//n
        if(keyStatus[77]) return "な";//m
        if(keyStatus[188]) return "ん";//,
        if(keyStatus[190]) return "ら";//.
        if(keyStatus[191]) return "れ";///
    }
}
タイピングゲームの基本機能
document.onkeydown = keydownFunction;  //キー押下時に関数keydownFunction()を呼び出す
document.onkeyup = releaseFunction;
var originSentence = "";
var count=0;             //何問目か格納
var typStart,typEnd;   //開始時と終了時の時刻を格納
var SentenceLength=0;
var typeLetter ="";
var keyStatus = new Array();
var SentenceArray = new Array("")//問題文をべた書きしているため省略
//タイピングゲームの問題をセットする関数
function SetSentence()
{
    //問題文とカウント数をクリアする
    count=0;
    SentenceLength=Sentence.length;
    originSentence=Sentence;
    //問題枠に表示する
    document.getElementById("waku").style.backgroundColor="aliceblue";
    document.getElementById("waku").innerHTML = originSentence;
}
function keydownFunction(e)
{
    //入力されたキーのキーコードを取得
    if(e.keyCode>30){   
        keyStatus[e.keyCode]=true;
        typeLetter = reaction(keyStatus);
    }
    return false;
}
function releaseFunction(e){
    if(typeLetter==Sentence.charAt(0)||typeLetter==Sentence.slice(0,2)){
        if (count==0)
        { 
            typStart = new Date();
        }
        count++;
        document.getElementById("waku").style.backgroundColor="aliceblue";
        if (count < SentenceLength)
        {
            //問題文の頭の一文字を切り取る
            if(typeLetter==Sentence.slice(0,2)){
                sliceSentence=Sentence.substring(0,2);
                Sentence = Sentence.slice(2);
                count++;
            }
            else{
                sliceSentence=Sentence.substring(0,1);
                Sentence = Sentence.slice(1);
            }
            
            if(Sentence.charAt(0)==" "){
                Sentence = Sentence.slice(1);
                count++;
            }
            //問題枠に表示する
            document.getElementById("pushKey").innerText="入力された文字:" + typeLetter;
            document.getElementById("waku").style.backgroundColor="palegreen";
            var aliceblue=function(){document.getElementById("waku").style.backgroundColor="aliceblue"}
            setTimeout(aliceblue,200);
            document.getElementById("waku").innerHTML = Sentence;
        }    
        else
        {
        //全文字入力していたら、終了時間を記録する
        typEnd = new Date();
        
        //終了時間-開始時間で掛かったミリ秒を取得する
        var elapsed = typEnd - typStart;
        
        //1000で割って「切捨て」、秒数を取得
        var sec = Math.floor( elapsed/1000 );
        
        //1000で割った「余り(%で取得できる)」でミリ秒を取得
        var msec = elapsed % 1000;
        
        //問題終了を告げる文字列を作成
        var fin="GAME終了 時間:"+sec+"秒"+msec+"\n";
        
        //問題枠にゲーム終了を表示
        document.getElementById("waku").innerHTML = fin;
        }
    }
    else{
        if(typeLetter!=undefined){
            document.getElementById("pushKey").innerText="入力された文字:" + typeLetter;  
        }
        else document.getElementById("pushKey").innerText="入力された文字:"
    } 
    keyStatus.map(function(value, index, array){
        return array[index]=false;
    });
    return false;
}
htmlのbody部分
実装としては、入力されたキーコード部分がtrueになる配列を用意して(同時押しが存在するため)、条件分岐して薙刀式で入力した場合の文字列として返し、問題文と比較して合っていたら問題文を削るというものです。薙刀式の条件分岐を作成するのに時間がかかりました。
正解すると画面が黄緑色になるよう実装しています。理由は、不正解時に赤くなるようにしていた場合同時押しにすると無条件で赤くなってしまう問題に直面したからです。配列で比較しているために問題が起こっているのでしょうか。自分では解決に至りませんでしたので正解で黄緑色になるようにしました。
終わりに
キーコードを取得して、実際に入力されるものを変えるという処理を応用すれば他の配列もタイピングソフトを作成することは可能なので、作ってみようと思います。
