[質問]外部アプリケーションにアクセスする場合の SendKeys の動作について
-
[質問]外部アプリケーションにアクセスする場合の SendKeys の動作について
Mery: 3.8.2 (x64, Portable)
Onigmo: 6.2.0
C/Migemo: 1.3
Tidy: 5.8.0
Hunspell: 1.7.1
uchardet: 0.0.8
QuickJS: 0.11.0
アウトライン: 3.2.5 (Outline.dll)
OS: Windows 11 (Version 24H2, OS Build 26100.7922, 64-bit Edition)素晴らしいテキストエディタを提供くださりありがとうございます。
さて,以下のようなマクロから外部アプリケーションにアクセスする場合,外部アプリにショートカットコマンドを送る際,2度目の SendKeys が機能しません。 sleep() の時間調整を長くとっても修正されません。
前後の SendKeys コマンドを入れ替えても,やはり1度目の SendKeys しか機能しません。QuickJS の仕様なのでしょうか?
EmEditor のマクロでは意図したとおりに機能します。どうか対処方法を教えてください。var ws = new ActiveXObject("WScript.Shell");
ws.AppActivate("外部アプリ名");
ws.SendKeys("^%c"); //1度目
sleep(600);ws.SendKeys("^a^c"); //2度目
sleep(400);| Mbaz | 返信 -
ご愛用いただきありがとうございます。
いただいたコードをこちらの環境で試してみましたが、特に問題なく 2 度目の
SendKeysも動作しました。外部アプリが何を指しているのか分からなかったため、検証では Windows の メモ帳 (notepad.exe) を指定して確認しています。
Ctrl + Alt + Cはメモ帳では特別な意味を持たないため、1 回目のキー送信は単純にCに置き換えて試しました。var ws = new ActiveXObject("WScript.Shell"); ws.AppActivate("無題 - メモ帳"); ws.SendKeys("c"); //1度目 sleep(600); ws.SendKeys("^a^c"); //2度目 sleep(400);この状態で実行すると、メモ帳に
Cが入力されたあと、Ctrl + A→Ctrl + Cが順に実行され、全選択してコピーされることを確認できました。> QuickJS の仕様なのでしょうか?
QuickJS は、スクリプトの先頭に
#language = "quickjs"と書いた場合にのみ使用されます。そのため、今回のコードに関しては QuickJS は関係ないと思われます。
考えられる可能性としては、外部アプリ側の仕様で、キー入力を同期的に処理していない、あるいは処理が完了するまで次のキー入力を受け付けない、といった動作になっているケースです。
なお、EmEditor さんでは動作するとのことですが、EmEditor さんのマクロは既定で非同期実行だったと記憶しています。
よろしければ、Mery のマクロの先頭に次の 1 行を追加してお試しいただけますでしょうか。
#async = trueこれを指定すると、マクロが別スレッドで実行されるようになりますので、挙動が変わる可能性があります。
もし差し支えなければ、外部アプリ名も教えていただけると、こちらでももう少し詳しく確認できるかと思います。
| Kuro | 返信 -
早速の返信ありがとうございます。
Mery のマクロの先頭に次の 1 行を追加しましたら,期待通りに 2 度目の SendKeys も動作しました。#async = true
随分と長い時間この問題と格闘していたので,とても感激です。ありがとうございました。
QuickJS 使用に関する情報にも感謝します。
益々のご健勝願っています。ありがとうございました。| Mbaz | 返信 -
ご返信ありがとうございます。
> 随分と長い時間この問題と格闘していたので,とても感激です。ありがとうございました。
そんなに長く格闘されていたのですね…!無事に解決できたようで、こちらもほっとしました。
アプリによっては、
SendKeysを非同期でしか受け付けないものもあるようですね。なかなか奥が深いです。ちなみに、
#async = trueはマクロを非同期で実行するための指令です。その副作用として、実行速度が少し遅くなったり、マクロ実行中でも Mery の一部を操作できてしまう場合があります。ある程度は操作を制限するようにしていますが、仕様上、非同期マクロの実行中に Mery を操作すると、意図しない挙動が発生する可能性があります。
そのあたりはサポート対象外となりますので、ご理解のうえお試しいただければと思います。
| Kuro | 返信 -
返信ありがとうございます。
追伸です。当方の環境においても「メモ帳」で SendKeys のテストをしてみました。
メモ帳で文字列をクリップボードにコピー後,Mery に戻ってペーストするというものです。ws.AppActivate("メモ帳");
ws.SendKeys("^a");
sleep(400);ws.SendKeys("^c{End}");
sleep(200);ws.AppActivate(" - Mery");
sleep(200);
var sData = clipboardData.getData("Text");
document.activate();
document.selection.Text = sData;当方の環境では,やはり「非同期実行」でなければ,2度目の SendKeys が実行できません。
どうもこの現象の原因は外部アプリではないように思います。
僭越ですが,ご参考まで。| Mbaz | 返信 -
ご返信ありがとうございます。
こちらの環境でも試してみました。たしかに、いただいたコードのままだとうまく動かないですね。
ただ、2 番目の
ws.SendKeys("^c{End}");までは問題なく実行できました。ws.AppActivate("メモ帳"); ws.SendKeys("^a"); sleep(400); ws.SendKeys("^c{End}"); sleep(200);この部分までは、メモ帳の内容をすべて選択してコピーするところまで、きちんと動作しています。
一方で、その後に
ws.AppActivate(" - Mery");以降のコードを追加すると、挙動が変わってしまうようです。あくまで推測ですが、同期実行の場合は Mery 側のマクロ処理が優先されるため、このような動きになっている可能性がありそうです。
流れをざっくり整理すると、次のようなイメージです。
SendKeys("^c")は「今すぐコピーする」というより、「あとで Ctrl+C を押す」という入力を予約するような動き (これは Windows の仕様によるものです)- 同期マクロ実行中は Mery が処理を続けているため、Windows 側がその「予約された入力」を処理するタイミングがない
- その状態で
ws.AppActivate(" - Mery");を実行する - そのあとで
SendKeysの入力が処理される
その結果、コピーが想定したタイミングで実行されない可能性がありそうです。
ちなみに、EmEditor さんで
#async = "off"(同期実行、Mery とは方言が若干違いますが…) を指定して同様の検証を行ってみたところ、やはり正常には動作しませんでした。このことから、特定のエディター固有の問題というよりは、Windows のメッセージ処理や入力キューの仕組みに起因する挙動ではないかと考えています。
もし見当違いでしたら、ご指摘いただければ助かります。
| Kuro | 返信 -
Kuro 様,詳細な検証をいただき恐れ入ります。お時間を取らせて申し訳ありません。
ご指摘通りの現象『同期実行ではMery 側のマクロ処理が,Windows 側の「予約された入力」より優先される』が再現されます。外部アプリとのデータ受け渡しがクリップボードしかなかったため,この問題にぶつかりしました。今後いただいた情報をぜひ生かしていきたいと思います。
本当にありがとうございました。| Mbaz | 返信