Что нового

Как следить за состоянием всех окон в системе?

Spray

Новичок
Сообщения
17
Репутация
2
Пролог

Задача

Решил доработать один свой сценарий. Его назначение — вежливо, но настойчиво заставлять пользователя отрывать пятую точку, чтобы уберечь его от геморроя. Принцип таков: есть таймер а-ля песочные часы; пока вы работаете, «песочек» сыпется; как только «песочек» заполнит выделенный ему «объём» (например, 50 минут), вылетает окно в полэкрана, мешающее нормально работать и предлагающее оторваться от рабочего места; в любой момент таймер можно «перевернуть», заблокировав компьютер, и тогда песочек посыпется обратно, раз в пять быстрее; как только песочек вернётся весь обратно, противное окно добреет и просит себя закрыть, чтобы вы могли продолжить работу; итого каждые пять минут работы принуждают к одной минуте отдыха.

Проблема

Мой алгоритм отлично работает, но не учитывает некоторые способы использования ПК, больше смахивающие на отдых, во время которых блокировка исключена, при этом пятая точка на свободе. В эту категорию входят просмотр фильмов и прослушивание музыки с лицезрением альбом-арта на экране монитора, что вполне реально практиковать лёжа на диване, вдали от компьютерного кресла.

Суть

Предложение

Чтобы решить проблему, возникла идея добавить в сценарий мониторинг окон: если на рабочем столе отображается хотя бы одно окно приложения (исключая медиаплееры), то сценарий всё так же должен считать, что вы работаете, ваши 50 минут истекают, а если вдруг все окна окажутся свёрнутыми, то часы должны «перевернуться», ибо это значит, что ваша попа отдыхает.

Вопрос

Как сделать такой вот мониторинг — постоянно контролировать, есть ли несвёрнутые окна, при этом не нагружать процессор и чтобы реакция была хорошая? Пробовал фильтровать список окон, возвращаемых функцией WinList(), но от регулярного опроса процессор захлёбывается. Быть может есть какой-то способ получить сигнал о том, что какое-либо окно изменило состояние и сканировать только в эти моменты?

Как я это примерно вижу:
Код:
while True
	if все_окна_свёрнуты () then
		$состояние = $ОТДЫХ ; таймер пойдёт обратно
	else
		$состояние = $РАБОТА ; таймер пойдёт прямо
	endif
	Sleep ($НЕ_СЛИШКОМ_БОЛЬШОЙ_ПЕРИОД)
wend

func все_окна_свёрнуты ()
	??? ; не слишком ресурсоёмкий алгоритм (WinList буксует)
endfunc


В идеале, конечно, цикл с условием заменить бы на такую конструкцию:
Код:
GUIRegisterMsg (???, "callback")

func callback ($hWnd, $iMsgID, $wParam, $lParam)
	switch $wParam
	case ??? ; какое-то окно изменило состояние
		if все_окна_свёрнуты () then …
	endswitch
endfunc
 

mr.Gbabak

Осваивающий
Сообщения
257
Репутация
23
Определение активного окна:
Код:
$aList = WinList()

$sText = ''
For $i = 1 To $aList[0][0]
    ; Только для окон имеющих заголовок и не скрытых
    If $aList[$i][0] <> "" And BitAND(WinGetState($aList[$i][1]), 8) Then
        ; объединяющее присвоение элементов массива к переменной $sText с переносом строки @LF
        $sText &= "Дескриптор=" & $aList[$i][1] & "    Заголовок=" & $aList[$i][0] & @LF
    EndIf

Next
MsgBox(4096, 'Сообщение', 'активное окно :'&@CRLF&$sText)


хотя если WinList () уже пробовали...а чем вам пауза не нравится во время определения? Поставьте Sleep (1000) я, думаю это не критично будет.
 
Автор
Spray

Spray

Новичок
Сообщения
17
Репутация
2
хотя если WinList () уже пробовали...а чем вам пауза не нравится во время определения? Поставьте Sleep (1000) я, думаю это не критично будет.
В самом деле, взялся за оптимизацию имеющегося алгоритма, и цель была достигнута, не без помощи Sleep (1000) (оказалось приемлемым для моей задачи).

Код:
local $окна_были_свёрнуты = False, $окна_теперь_свёрнуты

while True
    $окна_теперь_свёрнуты = все_окна_свёрнуты ()
    ; оптимизация: управляем режимом только в «критические» моменты
    if $окна_теперь_свёрнуты <> $окна_были_свёрнуты then
        if $окна_теперь_свёрнуты then
            установить_режим ($ОТДЫХ)
        else
            установить_режим ($РАБОТА)
        endif
    endif
    $окна_были_свёрнуты = $окна_теперь_свёрнуты
    Sleep (1000)
wend

func все_окна_свёрнуты ()
    local const $winList = WinList ("[REGEXPTITLE:.+]") ; отбор окон с непустыми заголовками прямо здесь
    local $title, $state
    for $i = 1 to $winList [0][0]
        $title = $winList [$i][0]
        $state = WinGetState ($winList [$i][1])
        if $title <> "Program Manager" _ ; рабочий стол сворачивать не нужно
            and not StringInStr ($title, "Windows Media Player") _
            and not StringInStr ($title, "YouTube") _
            and BitAND ($state, 2) _ ; видимое
            and not BitAND ($state, 16) _ ; несвёрнутое
        then return False
    next
    return True
endfunc


P. S.
Код:
; Только для окон имеющих заголовок и не скрытых
If $aList[$i][0] <> "" And BitAND(WinGetState($aList[$i][1]), 8) Then

Неверное утверждение. Несвёрнутыми являются те окна, у которых в переменной состояния есть бит 16.
 
Верх