HLFX.Ru Forum
профиль •  правила •  регистрация •  календарь •  народ •  FAQ •  поиск •  новое •  сутки •  главная •  выход  
HLFX.Ru Forum HLFX.Ru Forum > Наш форум > Технические вопросы > WM_ACTIVATE considered harmful
  Предыдущая тема   Следующая тема
Автор
Тема Новая тема    Ответить
Government-Man
Призрак

Дата регистрации: Apr 2006
Проживает: N/A
Сообщений: 3507

Рейтинг



Награды
 
[1 награда]


WM_ACTIVATE considered harmful

Давайте проведем мысленный эксперимент.

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

Что еще нужно для полноценного шутера? Конечно же возможность вертеть головой при помощи мыши! Как это сделать? Правильный ответ на этот вопрос в наше время - используя WM_INPUT, но предположим на секунду, что вы по каким-то лишь вам одним ведомым причинам отвергли этот вариант, и решили реализовать mouselook также, как это было сделано например в Quake, потому что только в нем и живет дух старой школы.

Метод следующий:

1) Находим координаты центра экрана (окна)
2) Перемещаем указатель мыши в центр экрана
3) Периодически получаем текущие координаты указателя, считаем дельту и возвращаем указатель в центр
4) По вкусу устанавливаем ClipCursor/SetCapture, но это уже детали...

Вау! Гордясь собой, вы перемещаетесь по созданному вами миру, стремясь осмотреть созданный вами треугольник со всех сторон. Но тут вы услышали уведомление - это друг написал вам в инстаграмчике, приглашая на новый митинг Навального. Вы жмете Alt+Tab чтобы переключиться на браузер, и тут понимаете, какая с вами произошла неприятность - кровавая гэбня захватила ваш к... указатель мыши все время перемещается в центр экрана, даже когда вы работаете с другим окном!

Слегка отойдя от шока, вы понимаете, что вам нужно каким-то образом узнавать, когда пользователь переключился на игру (и тогда активировать работу с мышью) и когда он переключился на что-то другое (и тогда мышь деактивируется). Пошерстив MSDN (или как вариант - код кваки) вы узнаете о существовании сообщений WM_ACTIVATE и WM_ACTIVATEAPP. Они немного различаются, но для однооконного приложения, каким является типичная игра, разницы практически нет (хотя WM_ACTIVATE позволяет еще узнать о том, что окно свернуто).

Казалось бы - вот оно решение! Пользователь нажимает на окно - оно активируется, нажимает на другое - первое деактивируется. Все просто, не так ли?

К сожалению, нет. Вернее, не совсем...

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

Но постойте, ведь активация мыши завязана на WM_ACTIVATE, как же так получилось, что окно получило это сообщение, несмотря на то, что не является активным?

Все дело в том, что в многозадачной винде статус активного (active) окна имеет смысл только для треда, который это окно создал. Он ничего не говорит о том, имеет ли окно на самом деле фокус ввода в системе. Окно может быть активным в рамках своего треда, но не иметь при этом системого фокуса ввода. Самое гадкое при этом, что функции GetActiveWindow() и GetFocus() при этом будут вас убеждать что именно ваше окно, а не какое-то там другое является активным и имеет фокус.

Окно, имеющее системный фокус, называется foreground window, узнать, имеет ли ваше окно фокус можно используя функцию GetForegroundWindow(). У нее есть и собрат - функция SetForegroundWindow(). Так вот же оно - решение! Просто попросим систему дать фокус нашему окну...

К сожалению, в современных версиях винды приложение не может принудительно установить фокус ввода на свое окно. Подробнее об этом можно прочитать в документации к SetForegroundWindow.

Как же быть? Хороший вопрос...

Вам может придти в голову идея установить вашему окну стиль WS_EX_TOPMOST чтобы оно появлялось поверх всех остальных окон. Не делайте этого ни в коем случае! То, что ваше окно находится поверх всех остальных еще не говорит, что оно является foreground window! Если бы окно нашей гипотетической игры в приведенном выше примере имело этот стиль, то нажатие например Alt+F4 после появления окна игры, закрыло бы не окно игры, а то окно, которое вы нажали в последний момент перед появлением окна игры, например - чатик с Навальным...

Можно при получении WM_ACTIVATE дополнительно проверять GetForegroundWindow() но тогда при клике на окно вы не получите второй раз WM_ACTIVATE - окно-то уже активно! А имеет ли оно реальный фокус - кому какое дело...

Вообще существует два прямо противоположных взгляда на взаимодействие игры с системой:

1) Концепция старой школы предписывает игре считать себя главным и единственным куском кода в системе. Она предполагает агрессивный захват ввода, вывода и всех остальных ресурсов компа, рекомендацию закрыть все остальные приложения итд. Зависло? Ресет!
2) Более современная концепция предписывает игре считать себя таким же приложением как и все другие, уважать многозадачность и интересы пользователя. Зависло? Приносим глубочайшие извинения!

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

Сообщить модератору | | IP: Записан
Сообщение: 191095

Старое сообщение 11-03-2020 17:29
- За что?
ncuxonaT
каков стол, таков и стул

Группа: Опытный
Дата регистрации: Oct 2009
Проживает: город/село/деревня
Сообщений: 1626
Возраст: 33

Рейтинг



Ты практически мою жизнь описал

Сообщить модератору | | IP: Записан
Сообщение: 191096

Старое сообщение 11-03-2020 17:39
- За что?
 Дядя Миша
racing for fish

Дата регистрации: Oct 2005
Проживает: Кубань
Сообщений: 32202
Нанёс повреждений: 392 ед.

Рейтинг



Цитата:
Government-Man писал:
и вот уже на экран выводится ваш первый в жизни треугольник.

А этот треугольник аппаратно-ускоренный или не очень?

Цитата:
Government-Man писал:
Вы в очередной раз запустили вашу игру, но сразу после запуска экзешника случайно щелкнули по открытому окну папки, в которой экзешник располагался.

У меня был несколько иной баг. Допустим, что я запускал приложение не мышкой, а нажатием Enter, так вот движок успевал загрузиться раньше, чем я отпускал кнопку и генерировал её отпускание уже в игре. А я никак не мог вдуплить, ну почему с мышки - норм, а с клавы - такое. В итоге это приводило к забавному багу - отжатая кнопка генерировала команду, которая блуждала-блуждала, выходила в меню и запускала новую игру, там же как раз эвент на отпускание кнопки

В ксаше я выполняю оба-два действия
C++ Source Code:
SetForegroundWindow( host.hWnd );
SetFocus( host.hWnd );

Под XP проблем нету, а дышатка мне и даром не упала.

Цитата:
Government-Man писал:
Концепция старой школы предписывает игре считать себя главным и единственным куском кода в системе. Она предполагает агрессивный захват ввода, вывода и всех остальных ресурсов компа

Ну я бы не сказал. Ксаш нормально отдаёт управление по альт-табу или просто по клику на другое окно. Я даже от аппаратной гаммы отказался в своё время по той же причине. А то как сделать упровление мышкой. Разве сейчас не только лишь все используют SDL2?
Я думал он уже давно дефакто стандарт для всех игровых движков.

Добавлено 11-03-2020 в 20:51:

Цитата:
ncuxonaT писал:
Ты практически мою жизнь описал

Меньше всего я подозревал тебя в том, что ты хочешь сделать свою игру.

Добавлено 11-03-2020 в 21:29:

Вообще вот эта замута с мышкой, имеет под собой вполне конкретную задачу - полный контроль. Нет чёткой уверенности, что дельту надо получать синхронно с окончанием одного кадра. Иногда её надо получать несколько раз за кадр. Как WM_INPUT поможет это разрулить?

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'

Сообщить модератору | | IP: Записан
Сообщение: 191097

Старое сообщение 11-03-2020 18:29
-
Government-Man
Призрак

Дата регистрации: Apr 2006
Проживает: N/A
Сообщений: 3507

Рейтинг



Награды
 
[1 награда]


Цитата:
Дядя Миша писал:
Вообще вот эта замута с мышкой, имеет под собой вполне конкретную задачу - полный контроль. Нет чёткой уверенности, что дельту надо получать синхронно с окончанием одного кадра. Иногда её надо получать несколько раз за кадр. Как WM_INPUT поможет это разрулить?


А зачем получать дельту несколько раз за кадр?

WM_INPUT никак не поможет это разрулить - наоборот, это пассивный способ ввода - приходится ждать пока система решит послать сообщение.

Сообщить модератору | | IP: Записан
Сообщение: 191102

Старое сообщение 11-03-2020 18:50
- За что?
 Дядя Миша
racing for fish

Дата регистрации: Oct 2005
Проживает: Кубань
Сообщений: 32202
Нанёс повреждений: 392 ед.

Рейтинг



Цитата:
Government-Man писал:
А зачем получать дельту несколько раз за кадр?

Конкретно в кваке это был такой способ борьбы с тормозами. Но уже в ку2 от него отказались.

Цитата:
Government-Man писал:
приходится ждать пока система решит послать сообщение

не нравится мне это совсем. Движок не та система, чтобы ждать подобные вещи. Вон в новом дууме для инпута вообще отдельный поток.

__________________
My Projects: download page

F.A.Q по XashNT
Блог разработчика в телеграме

Цитата:

C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'

Сообщить модератору | | IP: Записан
Сообщение: 191105

Старое сообщение 11-03-2020 18:56
-
Тема: (Опционально)
Ваш ответ:



Переводчик транслита


[проверить длину сообщения]
Опции: Автоматическое формирование ссылок: автоматически добавлять [url] и [/url] вокруг интернет адресов.
Уведомление по E-Mail: отправить вам уведомление, если кто-то ответил в тему (только для зарегистрированных пользователей).
Отключить смайлики в сообщении: не преобразовывать текстовые смайлики в картинки.
Показать подпись: добавить вашу подпись в конец сообщения (только зарегистрированные пользователи могут иметь подписи).

Временная зона GMT. Текущее время 13:04. Новая тема    Ответить
  Предыдущая тема   Следующая тема
HLFX.Ru Forum HLFX.Ru Forum > Наш форум > Технические вопросы > WM_ACTIVATE considered harmful
Версия для печати | Отправить тему по E-Mail | Подписаться на эту тему

Быстрый переход:
Оцените эту тему:

Правила Форума:
Вы not можете создавать новые темы
Вы not можете отвечать в темы
Вы not можете прикреплять вложения
Вы not можете редактировать ваши сообщения
HTML Код ВЫКЛ
vB Код ВКЛ
Смайлики ВКЛ
[IMG] Код ВКЛ
 

< Обратная связь - HLFX.ru >

На основе vBulletin
Авторское право © 2000 - 2002, Jelsoft Enterprises Limited.
Дизайн и программирование: Crystice Softworks © 2005 - 2024