UWSCのSlctBoxにアクセスキーをつける

UWSC公式掲示板で、キーボード入力とマウスクリックの両立に悩まれている方がいたので、この解決策を考えてみた。
結果、アクセスキーがつけられることに気付きました〜。



とりあえず、案の提示

こんなの書いてみました。
最初のSlctBoxが出たら、「i,t,o」と順番に押してみてください。
「いと」と入れるのと等価操作で、「イトーヨーカ堂」が選ばれます!

Hashtbl データ
データ["最初"] = "あ(&a),い(&i),う(&u),え(&e),お(&o),か行(&k),さ行(&s),た行(&t),な行(&n),は行(&h),ま行(&m),や行(&y),ら行(&r),わ行(&w)"
データ["か行(&k)"] = "か(&a),き(&i),く(&u),け(&e),こ(&o)"
データ["さ行(&s)"] = "さ(&a),し(&i),す(&u),せ(&e),そ(&o)"
データ["た行(&t)"] = "た(&a),ち(&i),つ(&u),て(&e),と(&o)"
データ["な行(&n)"] = "な(&a),に(&i),ぬ(&u),ね(&e),の(&o)"
データ["は行(&h)"] = "は(&a),ひ(&i),ふ(&u),へ(&e),ほ(&o)"
データ["あ(&a)"] = "アイ会社(&i),青木工業(&o)"
データ["い(&i)"] = "いタ行(&t),五十鈴(&s),イトーヨーカ堂(&1)"	// 頻繁に使う選択肢は上位階層に特別なキーで登録しても
データ["こ(&o)"] = "講談社(&u)"	// 1つしか登録がなければ、SlctBoxを出さない実装も便利かもしれません
データ["いタ行(&t)"] = "板橋印刷(&a),イトーヨーカ堂(&o)"	// この調子で階層を増やし過ぎると、クリック派はかわいそう
データ["アイ会社(&i)"] = "広島納品(&h),埼玉納品(&s)"	// ここはアクセスキーをつけない方が良いかもしれません

Const BACK = "戻る"
Dim 答え="最初", 今回

While データ[答え, HASH_EXISTS]
  今回 = 答え
  Eval("答え := SlctBox(SLCT_BTN OR SLCT_STR, 0,<#DBL>どれか選んでね<#DBL>,<#DBL>" + replace(データ[答え], "," , "<#DBL>,<#DBL>") + "<#DBL>,<#DBL>" + BACK + "<#DBL>)")
  If 答え = BACK Or 答え = -1 Then 答え = GetBackKey(データ, 今回)
Wend

// アクセスキーはどうやって切りましょうか、、、
// Eval魔法が使われているので、正規表現魔法を唱えましょう
Dim regex = CreateOleObj("VBScript.RegExp") 
regex.Pattern = "\(&\w\)"	// $をつけるべきかもしれません
答え = regex.Replace(答え, "")

MsgBox(答え)



Function GetBackKey(data[], key)
  // 連想配列の中身を順番に見て、選択肢を含むものを探します
  //  例えば、引数key="こ(&o)"の場合、「か行(&k)」を返します
  Dim i, m = Length(data) - 1
  Result = -1
  For i = 0 To m
    // こっちは正規表現の魔法は使わない方法で書きましょうか
    //  正規表現を使えば、Forの中身を減らせますね
    Dim l = Length(key)
    Dim val = data[i, HASH_VAL], vl = Length(val)
    Dim index = Pos(key, val)
    Ifb index > 1 Then
      // 前の文字はカンマで、後ろはカンマかないかですよね
      If Copy(val, index - 1, 1) = "," And (vl = l + index - 1 Or Copy(val, l + index, 1) = ",") Then Break
    ElseIf index = 1 Then
      // この場合は、後ろがカンマか、単体選択ですね
      If l = vl Or Copy(val, l + 1, 1) = "," Then Break
    EndIf
  Next
  If i <= m Then Result = data[i, HASH_KEY]
Fend


どうでしょうか?
以下は、ここに至る思考です。

普通のWindowsアプリケーションなら、と考えてみる

当然、アクセスキーでしょう。
マウスクリックと等価にアプリケーションの操作ができます。

UWSCでアクセスキー

そういえば、PopupMenuはアクセスキーが出ますね。

  Dim all[] = "日本", "{東京", "{世田谷", "千代田", "江戸川}", "名古屋", "大阪}", "アメリカ", "{ニューヨーク", "ロサンゼルス", "サンフランシスコ}"
  Dim sel = PopupMenu(all)

  Ifb sel >= 0 Then
    Msgbox(all[sel])
  Else
    Msgbox("キャンセル")
  EndIf

これ、選択項目がアルファベットだとそれなりなアクセスキーですが、この場合は「Z」とか。
選びにくいです。
指定、できないかしらん?
と思って、試しに書いてみたところ、、、

  Dim all[] = "日本(&j)", "{東京(&t)", "{世田谷(&s)", "千代田(&t)", "江戸川(&e)}", "名古屋(&n)", "大阪(&o)}", "アメリカ(&u)", "{ニューヨーク(&n)", "ロサンゼルス(&l)", "サンフランシスコ(&s)}"
  Dim sel = PopupMenu(all)

  Ifb sel >= 0 Then
    Msgbox(all[sel])
  Else
    Msgbox("キャンセル")
  EndIf

期待動作した!
最初のPopupで「j」を押すと、「日本」の階層に入れます!
(「&」の次の文字がアクセスキーの指定です)

ではSlctBox

悩まれていた方は、「いと」と入れるとその候補が出る、というI/Fを考えられている。
ならばその入力をアクセスキーに振れば良いではありませんか!

Hashtbl データ
データ["最初"] = "あ(&a),い(&i),う(&u),え(&e),お(&o),か行(&k),さ行(&s),た行(&t),な行(&n),は行(&h),ま行(&m),や行(&y),ら行(&r),わ行(&w)"
データ["か行(&k)"] = "か(&a),き(&i),く(&u),け(&e),こ(&o)"
データ["さ行(&s)"] = "さ(&a),し(&i),す(&u),せ(&e),そ(&o)"
データ["た行(&t)"] = "た(&a),ち(&i),つ(&u),て(&e),と(&o)"
データ["な行(&n)"] = "な(&a),に(&i),ぬ(&u),ね(&e),の(&o)"
データ["は行(&h)"] = "は(&a),ひ(&i),ふ(&u),へ(&e),ほ(&o)"
データ["あ(&a)"] = "アイ会社(&i),青木工業(&o)"
データ["い(&i)"] = "いタ行(&t),五十鈴(&s),イトーヨーカ堂(&1)"
データ["こ(&o)"] = "講談社(&u)"
データ["いタ行(&t)"] = "板橋印刷(&a),イトーヨーカ堂(&o)"
データ["アイ会社(&i)"] = "広島納品(&h),埼玉納品(&s)"

Dim 答え="最初"

While データ[答え, HASH_EXISTS]
  Eval("答え := SlctBox(SLCT_BTN OR SLCT_STR, 0,<#DBL>どれか選んでね<#DBL>,<#DBL>" + replace(データ[答え], "," , "<#DBL>,<#DBL>") + "<#DBL>)")
Wend

MsgBox(答え)


いや良いと思いませんか?
でも、アクセスキーの指定である「(&a)」とかがかっこ悪いですね。
なら、「答え」を書き変えましょう。

  • 後ろ4文字を切る
  • 「(」〜「)」を切る

とかも考えましたが、結局、面倒なので正規表現としました。
さらにおまけで、「戻る」を追加したのが、最初のものです。


UWSC、便利過ぎます。
アクセスキーも受け付けてくれるし(Windows標準とも言いますが)
VBScriptのオブジェクトも呼べてしまうし。
Powershellまで守備範囲とは。


また、この解決を考えることで、良い頭の体操をさせてもらいました。
ありがとうございました!