マクロにおけるキーボード入力の判定について

  1. Kuro 様、皆様、大変お世話になっております。

    Windows10 Pro, ver 22H2, 64bit
    Mery 3.6.5, 64bit

    を使わせて頂いております。現在、長文テキストを読むときに、自動スクロールができたら良いなと思い、マクロを書いてみました。

    ---------------------------------------
    // 自動的にスクロールするマクロ
    // 2024-01-24, Ver 0.0

    var lastLine = 10000;
    //出来れば、開いているファイルの最大行数、もしくはカーソル位置がEOFかどうかを判定したい
    //途中の行で、安全にマクロを終了できれば、この稚拙なコードでも実用上問題無い

    var speed = 3500;
    //スクロールのスピード、数値が大きくなるほどゆっくりスクロールする。単位 ミリ秒

    for (let i = 1; i < lastLine; i++) {
    document.selection.LineDown(false, 1);
    Sleep(speed);

    //キーボード入力に応じて for ループを抜け、処理を終了したい
    // Quit(); が使えるか?
    }
    ---------------------------------------------

    ところがこのコードでは、いったん起動させると、Mery を強制終了しか止める術がありません。

    キーボード入力に応じて処理を安全に終了させる方法を教えて下さい。

     |  Takeshi  |  返信
  2. 皆様、一応自己解決しました。

    GetKeyState.exe(キー状態取得実行ファイル) のページを参考に、Shift キーを長押しすると、動作を止められるようになりました。下記が修正後のコードです。とりあえず、これで使ってみようと思います。

    // 自動的にスクロールするマクロ
    // 2024-01-24, Ver 0.1

    var lastLine = 10000;
    //出来れば、開いているファイルの最大行数、もしくはカーソル位置がEOFかどうかを判定したい
    //実用上は、この稚拙なコードでも我慢できる

    var speed = 3500;
    //スクロールのスピード、数値が大きくなるほどゆっくりスクロールする。単位 ミリ秒

    for (let i = 1; i < lastLine; i++) {
    document.selection.LineDown(false, 1);
    Sleep(speed);

    //SHIFTキーが押されたら for ループを抜け、処理を終了
    var wshShell = new ActiveXObject("WScript.Shell");

    // カレントディレクトリをマクロディレクトリに変更
    wshShell.CurrentDirectory = editor.FullName.match(/^.*\\/)[0] + 'Macros';

    // SHIFTキー状態を取得
    var shift = wshShell.Run("GetKeyState.exe shift", 0, true);

    if(shift != -1){
    if(shift == 1){
    Quit();
    }
    }

    }

     |  Takeshi  |  返信
  3. Mery をご愛用いただきありがとうございます。

    おぉ、面白いマクロですね!

    Mery のマクロは Windows のスクリプト エンジンに丸投げなので、マクロを実行したら終了するまで、Mery 側から途中で割込み処理は難しいと思いますが、こんな方法があったとは…。勉強になりました。

    自動スクロールについては、マウスのホイール クリックでそれっぽいことができますが、実際にやってみると、スクロール速度が速すぎて読めませんね ^^;

    ホイール クリックの自動スクロール速度を調整できれば、テキストを読むときのような用途にも使えるようになるかもしれませんね。

     |  Kuro  |  返信
  4. 自分の環境では Sleep メソッドが使われてるマクロを Chakra や JScript (5.8) で実行すると、すべての Sleep が終わるまで Mery がフリーズしてしまいます。

    例えば、下記のマクロは1秒間隔で5回スクロールするという動作が期待されます。しかし、実際は1つめのスクロールも描画されずにフリーズしてしまい4秒後に復帰して5回スクロールされた状態で描画されます。

    ++ScrollY;
    Sleep(1000);
    ++ScrollY;
    Sleep(1000);
    ++ScrollY;
    Sleep(1000);
    ++ScrollY;
    Sleep(1000);
    ++ScrollY;
    

    以下を先頭に追加して V8 で実行すると期待通りに動作します。

    #language = "V8"
    

    Takeshi さんは上述の「自動的にスクロールするマクロ」が動作してるようなので環境によるのかもしれません。
    面白そうなマクロですが、残念ながら自分の環境ではうまく動作しませんでした。

    【テストした環境】
    ・Mery: 3.6.5 (x64)
    ・OS: Windows 10 22H2 (19045.3930、64 ビット)
    ・CPU: Intel Core i5-6200U
    ・GPU: Intel HD Graphics 520

    少し話がそれますが、マクロの記録で Ctrl + Up/Down でカーソルを動かさずにスクロールしたとき LineUp/LineDown メソッドと記録されるのは少し違和感がありますね。

     |  ucky  |  返信
  5. ご報告ありがとうございます。

    これは、画面が描画されるタイミングに依存しているようですね。

    Mery の仕様において、たとえば…

    カーソルが画面の最終行にある状態で、カーソルの下移動によって画面全体がスクロールする場合ですね。マクロの場合、以下のようになります。

    document.selection.LineDown(false, 1);
    

    このとき、仕様上、画面が強制的に再描画されます。

    しかし、マウス ホイールによるスクロールやその他多くのシーンでは、常に再描画を行うと動作速度が低下してしまうため、CPU に余裕ができたタイミングで再描画が行われる仕組みになっています。

    そのため、マクロの ScrollY プロパティを変更した場合、再描画のタイミングはマクロが終了して、CPU に余裕ができたときとなります。

    ちなみに、Redraw プロパティも試してみましたが、これは画面の再描画を抑制するためのプロパティだったもので、Redraw = true にしても強制的に再描画される仕様にはなっていないですね。

    そもそも、マクロの実行中にリアルタイムで画面を更新する使い方を想定していなかったため、画面スクロールのマクロには驚きました。

    そういった使い方がある場合、内部的な再描画のタイミングまでは変更できませんが、Redraw = true を呼び出すことで画面を強制的に再描画できるようにすると面白いかもしれませんね。

    > 少し話がそれますが、マクロの記録で Ctrl + Up/Down でカーソルを動かさずにスクロールしたとき LineUp/LineDown メソッドと記録されるのは少し違和感がありますね。

    これは気付いていませんでした。次のバージョンでは対応しておきますね。

     |  Kuro  |  返信
  6. 書き忘れていました。

    #language = "V8"
    

    V8 エンジンを使う場合、マクロは Mery.exe とは別のプロセスで実行されます。

    簡単に言うと、別のアプリから Mery を操作してる感じですね。

    そのため、再描画は通常、人間が操作しているときと同じタイミングで行われ、ScrollY プロパティでもリアルタイムに再描画されるんじゃないかなと思います。

     |  Kuro  |  返信
  7. >> Kuro さん

    ご確認ありがとうございます。

    なるほど、そういう仕様だったんですね。

    Takeshi さんのマクロもスピードを速めて改めて試したところ、カーソルが画面下部に来たタイミングで描画が再開されてスクロールしました。

    > そういった使い方がある場合、内部的な再描画のタイミングまでは変更できませんが、Redraw = true を呼び出すことで画面を強制的に再描画できるようにすると面白いかもしれませんね。

    既存のプロパティに機能を追加するのは少し怖いですが、面白そうですね。今のところ活用法は思いついてないですが……。

    >> Takeshi さん

    もう解決されているかもしれませんが、開いているファイルの行数は document.GetLines メソッドで取得できます。加えてカーソル位置の行数も document.selection.GetActivePointY メソッドで取得できるので、下記のようにすることで文書の終端の行でマクロを終了できると思います。

    // 文書の終端の行数を表示座標で取得
    const lastLine = document.GetLines(meGetLineView);
    
    // 現在のカーソル位置の行数を表示座標で取得
    const currentLine = document.selection.GetActivePointY(mePosView);
    
    // ループ回数を計算
    const loopCount = lastLine - currentLine;
    
    // 略
    
    for (let i = 0; i < loopCount; i++) {
    // 略
    }
    
     |  ucky  |  返信
  8. > > 少し話がそれますが、マクロの記録で Ctrl + Up/Down でカーソルを動かさずにスクロールしたとき LineUp/LineDown メソッドと記録されるのは少し違和感がありますね。
    >
    > これは気付いていませんでした。次のバージョンでは対応しておきますね。

    Version 3.7.0 にてスクロールに変更されているのを確認しました。

    修正ありがとうございました。

     |  ucky  |  返信
  9. ご確認ありがとうございます。

    うまく動いているようで安心しました。

    ちなみに、Ver 3.7.0 では、Ctrl + Up/Down 以外にも、Alt や Shift と組み合わせた場合でも、正しいコマンドが記録されるようになっています。

    > 既存のプロパティに機能を追加するのは少し怖いですが、面白そうですね。今のところ活用法は思いついてないですが……。

    それから、前回ご返信をいただいていた、「Redraw = true で再描画する」件については、今のところ使い道が見つからなさそうとのことでしたので、今回は実装を見送りました。

     |  Kuro  |  返信
スポンサーリンク