HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2017
0124
Sadoユーザー定義のホットキーの実装/すべてのキーを取得する19解決


Sado

リンク

2017/1/24(Tue) 01:28:19|NO.78022

サドと申します。
ツールを作っていましてユーザー定義のホットキーを設定したいのですが、
適当な方法が分かりませんでしたので質問させていただきました。

現在僕が考えている方法は、
オプション画面のキー割り当て受付中に「すべてのキーを取得する関数」で取得した値を、
同じく「すべてのキーを取得する関数」と所得した値を常時比較して判定するといったものです。
自分で言っておきながらなんですが、とても気持ちの悪いプログラムだと思います。(重そう)

ここで問題になる「すべてのキーを取得する関数」ですが、onkeyだと漏れがありますし、
これは使えそうと思ったGetKeyboardState関数も、僕の知識不足のために使い方が分からず。
(常時押されたままのキー(変動する)が複数あり、調べてみるとF17とか何とか……???)
※参考にしたキーコード一覧
http://kts.sakaiweb.com/virtualkeycodes.html
僕が使用しているキーボードは、
Acer aspire(ノート型)付属のものです。

/* 元のサンプル以下より http://hsp.tv/play/pforum.php?mode=pastwch&num=36534#36554 */ #uselib "user32" #func GetKeyboardState "GetKeyboardState" var title "キーの状態を取得" sdim keys,256 repeat redraw 0 color 255,255,255 boxf 0,0,640,480 color 0,0,0 GetKeyboardState keys sumkeystate=0; for y,0,16 for x,0,16 if peek(keys,y*16+x) & 0x80 { pos x*30,y*20 mes str(y*16+x) } sumkeystate+=peek(keys,y*16+x); next next if gettime(7)<980: pos 0,460: mes "SUM="+sumkeystate; redraw 1 await 10 loop
yahooブログでホットキー(?)のhspモジュールを公開している方を見かけましたが、
動作がいまいちで納得の行くような結果を得られませんでした。
他に正規のホットキーの実装方法があるのではないかとも考えました。
(自力では見つけることができませんでしたが)

hspでホットキーのような動作を実現する方法について、ご教示くださいませんか?



この記事に返信する


syam

リンク

2017/1/24(Tue) 02:04:46|NO.78024

「現在僕が考えている方法」とは、何を実現する方法でしょう?
単にホットキー的なものを実現したい、というだけであれば getkey 命令で十分できるはずです。
それとは違う話なのであれば、方法の話よりもまずやりたいことを具体的に書いていただいたほうがよさそうです。



Sado

リンク

2017/1/24(Tue) 02:21:10|NO.78026

>syamさん
説明不足でした、すみません。
僕のやりたいことを補足しつつまとめると以下のようになります。

ツールのユーザーに任意のホットキー(単数でも複数でも)を設定させたい。
次に入力されたキーを常時判定したい。(これが「getkey 命令で十分できる」ものなんですね)



syam

リンク

2017/1/24(Tue) 02:39:05|NO.78028

設定をするときは onkey 命令でキー入力を検出して、
ホットキーとしての動作をするときは 設定した文字コードを getkey命令で監視する
...で できると思います。
(getkey 命令のヘルプに onkey 命令で文字コードを得るサンプルが載っています)

が、先の投稿には「onkeyだと漏れがある」とありますね...もしそこがまだ解決しないなら、どういう漏れが問題なのか教えてください。



Sado

リンク

2017/1/24(Tue) 03:02:15|NO.78031

押し漏らしは完全に僕の勘違いでした、ごめんなさい。
しかし、onkeyだと同時押しに対応できません。
(個人的にルーチンの中で使いにくいという苦手意識もある)

僕の理想としているのは、一般的なホットキー割当のできるソフトウェアの、
「割り当て」等のボタンを押した後に始まる入力受付中の同時押しです。
上手く説明できず申し訳ありませんが、長押し中は
「...」「Ctrl+...」「Ctrl+F1+...」と表示されていくような動作です。

手元にあるソフトウェアで言うと、
MassiGraの「キー設定」やMediBang Paint Proの「ショートカット設定」
が該当の動作をします。



syam

リンク

2017/1/24(Tue) 03:27:45|NO.78032

onkey でジャンプした先で getkey で ctrl を検出してみてはどうでしょう?


title "キー入力してください(^^)v" onkey *inkey stop *inkey if lparam>>30:stop if iparam==0:stop getkey shift, 16 getkey ctrl, 17 getkey alt, 18 s = "" if shift == 1 : s += "[shift]" if ctrl == 1 : s += "[ctrl]" if alt == 1 : s += "[alt]" s += "[" + iparam + "]" mes s stop



Sado

リンク

2017/1/24(Tue) 15:28:40|NO.78038

onkeyでも工夫すれば基本的なホットキーの組み合わせは実装できるのは分かりますが、
文字入力(単キー)に使うのが正しい使い方ではないですか。
逆に同時押し(今回のようなホットキーを判定する場合)には向かないと思うのですが、
どうなんでしょう。

くどいようですが、やりたい事をもう一度明言しておきます。

>一般的なホットキー割当のできるソフトウェアの、
>「割り当て」等のボタンを押した後に始まる入力受付中の同時押しです。
>長押し中は「Ctrl+...」「Ctrl+F1+...」と表示されていくような動作です。
>
>手元にあるソフトウェアで言うと、
>MassiGraの「キー設定」やMediBang Paint Proの「ショートカット設定」
>が該当の動作をします。

一般的なホットキー(ショートカットキー)の実装方法を知りたいのです。
・設定時/通常時における、任意のキー1〜3つの同時押し判定
・ファンクションやshift,ctrl,alt,BS,space,Insert,Delete等も使える
・可能ならば右左Ctrl/Shiftを区別する

やはりgetkeyboardstateを使うのが一番なのでしょうか……
キー未押下時の変動する謎数値をどう扱えば良いものか。



syam

リンク

2017/1/24(Tue) 15:40:23|NO.78039

onkey は、「新しくなにかのキーが押されたことを知る」ものなので、「どのキーが押されているかを調べ始めるタイミング」には適しています。
常に全キーの状態をポーリングする必要はないですね。

それで設定ができたら、設定したキーだけをgetkeyでポーリングしたらよいでしょう。



InoueSoftware

リンク

2017/1/24(Tue) 17:42:53|NO.78040

GetKeyboardState の使い方。
GetKeyboardState の引数にBYTE型で256配列ある変数へのポインタを指定します。
しかし、HSPでは4byteの変数しか作れないので、64要素ある変数を作成して256byte分を作ります。

キーの状態を取得するには、peek関数を使って、第二引数にキーコードを指定します。

#include "user32.as"
dim KeyState,64//キーの状態を入れる配列(一つの要素あたり4byte。256byteの場合は64要素必要) repeat GetKeyboardState varptr(KeyState)//キーの状態取得 //例 : スペースキーを取得。peekの第二引数にキーコードを指定 if (peek(KeyState,32) & 0x80){ title "押した" }else{ title "押してない" } await 1 loop



Sado

リンク

2017/1/24(Tue) 17:45:34|NO.78041

自分なりに考えてみましたが、やはりonkeyは扱いが難しいです。
英数字から入力を始めればonkeyによってgetkeyのラベルに飛べますが、
その逆、Shift等から入力を始めたと考えると頭が痛くなります。

そして今気づきましたが、onkeyは「文字コード」で返してくるわけじゃないですか。
「仮想キーコード」が欲しいんです。
(どうりでVK_1とVK_NUMPAD1が区別されない訳だ……)


ホットキーの任意割り当て/判定 こんなにややこしいことを考える必要があるのでしょうか……
(疲れてきてしまった)



Sado

リンク

2017/1/24(Tue) 18:02:49|NO.78042

>InoueSoftwareさん
回答ありがとうございます。
見つけたサンプルがsdimで256byte確保していたので、そういうものかと思っていました。
MSDNを参照してみると、たしかに「256 バイトの配列へのポインタ」とありますね。


しかし、これではgetkey(GetkeyState関数?)と同じ使い方しかできません……
任意のホットキーの同時押しは、どう検出すれば良いのでしょうか?

検出後の値は保持して、syamさんの提案通りgetkeyを一〜三重に掛けて
ホットキー判定をしようと考えています。



MillkeySoftware

リンク

2017/1/24(Tue) 19:05:14|NO.78046

難しく考える必要ないんじゃ・・・

#uselib "user32.dll" #cfunc MapVirtualKey "MapVirtualKeyA" int,int #func GetKeyNameText "GetKeyNameTextA" int,var,int #define VK_ESCAPE 0x1B sdim VKReturn,12 sdim KeyInpData,256 onkey *KeyDown stop *KeyDown if wparam == VK_ESCAPE : memset KeyInpData,0,256 : mes "入力をリセットしました" : stop if (peek(KeyInpData,wparam) = 0){ poke KeyInpData,wparam,1 Delta = "" repeat 256 if (peek(KeyInpData,cnt) == 1){ // Delta += strf("%d (%02X) ",cnt,cnt) //登録文字列として取り出す lParamValue = MapVirtualKey(cnt, 0) << 16; GetKeyNameText lParamValue, VKReturn, 12; Delta += VKReturn+" + " } loop poke Delta,strlen(Delta) - 2,0 mes ""+Delta } stop

onkey = WM_KEYDOWN なのですから、WM_KEYDOWN の対になる WM_KEYUP も処理すればいいだけだと思うよ。
ちなみに、上記スクリプトは簡潔にしか処理していません。



tds12

リンク

2017/1/24(Tue) 20:36:40|NO.78049

user32.dllにRegisterHotKeyという関数があります。
過去ログにもありますがどうでしょうか?



MillkeySoftware

リンク

2017/1/24(Tue) 22:06:50|NO.78051

RegisterHotKey 及び CreateAcceleratorTable は知っているのかわからないけど、たぶんホットキーのキー情報決定の方が出来てないんじゃないかなー。

まぁ、途中の書き込みから察するに、CTRL を押したら画面に CTRL として表示される。
追加で、SHIFT も押したら CTRL + SHIFT が表示される。
さらに F も押したら、CTRL + SHIFT + F が表示される。

という表示の変化を行いたいんじゃないかと。
キー情報が決定したら、RegisterHotKey 及び CreateAcceleratorTable での実装は可能なのでそれは、決定後の話という。



Sado

リンク

2017/1/25(Wed) 16:08:58|NO.78058

>syamさん
失礼しました!また僕の勘違いでした。
onkeyのwparamでちゃんと全部のキーが取得できました。
「oncmd ,WM_KEYDOWN」とイコールだったのか……

>MillkeySoftwareさん
サンプルありがとうございます。
GetKeyNameText()関数は便利ですね。
なるほど、
WM_KEYDOWNで取得できたキーがどれか一つでもWM_KEYUPで取得できたときに、
任意ホットキー確定……とすれば、あの動作が実現できるんですか。
ようやくパーツが揃った気がします。
任意ホットキー入力の終了は、
WM_KEYUP時ルーチンで、サンプル中のDeltaのようなものとGetKeyboardState()の内容を
比較して判定する。
(……256*Dlta中の保持キー数(1~3個)ループするのか)
もう少しスマートな方法がありそうです。

>tds12さん,coldtimeさん
RegisterHotkeyは知りませんでした!
これですね、ホットキーの正体。危うくgetkeyで実装してしまうところでした。
ペイントツール等のホットキーを奪ってしまう/逆にこちら側で登録できない等の
他のアプリとの干渉を避けるにはキーボードアクセラレータを利用すると。
こちらはメッセージの送受信(?)のくだりが、僕にとって完全に未知の領域なので、
すぐに理解するのは厳しいです。

http://wiki.hsp.moe/%E3%82%A2%E3%82%AF%E3%82%BB%E3%83%A9%E3%83%AC%E3%83%BC%E3%82%BF.html より、サッパリな部分を引用 *msgloop GetMessage varptr(MSG), 0, 0, 0 ret = stat if ret = 0: gosub *DestroyAccel: end if ret = -1: gosub *DestroyAccel: end TranslateAccelerator hwnd, haccel, varptr(MSG) if stat=0{ TranslateMessage varptr(MSG) DispatchMessage varptr(MSG) ; プロシージャに送ってます } // メッセージを処理しているからawait要らず? ;await goto *msgloop
ここで、「GetMessage varptr(MSG), 0, 0, 0」は、何をGetしているのでしょうか……
「TranslateAccelerator hwnd, haccel, varptr(MSG)」はMSDNでは全ての引数が入力とありますが、
何をGetして何をTranslateAcceleratorへ送信しているのでしょう。
更に、MSDNには処理が終了するまでタスクを返してくれないとありますが、
どのくらいの時間持っていかれるのかと不安を感じます。

ほとんど理解できていませんが、正常にメッセージを処理することができれば、
アクセラレータからWM_COMMAND(0x0111)が送られ、
wparamに、アクセラレータテーブルの3つ目に指定した値が返るという認識で合っていますか?

switch (wparam & $FFFF)で& $FFFFとしている理由も、
Altキーをどこで判定しているのかも分かりません。



InoueSoftware

リンク

2017/1/25(Wed) 17:41:01|NO.78059

>ここで、「GetMessage varptr(MSG), 0, 0, 0」は、何をGetしているのでしょうか……
GetMessageはウィンドウメッセージを確実に受け取るためのものです。
GetMessage の第一引数にはMSG 構造体と言う構造体を指定します。
取得できるものは、
・HWND メッセージを受信したウィンドウハンドル
・message ウィンドウメッセージID(WM_~など)
・wParam/lParam メッセージの付加情報
・time メッセージが受信された時間
・pt(x,y) メッセージが受信された時のマウスポインタの位置
です。

>どのくらいの時間持っていかれるのかと不安を感じます。
メッセージキューにメッセージが置かれるまで処理を待機させます。

>switch (wparam & $FFFF)で& $FFFFとしている理由も、...
LOWORDのマクロを展開したものです。
これで、アクセラレーターの IDなどを識別します。



Sado

リンク

2017/1/25(Wed) 18:27:42|NO.78060

GetMessage関数、リファレンスを読み返してもさっぱりです……
MSG構造体を調べてみても6つだというのはわかりましたが、dim ,7とするのはなぜでしょうか。

第一引数に自ハンドルではなくNULLを指定する理由についても、
「呼び出し側スレッドに所属する任意のウィンドウへ送信されたメッセージ」と説明されても
「自ハンドルを指定するのとは違うのか?」とピンと来ません。

LOWORDのマクロについては、ごめんなさい、本当に何も分かりませんでした。
今は、メッセージ中から下位ワード(?)と呼ばれるようなアクセラレーターIDを取り出す
ためのおまじない程度に覚えておきます。



疑問点を書き出してみましたが、このメッセージの問題はHSPとは関係ありませんね。
この件で何か問題が起きた場合は、Cのコミュニティに相談するようにします。
(C言語のことは全く知りませんが)

ここまでで、ホットキー/アクセラレータによるキーの登録は分かりました。
No.78058の「任意ホットキー入力の終了」のヒントを得られたらトピックを解決とします。



tds12

リンク

2017/1/26(Thu) 00:14:42|NO.78063

>No.78058の「任意ホットキー入力の終了」のヒントを得られたらトピックを解決とします。
UnregisterHotKey

>このメッセージの問題はHSPとは関係ありませんね。
HSP標準のメッセージ処理はアクセラレータを認識しないために
必要になった処理です。
waitでしているようなことです。



Sado

リンク

2017/1/26(Thu) 00:27:55|NO.78064

>tds12さん
分かりにくい表現ですみません。
「任意ホットキー入力の終了」は、

(No.78058より一部) WM_KEYDOWNで取得できたキーがどれか一つでもWM_KEYUPで取得できたときに、 任意ホットキー確定……とすれば、あの動作が実現できるんですか。 ようやくパーツが揃った気がします。 任意ホットキー入力の終了は、 WM_KEYUP時ルーチンで、サンプル中のDeltaのようなものとGetKeyboardState()の内容を 比較して判定する。 (……256*Dlta中の保持キー数(1~3個)ループするのか) もう少しスマートな方法がありそうです。
の中のキーワードです。
もう少しまともなプログラムを組めるようになりたいとの思いで……


P.S.
ウェブサイトを先程更新しました!
最近訪問したことのある方はスーパーリロードをお願いします。(cssも修正/追加したので)



Sado

リンク

2017/1/26(Thu) 22:13:18|NO.78080

任意キー設定のくだりは微妙なものになってしまいましたが、
「ホットキー」そのものは実装できるようになりましたので解決とします。
ありがとうございました。



ONION software Copyright 1997-2023(c) All rights reserved.