|
 |
|
2013/3/18(Mon) 05:17:50|NO.53035
前回の質問で解決したのチェックを入れたのですが、その後問題点に気づいてしまいました
<objselによるフォーカス移動について>
http://hsp.tv/play/pforum.php?mode=all&num=52951
objselでフォーカスを移動する際、移動のトリガーをキーボード入力にすると
最初の入力が反映されないため、それを何とかしようとしたのが
下記スクリプトです
#uselib "User32"
#func SendInput "SendInput" int, var, int
#cfunc MapVirtualKey "MapVirtualKeyA" int,int
#func keybd_event "keybd_event" int, int, int
dim KEY,5
input a
b=""
mesbox b,200,16,0
onkey gosub *INPUTCHK
color 0,0,0 : boxf : color 255,255,255
repeat
await 30
loop
*INPUTCHK
//比較チェック部
keypush=0
repeat
keycnt=cnt+32
getkey keytest,keycnt
if keytest=1 : keypush=keycnt : break
if keycnt=126 : break
loop
Title ""+iparam+"/"+keypush
//比較チェック部
objsel -1
CHKOBJ=stat
if CHKOBJ!0{
objsel 0
KEY(0) = 1
KEY(1) |= MapVirtualKey(keypush,0)<<16
KEY(2) = 0x0008
SendInput 1,KEY,28
}
return
(キーコードのチェック部を入れた以外は同じスクリプトです)
当初はこれで一見目的は果たせたと思ったのですが、
動かしていると次のような症状が発生することに気づきました
・そもそも目的である最初の入力が反映されなくなる(すべてのキーだったり特定のキーのみだったり)
・フォーカスは移動してそのタイミングで文字も入力されるが、何を押しても(BSだろうがEnterだろうが)同じ文字しか出なくなる
・キーボードが暴走する
といったことです
なお症状はht.さんのサンプルでも発生しました
キーコードを調べてみると、iparamに押したキーとは違うコードが返ってきているようです。
それならばとチェック部で引き出したkeypushをirapamの代わりに使ってみたのですが、
キーボード暴走の影響か、getkeyも正常に動作しなくなってしまいました
(最初のうちは正常に動作していたのに、どのキーを押そうが特定の数字でbreakするようになってしまいました。
その数字に至る前のキーコードは拾えます)
原因はどういったことが考えられるでしょうか…?

| |
|
2013/3/18(Mon) 17:37:50|NO.53055
直接の原因かは解りませんが、KEY配列のサイズ(5*4=20)と
SendInputでの構造体サイズ指定(28)が異なる点が少し気になります。
また、onkey時のiparamは文字コードに当るようです。
(文字コード=キーコードなキーが多い為紛らわしいですが)
wparamがキーコードっぽいので、以下のようにしてみましたがどうでしょうか?
#uselib "User32"
#func SendInput "SendInput" int, var, int
#cfunc MapVirtualKey "MapVirtualKeyA" int,int
#func keybd_event "keybd_event" int, int, int
#cfunc GetMessageExtraInfo "GetMessageExtraInfo"
#uselib "kernel32.dll"
#func Sleep "Sleep" sptr
dim KEY,7 ;←サイズ合わせてみました
input a
b=""
mesbox b,200,16,0
onkey gosub *INPUTCHK
color 0,0,0 : boxf : color 255,255,255
repeat
await 30
loop
*INPUTCHK
if evt : return ;多重割り込み防止用
objsel -1 : CHKOBJ=stat
if CHKOBJ!0{
evt = 1
objsel 0
Sleep 3 ;念の為のフォーカス移行待ち
dim KEY,7 ;内容初期化の為
KEY(0) = 1 ;INPUT_KEYBOARD
KEY(1) = (MapVirtualKey(wparam,0)<<16)|wparam
KEY(2) = 0x0008 ;KEYEVENTF_SCANCODE|KEYEVENTF_KEYDOWN
KEY(4) = GetMessageExtraInfo() ;←不要かも
SendInput 1,KEY,28
evt = 0
}
return
|
|
2013/3/18(Mon) 18:00:16|NO.53057
0~9とa~zはきちんと反応する辺り、変だなと思って調べてみましたが文字コードとのミスですね。
既に書いてくださっているように、wparamに変更して頂ければ動作すると思われます。(keybd_eventでの動作を確認しました)
どうも失礼致しました。
|
|
2013/3/18(Mon) 19:19:23|NO.53059
774さん、ht.さん、ありがとうございます
ht.さんのサンプルは確かにwraramで正常に動きました
またht.さんスクリプトサンプルが暴走気味だったのは自分のスクリプトの暴走の影響を受けていたようです
SendInput使う場合の不具合動作は徐々にPC蓄積していき、(PC再起動で一時的にリセットされますが)そのうち手が付けられなくなるという状態なので
774さんのサンプルと、それを元に自分のものに組み込んだものとでしばらく動作検証してみようと思います。
|
|
2013/3/19(Tue) 17:02:28|NO.53069
途中経過ですが、全ての原因の判明と、
そのうちいくつかの解決ができました。
774さんのサンプルを元に検証した結果
・まったく違うキーが入力される
・キーボードが暴走する
この二点は関数関係が引き金となっており、特にキーコードの判定暴発は、param値(iparamとwparam)の指定ミスと
配列変数KEYの内容不適が原因のキーボードの暴走がそれぞれ別の引き金になっていたため
手間取りましたがそれぞれをサンプルを元に修正することで改善されました。
・最初の入力が反映され無いことがある
これについては解決はしていませんが、発生する条件を特定することが出来ました。
何度かチェックを行なっているうち、最初のキーが反映されない問題は実装しているプログラムでのみ発生することに気づきました。
下記は774さんのサンプルを、実装状態にちかくなるよう手を加えさせていただいたものです。
#uselib "User32"
#func SendInput "SendInput" int, var, int
#cfunc MapVirtualKey "MapVirtualKeyA" int,int
#func keybd_event "keybd_event" int, int, int
#cfunc GetMessageExtraInfo "GetMessageExtraInfo"
#uselib "kernel32.dll"
#func Sleep "Sleep" sptr
#define WM_ACTIVATE 0x0006 ;アクティブ変化
#define WM_LBUTTONDOWN 0x0201 ;マウス左押し下げ
screen 0 : hwnd0= hwnd ;第1スクリーン
dim KEY,7
input a
b=""
mesbox b,200,16,0
onkey gosub *INPUTCHK
oncmd gosub *LBUTTONDOWN , WM_LBUTTONDOWN
oncmd gosub *windowact,WM_ACTIVATE
screen 1 : hwnd1= hwnd ;第2スクリーン
c=""
mesbox c,200,16,0
onkey gosub *INPUTCHK
oncmd gosub *LBUTTONDOWN , WM_LBUTTONDOWN
oncmd gosub *windowact,WM_ACTIVATE
color 0,0,0 : boxf : color 255,255,255
repeat
await 30
winact=0
loop
*INPUTCHK;---------------------------------------------------
if evt : return ;多重割り込み防止用
//第1スクリーンへ移動し、オブジェクトフォーカスをチェック↓
gsel 0
objsel -1 : CHKOBJ=stat
//第1スクリーンへ移動し、オブジェクトフォーカスをチェック↑
if CHKOBJ!0{
evt = 1
objsel 0
Sleep 3 ;念の為のフォーカス移行待ち
dim KEY,7 ;内容初期化の為
KEY(0) = 1 ;INPUT_KEYBOARD
KEY(1) = (MapVirtualKey(wparam,0)<<16)|wparam
KEY(2) = 0x0008 ;KEYEVENTF_SCANCODE|KEYEVENTF_KEYDOWN
KEY(4) = GetMessageExtraInfo() ;←不要かも
SendInput 1,KEY,28
evt = 0
}
return
*LBUTTONDOWN;-------------------------------------------------
if moveact=0 {
gsel 1,1
gsel 0,1
}
return
*windowact;---------------------------------------------------
return ;サブルーチン呼び出しのみのチェック
objselで移動した際、最初のキー入力を反映したい、と言う目的は変わりませんが、
実装状態ではさらに2つのウィンドウにそれぞれ一個ずつのmesboxと,
片方だけに一つのinputboxがあり、双方のmesboxからそのinputboxへフォーカスを移して
キーを反映する、というものです。
そしてどちらか片方のウィンドウがクリックされてアクティブになった時、もう片方のウィンドウが
連動してアクティブになるよう oncmd gosub *LBUTTONDOWN , WM_LBUTTONDOWN にて仕込んでいるのですが、
実はこれだけだとオブジェクト類をクリックした時サブルーチンへ飛ばず、
クリックしたほうのウィンドウしかアクティブになりません。
そこでその対策として、 oncmd gosub *windowact,WM_ACTIVATE により片方がアクティブになった場合
もう片方を強制的にアクティブにするようにしていましたのですが、
(検証に必要なかったためreturnしか書いてありませんが実際には*LBUTTONDOWNと被らないようにした処理内容が入っています)
その対策部分「WM_ACTIVATE」を実装しただけで、ウィンドウをまたいだフォーカス移動の際
キー入力が反映されなくなってしまいます(同じウィンドウ内のフォーカス移動であれば反映されます)。
この部分さえ何とかなれば全て解決するのですが、アクティブ化の連動は実装時の必須項目なので
WM_ACTIVATEを使用しないわけにもいかず、代替策を模索中です…。

| |
|
2013/3/19(Tue) 17:31:53|NO.53070
ふと思いついたことを実行したら改善(?)されたような感じになりました
#uselib "User32"
#func SendInput "SendInput" int, var, int
#cfunc MapVirtualKey "MapVirtualKeyA" int,int
#func keybd_event "keybd_event" int, int, int
#cfunc GetMessageExtraInfo "GetMessageExtraInfo"
#uselib "kernel32.dll"
#func Sleep "Sleep" sptr
#define WM_ACTIVATE 0x0006 ;アクティブ変化
#define WM_LBUTTONDOWN 0x0201 ;マウス左押し下げ
screen 0 : hwnd0= hwnd ;第1スクリーン
dim KEY,7
input a
b=""
mesbox b,200,16,0
onkey gosub *INPUTCHK
oncmd gosub *LBUTTONDOWN , WM_LBUTTONDOWN
oncmd gosub *windowact,(WM_ACTIVATE)&(evt = 0)
screen 1 : hwnd1= hwnd ;第2スクリーン
c=""
mesbox c,200,16,0
onkey gosub *INPUTCHK
oncmd gosub *LBUTTONDOWN , WM_LBUTTONDOWN
oncmd gosub *windowact,(WM_ACTIVATE)&(evt = 0)
color 0,0,0 : boxf : color 255,255,255
repeat
await 30
winact=0
loop
*INPUTCHK;---------------------------------------------------
if evt : return ;多重割り込み防止用
//第1スクリーンへ移動し、オブジェクトフォーカスをチェック↓
gsel 0
objsel -1 : CHKOBJ=stat
//第1スクリーンへ移動し、オブジェクトフォーカスをチェック↑
if CHKOBJ!0{
evt = 1
objsel 0
Sleep 3 ;念の為のフォーカス移行待ち
dim KEY,7 ;内容初期化の為
KEY(0) = 1 ;INPUT_KEYBOARD
KEY(1) = (MapVirtualKey(wparam,0)<<16)|wparam
KEY(2) = 0x0008 ;KEYEVENTF_SCANCODE|KEYEVENTF_KEYDOWN
KEY(4) = GetMessageExtraInfo() ;←不要かも
SendInput 1,KEY,28
evt = 0
}
return
*LBUTTONDOWN;-------------------------------------------------
if moveact=0 {
gsel 1,1
gsel 0,1
}
return
*windowact;---------------------------------------------------
return ;サブルーチン呼び出しのみのチェック
何とかして
oncmd gosub *windowact,WM_ACTIVATE
これを一定条件かだけで呼部ことが出来れば解決するのではないかと思い、
ifで囲ってみたりしてたのですが、
頂いたサンプルに割り込み防止としてevt変数が使われているのがふと目に入り、
oncmd gosub *windowact,(WM_ACTIVATE)&(evt = 0)
としてみたら一応の解決に至りました、が…
oncmdのメッセージIDでこんなことやっちゃっても大丈夫なのでしょうか…?

| |
|
2013/3/19(Tue) 17:47:28|NO.53071
あ、 ちょっとものすごい勘違いしてたので上の(NO.53070)は無視してくださいorz
最後の問題点は全然解決してません
|
|
2013/3/19(Tue) 18:51:07|NO.53073
>774さん
oncmdの存在をすっかり忘れていました…!!
指摘ありがとうございます
フォーカス移動処理中は無効化する形で挟み込んだところ最後の問題も解決し、無事動作するようになりました
|
|
2013/3/19(Tue) 19:14:18|NO.53074
書いた後マズイ事に気付いて慌てて消したのですが
お役に立てたようで何よりです(w
もし参照なさる方が居た場合の為に書いておきますと、
*INPUTCHK;---------------------------------------------------
if evt : return ;多重割り込み防止用
oncmd 0 ;WM_ACTIVATE/WM_LBUTTONDOWNの無効化
/*~~ 一連の処理 ~~*/
oncmd 1 ;無効化の解除
return
なのですが、oncmd命令が各ウィンドウ毎に適用される為
コレだとgselで対象ウィンドウが切り替った際に不具合が起こりそうな気がしたのですが
oncmd 0 による無効化は全ウィンドウに適用される…のでしょうか^^;
|
|
2013/3/19(Tue) 19:39:39|NO.53075
>oncmd命令が各ウィンドウ毎に適用される為
>コレだとgselで対象ウィンドウが切り替った際に不具合が起こりそうな気がしたのですが
>oncmd 0 による無効化は全ウィンドウに適用される…のでしょうか^^;
そういえばどうなのでしょう
と思い実験してみました
#uselib "User32"
#func SendInput "SendInput" int, var, int
#cfunc MapVirtualKey "MapVirtualKeyA" int,int
#func keybd_event "keybd_event" int, int, int
#cfunc GetMessageExtraInfo "GetMessageExtraInfo"
#uselib "kernel32.dll"
#func Sleep "Sleep" sptr
#define WM_ACTIVATE 0x0006 ;アクティブ変化
#define WM_LBUTTONDOWN 0x0201 ;マウス左押し下げ
screen 0 : hwnd0= hwnd
Title "第1スクリーン"
dim KEY,7
input a
b=""
mesbox b,200,16,0
onkey gosub *INPUTCHK
oncmd gosub *LBUTTONDOWN , WM_LBUTTONDOWN
oncmd gosub *windowact,WM_ACTIVATE
screen 1 : hwnd1= hwnd
Title "第2スクリーン"
c=""
mesbox c,200,16,0
onkey gosub *INPUTCHK
oncmd gosub *LBUTTONDOWN , WM_LBUTTONDOWN
oncmd gosub *windowact,WM_ACTIVATE
color 0,0,0 : boxf : color 255,255,255
repeat
await 30
winact=0
loop
*INPUTCHK;---------------------------------------------------
if evt : return ;多重割り込み防止用
//第1スクリーンへ移動し、オブジェクトフォーカスをチェック↓
gsel 0
objsel -1 : CHKOBJ=stat
//第1スクリーンへ移動し、オブジェクトフォーカスをチェック↑
if CHKOBJ!0{
evt = 1
oncmd 0
objsel 0
Sleep 3 ;念の為のフォーカス移行待ち
dim KEY,7 ;内容初期化の為
KEY(0) = 1 ;INPUT_KEYBOARD
KEY(1) = (MapVirtualKey(wparam,0)<<16)|wparam
KEY(2) = 0x0008 ;KEYEVENTF_SCANCODE|KEYEVENTF_KEYDOWN
KEY(4) = GetMessageExtraInfo() ;←不要かも
SendInput 1,KEY,28
evt = 0
;oncmd 1
}
return
*LBUTTONDOWN;-------------------------------------------------
if moveact=0 {
gsel 1,1
gsel 0,1
}
return
*windowact;---------------------------------------------------
return ;サブルーチン呼び出しのみのチェック
内容は復帰のためのoncmd 1を「;」で殺してあります。
2つのスクリーンの描画エリアのどちらか片方クリックするとそれぞれのスクリーンへ割り当てた
oncmd gosub *LBUTTONDOWN , WM_LBUTTONDOWN によってもう片方のスクリーンも最前面へ飛び出してきます。
そしてキーボードの入力により「*INPUTCHK」へ飛んだ後は「gsel 0」で第1スクリーンに描画先が変わり、そこでoncmd命令が実行されています。
この状態で再びスクリーンの描画エリアをクリックすると、どちらもクリックしたスクリーンしか前面に出て来ません。
「oncmd0or1」の判定もスクリーンごとなら、第2スクリーンのoncmdは生きているはずなので、
どうやらoncmd命令でサブルーチンを作る時はウィンドウごとですが、「oncmd 0or1」で割り込みを切り替える際は
すべてのウィンドウの割り込みに適用されるようです。

| |
|