2023-11-29 (Wed) [長年日記]

_ [ahk]モニタのオンオフでウィンドウ動いちゃう問題 その2

マウスポインタの位置も元に戻したいと思ったんだけど、 モニターがオフの間にもなぜかスクリーンサイズが戻る瞬間があるみたいで、 そのときに MouseMove すると画面がオンになってしまう。(WinMove だけなら問題ない)

面倒なので、画面サイズじゃなくてやっぱり https://www.autohotkey.com/boards/viewtopic.php?p=539708 の通知を使うことにした。

だからループの頻度を減らしても良さそう。 ループを消してしまうことも考えたけど、 最小化ウィンドウが最小化する前の位置を記憶しておくために利用することにした。

#Requires AutoHotkey v2.0
#Warn
#SingleInstance Force

monpower := 1
registerpower()

awake := true
wins := Map()
while (true) {
  if (awake and monpower) {
    savewins(&wins, WinGetList(, , "Program Manager"))
  }
  Sleep(1000)
  continue
}

savewins(&oldmap, ids) {
  newmap := Map()

  MouseGetPos(&mx, &my)
  newmap["mouse"] := { x: mx, y: my }

  for (this_id in ids) {
    try {
      minmax := WinGetminmax(this_id)
      WinGetPos(&x, &y, , , this_id)
    } catch (TargetError) {
      continue
    }

    if (minmax = -1 && oldmap.Has(this_id)) {
      newmap[this_id] := {
        x: oldmap[this_id].x,
        y: oldmap[this_id].y,
        minmax: minmax
      }
    } else {
      newmap[this_id] := { x: x, y: y, minmax: minmax }
    }
  }
  oldmap := newmap
}

restorewins(winmap) {
  for (this_id, d in winmap) {
    if (this_id = "mouse") {
      MouseMove(d.x, d.y, 0)
      continue
    }

    try {
      minmax := WinGetMinMax(this_id)
      WinGetPos(&x, &y, , , this_id)
    } catch (TargetError) {
      continue
    }

    if (d.x = x && d.y = y && d.minmax = minmax) {
      continue
    }

    if (d.minmax = 0) {
      WinMove(d.x, d.y, , , this_id)
    } else {
      WinRestore(this_id)
      WinMove(d.x, d.y, , , this_id)
      if (d.minmax = 1) {
        WinMaximize(this_id)
      } else if (d.minmax = -1) {
        WinMinimize(this_id)
      }
    }
  }
}

; https://www.autohotkey.com/boards/viewtopic.php?p=539708
registerpower()
{
  CLSID := Buffer(16)
  if (res :=
    DllCall("ole32\CLSIDFromString",
      ; GUID_CONSOLE_DISPLAY_STATE_
      "WStr", "{6FE69556-704A-47A0-8F24-C28D936FDA47}",
      "Ptr", CLSID,
      "UInt")
  ) {
    throw (Error("CLSIDFromString failed. Error: " . Format("{:#x}", res)))
  }

  if (! ;hPowerNotify :=
    DllCall('RegisterPowerSettingNotification',
      'Ptr', A_ScriptHwnd,
      'Ptr', CLSID,
      'UInt', 0,
      'Ptr')
  ) {
    throw (OSError(A_LastError, -1, 'RegisterPowerSettingNotification'))
  }

  Sleep(1) ; a notification is always emitted immediately after registering for it for some reason. this prevents seeing it
  OnMessage(0x218, _WM_POWERBROADCAST)
}

_WM_POWERBROADCAST(wParam, lParam, msg, hwnd) {
  global awake
  global monpower
  global wins
  Critical(1000)
  if (wParam = 0x8013) { ; PBT_POWERSETTINGCHANGE
    monpower := NumGet(lParam, 20, 'UChar') ; 0 (off) or 1 (on).
    if (awake and !monpower) {
      awake := false
    } else if (!awake and monpower) {
      SetTimer(restorewins.Bind(wins), -1)
      awake := true
    }
  }
  return (true)
}

«前の日記(2023-11-28 (Tue)) 最新