Робимо просте утримання курсору у вікні Warcraft 3

Вітаю тебе, читачу. У мене є хобі - це старий добрий Warcraft 3. На хабрі вже був цикл статей, присвячений цій чудовій грі. Хочу поділитися з комьюніті однією утилітою, що знадобилася мені під час проведення стриму. Всіх, хто зацікавився, прошу пройти під кат.

Передмова
Супутнє ПЗ

Для проведення трансляції, крім усього іншого, буде потрібно програму для захоплення контенту. На даний момент можна виділити два з них: xsplit та openbroadcaster. Чесно скажу, першим не скористався. У безкоштовній версії доступний базовий функціонал. Але для завантаження базової версії доведеться пройти обов'язкову реєстрацію (не те, що б це було проблемою, але.). До другого варіанту схилила ліцензія GPL і доступність вихідного коду. На Openbroadcaster я і зупинився.

Із встановленням та налаштуванням OBS проблем не виникло. Але запущена гра ніяк не хотіла захоплюватися в рекомендованому режимі Game capture (ймовірно, це пов'язано з використанням старої версії directx при розробці гри). Погравшись з іншими режимами захоплення, вдалося знайти два, які забезпечували необхідну поведінку - Monitor capture та Window capture. Перший досить сильно афект перформанс. Відчувається під час гри. Але це був робочий варіант, що називається "з коробки". Другий варіант приводив до дискомфорту в процесі гри - курсор постійно виходив за межі вікна. Загалом, було абсолютно неграбно.

Було обрано другий варіант і прийнято рішення написати утиліту для усунення описаного вище дискомфорту. Спочатку Warcraft III запускається в повноекранному режимі. Для запуску у віконному режимі необхідно використовувати ключ "-window" у команді запуску програми, це якраз дозволить виконати захоплення в режимі Windowscapture.

Для утримання курсору в рамках клієнтської області вікна було написано першу версію утиліти. Основний цикл її роботи наведено нижче:

Тут використовується допоміжний клас ClipHelper для управління процесом утримання курсору та клас FullScreen для управління процесом переходу в повноекранний режим та відновлення з нього. Сам цикл реалізує алгоритм полінгу активного вікна з таймаутом 500 мс. Цей момент мені не сподобався відразу, але для руху далі потрібно перевірити всю концепцію, а потім зайнятися оптимізацією.

У процесі використання утиліти відразу виникли такі хотіння: — Clip проводити тільки у разі кліка (утримання для полінг версії) по клієнтській області, щоб мати можливість перетягувати вікно; - дратував вигляд taskbar під час гри (актуально, якщо вона зафіксована). Першою думкою було приховати її програмно. Але в такому випадку необхідно було б відстежувати моменти виходу користувача з гри та показувати taskbar назад. Підвищувався ризик залишити користувача без панелі завдань. Тому реалізацію fullscreen я вирішив зробити зміною розмірів ігрового вікна до розмірів роздільної здатності монітора, за яким це вікно закріплено:

Оптимізація

У другій версії утиліти полінг активного вікна був замінений хуком повідомлень WM_ACTIVATE та WM_LBUTTONDOWN. Для цього я використовував два типи хуків: WH_CALLWNDPROC та WH_MOUSE. Суть у тому, що ми відстежуємо необхідні події ігрового вікна та повідомляємо нашу утиліту через вікно-сервер. Хук вішався лише для процесу гри. Таким чином, гра має бути запущена до утиліти:

А основний цикл роботи звівся до наступної процедури:

Допоміжні класи, що використовуються, ті ж, що і в першій версії. Ця функція є віконною процедурою вікна-сервераутиліти. Для захоплення курсору та переходу в повний екран необхідно активувати вікно та клацнути лівою кнопкою по клієнтській області. Коли вікно перестає бути активним, воно відновлюється до вихідних розмірів і положення, а курсор більше утримується у ньому.

Післямова

Було розроблено утиліту, покликану зробити процес стримування улюбленої гри більш комфортним, ніж пропонований робочий варіант «з коробки». Радий, якщо хтось почерпне для себе щось цікаве. Весь вихідний код залито на github WinClipCursor.