[ 新規に投稿する ]

hidemaruorder が非同期に欲しいかもNo.10675
こみやんま さん 25/04/14 16:29 [ コメントを投稿する ]
  以前投稿した気もしますが、

hidemaruorder かもしくは hidemaruhandle かどちらかを非同期にした方がよい気がします。

jsmode の非同期って、非アクティブウィンドウであっても律儀に動作しますが、
非アクティブウィンドウの時は大抵は 処理をまるまるスルーしても問題ないことがほとんどなので...

// 非同期で典型的なTick処理となるが、
// そもそも非アクティブはほとんどのケースでは処理自体不要なので
// 下記ソースの★により処理の弾きをどうするのか。

// 「テキスト変化やカーソル変化が相手」のスクリプトなら、updateCouuntやlinenoやcolumn 使えばほとんど弾けるが、
// そうではない場合に、heavy処理やったあげく使われてないとかでは悲しい。

hidemaruversion "9.46.02";

jsmode "WebView2\\" + currentmacrofilename;

js {

debuginfo(2);
const hwnd = hidemaru.getCurrentWindowHandle();
console.log(findwindowclass("Hidemaru32Class")==hwnd);
function isCurrentWindowBackGroud() {
    // 異なる目的で実装してももらったものだが、タブモードの時はほとんど似た働きをする
    return (windowstate2() & 0x0004) != 0;

    // 本当は
    // hidemaruorder( hidemaru.getCurrentWindowHandle() ) == 0
    // とかが妥当か。

    // 原則は秀丸が複数あると一番上のがヒットするから
    // FindWindow系でも出来はするだろうが、「Windowsデスクトップ直下から頻繁にウィンドウ探してる」のは無駄も多くもったいない。
    // また、常駐秀丸のメニューを右クリックしてしまったりすると、FindWindow はどちらに反応するの? という迷いが出る
    // const hwnd = hidemaru.getCurrentWindowHandle();
    // findwindowclass("Hidemaru32Class")==hwnd || findwindowclass("Hidemaru32Class_Appx")==hwnd
}


var dummyTestCount = 0;
function clearCondition() {
    return dummyTestCount > 10;
}

var timeoutHandle;
if (timeoutHandle) {
    hidemaru.clearTimeout(timeoutHandle);
}

function asyncFunc() {

    if (clearCondition()) {
        hidemaru.clearTimeout(timeoutHandle);
        return;
    }

    try {
        // ★ 非アクティブならこの記述でポーンと弾く!! 
        if (isCurrentWindowBackGroud()) {
            return;
        }

        // ほとんどのスクリプトにおいては、
        // トップの時だけなにか監視や計算や更新すればよく、それ以外の時は、やる必要がない。

        // 何か計算したり、変化を調べたりしている
        // 他のウィンドウや枠にメッセージを送信している
        console.log(dummyTestCount++);
    }
    finally {
        timeoutHandle = hidemaru.setTimeout(asyncFunc, 1000);
    }
}

timeoutHandle = hidemaru.setTimeout(asyncFunc, 1000);

} // js
[ ]
RE:10675 hidemaruorder が非同期に欲しいかもNo.10676
秀丸担当 さん 25/04/15 11:49 [ コメントを投稿する ]
  hidemaruorder等のウィンドウ番号は、自分自身は常に0になります。
そのため、アクティブかどうかの判定はできませんでした。
将来やるとしたら、inputstatesにそのままアクティブかどうかのビットがあったら簡単かもしれません。
現状では、タブモードであればタブが裏側で非表示状態となっているかで判定するくらいしかなさそうです。
[ ]
RE:10676 hidemaruorder が非同期に欲しいかもNo.10677
こみやんま さん 25/04/15 12:59 [ コメントを投稿する ]
  タブモードについては、(監視処理の処理部分スルーするかどうかの判定は)
おそらくは、

inputstates() & 0x00000800  や、
windowstate2() & 0x0004     が

良い間引き判定になるんだろううと思います。

(個人的にはほぼタブモードでしか利用しないので、いいんですが)

「非タブモード」
の間引きは「見えてたらやる」
のか「トップならやる」のかは、
ユーザーが作成する個々のスクリプトの機能というか性質によって左右されますが、
扱いの柔軟性という意味では、
「秀丸ウィンドウハンドルのリスト」を
レイヤーが上のものから順に格納されたリストを得るっていうのが
一番扱いやすいかと思います。

```こういうのが取得出来る関数が秀丸から提供されているのが楽。結局一番楽(全てのハンドル・Z順・個数が全部一気にわかるので...)
var hidemaruWndZLayerList = [1番上の秀丸, 2番目... ]

var hidemaruWndZLayerList = hidemaru.getHidemaruWindowHandleList();
```

そうすれば、ユーザーは以下みたいに記述しておけば、ざっくりとは「関係ないプロセスは裏でJSで処理しなくてもいいよ」と出来るので。

```
// 監視対象とするべきウィンドウなの?
function isMustWatchCurrentWindow() {
    // タブの裏、もしくは非表示
    if (inputstates() & 0x00000800) {
        return false;
    }

    // 自分何番目
    const curWindowHandle = hidemaru.getCurrentWindowHandle();
    const layerIndex = hidemaruWndZLayerList.indexOf(curWindowHandle);

    // 非タブモードでは、トップ1位・2位までなら処理とか(非タブモードで多分左右横にならべる程度までの考慮)。
    // (ほとんどのスクリプトでは機能的にもトップ1位だけで十分でしょうが...)
    if (layerIndex >= 2) {
        return false;
    }

    return true;
}
```

[ ]
RE:10677 hidemaruorder が非同期に欲しいかもNo.10678
秀丸担当 さん 25/04/15 17:30 [ コメントを投稿する ]
  そういう手段もあったらいいということで、ご意見参考にさせていただきます。
[ ]
RE:10678 hidemaruorder が非同期に欲しいかもNo.10679
こみやんま さん 25/04/17 13:11 [ コメントを投稿する ]
  >そういう手段もあったらいいということで、ご意見参考にさせていただきます。


例えば、

let hmWndList = hidemaru.getWindowHandleList();

で、

[ 1番目のウィンドウハンドル, [2番目, 3番目, 4番目], 5番目, 6番目, [7番目, 8番目], 9番目]

みたいなのが返ってきて、

・全体の順番はウィンドウズからみたレイヤーの順
・「要素自体」がリスト(上の例なら2,3,4番目)は、タブになってる

みたいなのでも有りだと思います。
(今のjsは 配列オブジェクトにはflat()みたいな関数もあるので、ネストを平らするうのも楽ですし)

// -------------------------------------------

現在は重量級のもの、
一度実行してしまうと、非同期[jsではなく本当の非同期] であるとはいえ、秒といった時間がかかるものに対しては
以下みたいに形で間引き判定しています。

```
IsCurrentWindowAbove()
```

これと似たようなことを 「jsmode 層だけで完結するような処理の場合」
に手軽にできればよいという感じです。


// Hm.WindowHandleのクラス名。ストア版とデスクトップ版で異なため、それを考慮してキャッシュする。
string curHmWndClassNameCache = null;

// 指定されたウィンドウのクラス名を取得する関数
private string GetWindowClass(IntPtr hWnd)
{
    StringBuilder className = new StringBuilder(256);
    int result = GetClassName(hWnd, className, className.Capacity);
    if (result > 0)
    {
        return className.ToString();
    }
    return null;
}

// 親ウィンドウをたどり、同じクラス名のウィンドウがあるか判定する関数
public bool HasSameClassParent(IntPtr hWnd)
{
    IntPtr parentHWnd = GetParent(hWnd);
    while (parentHWnd != IntPtr.Zero)
    {
        string parentClassName = GetWindowClass(parentHWnd);
        if (parentClassName == curHmWndClassNameCache)
        {
            return true; // 同じクラス名の親ウィンドウが見つかった
        }
        parentHWnd = GetParent(parentHWnd);
    }

    return false; // 同じクラス名の親ウィンドウは見つからなかった
}

// 他のウィンドウより上方にある(1つに絞るわけではなく、jsmodeやネイティブやC#などプログラム実行継続の対象となるウィンドウという意味)
private bool IsCurrentWindowAbove()
{
    IntPtr curHWnd = Hm.WindowHandle;

    // 自身のウィンドウハンドルのクラス名のキャッシュがない
    if (curHmWndClassNameCache == null)
    {
        curHmWndClassNameCache = GetWindowClass(curHWnd);
    }

    // タブモードである
    if (HasSameClassParent(curHWnd) )
    {
        int currentWindowBackGround = Hm.Edit.InputStates & 0x00000800;
        // 非アクティブではない(=自分のプロセスはアクティブである)
        if (currentWindowBackGround == 0)
        {
            return true;
        }
    }
    // 非タブモードなら
    else
    {
        if (curHmWndClassNameCache?.Length > 0)
        {
            // そのクラス名で検索。(非タブモードならデスクトップ直下のルートウィンドウとして秀丸ウィンドが存在する)
            IntPtr firstFindWnd = FindWindow(curHmWndClassNameCache, IntPtr.Zero);
            // 自分が秀丸の中で一番手のウィンドウである
            if (firstFindWnd == curHWnd)
            {
                return true; ;
            }
            else
            {
                IntPtr secondFindWnd = FindWindowEx(IntPtr.Zero, firstFindWnd, curHmWndClassNameCache, IntPtr.Zero);
                // 自分が秀丸の中で2番手のウィンドウである
                if (secondFindWnd == curHWnd)
                {
                    return true; ;
                }
            }
        }
    }

    return false;
}
[ ]
RE:10679 hidemaruorder が非同期に欲しいかもNo.10680
秀丸担当 さん 25/04/17 15:14 [ コメントを投稿する ]
  現在操作中のウィンドウかどうかは、inputstatesに追加してみています。
Zオーダーのリストはわりませんが、参考にさせていただきます。
自前のDLL等で親子関係やウィンドウクラスでの判別するとしたら、必ずしもこのウィンドウ構成が保証されるとは限らないので、現在のバージョンや環境では動いているというくらいに留めておいてほしいです。
[ ]
RE:10680 hidemaruorder が非同期に欲しいかもNo.10681
こみやんま さん 25/04/17 15:31 [ コメントを投稿する ]
  >自前のDLL等で親子関係やウィンドウクラスでの判別するとしたら、必ずしもこのウィンドウ構成が保証されるとは限らないので、現在のバージョンや環境では動いているというくらいに留めておいてほしいです。

タブモードなのか、タブモードじゃないのかで、結構 dllなどネイティブから探るのが苦戦する
(担当さんがいうように
「現在はそれでいけるが将来それでいけるとは限らない」)
みたいなことになりがちなので、

久々であまり追加したくはないかもしれないですが、
ネイティブのexportの
Hidemaru_*** シリーズに tabmode 相当の値を得るものを出しておいてもらいたいです。

(そうすればネイティブから変にウィンドウの構造を調べる必要性がなくなるうので)
[ ]
RE:10681 hidemaruorder が非同期に欲しいかもNo.10682
秀丸担当 さん 25/04/18 16:12 [ コメントを投稿する ]
  Hidemaru_***のほうはできるだけこれ以上は追加したくないところですが、そういうご意見があるということで参考にさせていただきます。
[ ]
RE:10680 hidemaruorder が非同期に欲しいかもNo.10683
こみやんま さん 25/04/19 02:25 [ コメントを投稿する ]
  >現在操作中のウィンドウかどうかは、inputstatesに追加してみています。

9.46.04 で追加されているのを確認しました。

これ今までと趣旨が反転しているような印象を受けますが大丈夫なんでしょうか。

まぁ inputstates() というだけだから、間違ってはいないのですが、
「チック処理をするに妥当性を欠く可能性が高い」といったステータスの時に「フラグが立つ」ように構成しているのかな? と思っていました。

もちろん関数名は、そのようなことを意味していないので、いいんですが、
ちょっとローカルを検索してみた際に、

秀丸担当さんが作成した
https://hide.maruo.co.jp/lib/macro/v922macsamples.html
  └ samples\04md\mdeasy2.mac
       └ if(hm.getInputStates()==0){

といった記述があるように、
inputstates()が0の時が、「もっとも問題がない」とおぼしき時という
というように作成している(つもり)的な感じの記述があります。

とりあえず、単体でみると、inputstates() & 0x00100000 は いい感じでコントロールできるかと思います。

個人的には、操作しているのが 0 、操作していないのが 1の方がいいんでないか?
今までとあってるし、全体や 特に 0x00000800 ともあっているのでは?
とは思います。
(もちろん意味反転フラグになるので、理解が少し難しくはなってしまうんですが...)

[ ]
RE:10683 hidemaruorder が非同期に欲しいかもNo.10686
秀丸担当 さん 25/04/21 09:25 [ コメントを投稿する ]
  ご指摘ありがとうございます。
確かにこれまでの主旨を考えると、逆のほうがよかったです。
次のβ版では、0x00100000を廃止して、意味が逆の0x00200000に変更しようと思います。
[ ]
RE:10686 inputstates() & 0x800 と windowstate2() & 0x4No.10688
こみやんま さん 25/04/22 07:02 [ コメントを投稿する ]
  ちょっと関連する項目で、以下の2つの違いがよくわからなくて
判定する上で自信が持てないです。

@ inputstates() & 0x00000800

「非アクティブなタブ」または「非表示のウィンドウ」の、
「非アクティブなタブ」の部分と、

A windowstate2() & 0x0004
「Windowsが管理するウィンドウとして非表示状態」と
「タブモードでアクティブではない状態としての非表示状態も」

という2つは、ちょっと微妙に違うのかもしれないですが、
何が違いますか?


よくわからないから、今はjsmodeでは「@ or A」みたいな 判定してます...
[ ]
RE:10688 inputstates() & 0x800 と windowstate2() & 0x4No.10689
秀丸担当 さん 25/04/22 13:31 [ コメントを投稿する ]
  ご指摘ありがとうございます。
このオプションの存在を忘れていてwindowstate2が必要かと思ったのですが、実際は結果的に同じでした。
windowstate2は必要無かったです。
意味としては、inputstatesのほうは、トップレベルのウィンドウが非表示のときも判定に含まれますが、windowstate2はトップレベルのウィンドウが非表示ならタブのウィンドウも非表示なので、ようするに同じです。
違いは他の秀丸エディタからも取得できることですが、それは狙ったことではないです。
でもせっかくなので残しておこうと思います。
[ ]
RE:10688 inputstates() & 0x800 と windowstate2() & 0x4No.10690
こみやんま さん 25/04/24 16:17 [ コメントを投稿する ]
  ◎ inputstate() & 0x00200000 大丈夫そうです。

・jsmode 非同期関数内
・ネイティブのHidemaru_InputStatesで、かつ秀丸とは別スレッド(チックで
並列実行)

で両方でパッと実行した分では大丈夫そうです。
[ ]

[ 新規に投稿する ]