Как правильно разрешить переход по прозрачным участкам верхнего окна? - PullRequest
0 голосов
/ 17 марта 2019

Я работаю над оверлейным компонентом проекта в C # / DirectX .

Этот проект не использует WinForms или WPF

Это наложение является гибридным, в котором я хочу визуализировать компоненты пользовательского интерфейса через DirectX в мое окно и пройти через весь ввод, который не имеет отношения к базовому окну / приложению (которое яне владею).Я в основном хочу прозрачное полноэкранное окно, которое действует как интерактивный слой поверх другого приложения, где я определяю, какие входные события я использую, и какие события я пропускаю.

Это наложение создает HWND через RegisterClassEx / CreateWindowEx WIN API-вызовы.Главным образом для целей тестирования, я передаю логическую переменную, чтобы определить, хочу ли я включить «passthrough» (в основном добавляя WS_EX_TRANSPARENT к флагам создания).Мой DX-код отображается в окне с помощью CreateSwapChainForHwnd.

Фрагмент справочного кода:

        // prepare WNDPROC-equivalent code for processing WM_* messages

        wndProc = windowProcedure;  
        RuntimeHelpers.PrepareDelegate(wndProc);
        wndProcPointer = Marshal.GetFunctionPointerForDelegate(wndProc);

        // prepare window class registration structure

        PInvoke.WNDCLASSEX wndClassEx = new PInvoke.WNDCLASSEX()
        {
            cbSize = PInvoke.WNDCLASSEX.Size(),
            style = 0,
            lpfnWndProc = wndProcPointer,
            cbClsExtra = 0,
            cbWndExtra = 0,
            hInstance = IntPtr.Zero,
            hIcon = IntPtr.Zero,
            hCursor = PInvoke.LoadCursor(IntPtr.Zero, (int)PInvoke.IDC_STANDARD_CURSORS.IDC_ARROW),
            hbrBackground = IntPtr.Zero,
            lpszMenuName = randomMenuName,
            lpszClassName = randomClassName,
            hIconSm = IntPtr.Zero
        };

        // Register window class via WINAPI 

        PInvoke.RegisterClassEx(ref wndClassEx);

        // Prepare window basic style flags (WS_*)

        WS style = (WS.WS_POPUP | WS.WS_VISIBLE);

        // Prepare window extended style flags (WS_EX_*)

        WSEx exStyle;

        if (_Topmost)
        {
            if (_AllowPassthrough)
                exStyle = (WSEx.WS_EX_TOPMOST | WSEx.WS_EX_TRANSPARENT | WSEx.WS_EX_LAYERED | WSEx.WS_EX_TOOLWINDOW | WSEx.WS_EX_NOACTIVATE); 
            else
                exStyle = (WSEx.WS_EX_TOPMOST | WSEx.WS_EX_LAYERED | WSEx.WS_EX_TOOLWINDOW | WSEx.WS_EX_NOACTIVATE); 
        }
        else
        {
            if (_AllowPassthrough)
                exStyle = (WSEx.WS_EX_TRANSPARENT | WSEx.WS_EX_LAYERED | WSEx.WS_EX_TOOLWINDOW | WSEx.WS_EX_NOACTIVATE);
            else
                exStyle = (WSEx.WS_EX_LAYERED | WSEx.WS_EX_TOOLWINDOW | WSEx.WS_EX_NOACTIVATE);
        }

        // Create window via WINAPI 

        _WindowHandle = PInvoke.CreateWindowEx(
            (uint)exStyle,
            randomClassName,
            randomWindowName,
            (uint)style, 
            _Position.X, _Position.Y,
            _Size.X, _Size.Y,
            IntPtr.Zero,
            IntPtr.Zero,
            IntPtr.Zero,
            IntPtr.Zero
            );

        // SetLayeredWindowAttributes is required to define transparency 

            // BOOL SetLayeredWindowAttributes( HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);
            // Flag: LWA_ALPHA      0x00000002    Use bAlpha to determine the opacity of the layered window.
            // Flag: LWA_COLORKEY   0x00000001    Use crKey as the transparency color. 

        PInvoke.SetLayeredWindowAttributes(_WindowHandle, 0, 255, 0x2);
        PInvoke.UpdateWindow(_WindowHandle);

Прозрачное самое верхнее окно DirectX 11 хорошо отрисовывается и ведет себя должным образом извизуальная перспектива.

Если я установлю _AllowPassthrough на ИСТИНА, все входные данные будут переданы в основное окно.

Если я установлю _AllowPassthrough на ЛОЖЬ, никакой ввод не будет передан внизв основное окно.

Я использую API-функцию SetWindowsHookEx () для получения низкоуровневой информации о мышке и клавиатуре, но кажется, что когда я вызываю CallNextHookEx () после определения того, что ввод не относится ко мне, он никогда не попадает в основное окно для обработки (если _AllowPassthrough false) или никогда не блокируется / не используется (если _AllowPassthrough true).

Внутри процедуры Hook я либо возвращаю (IntPtr) 1; , чтобы заблокировать дальнейшую обработку, либо возвращаю PInvoke.CallNextHookEx (hookHandle, nCode, wParam, lParam); , чтобы позволить кому-то другомусправитьсяit.

Большинство моих исследований привели меня только к дискуссиям или статьям о полностью оверлейных окнах с «кликом»;не окна, которые частично просматриваются в определенных регионах.

Я предполагаю, что это связано с моей реализацией стиля окна "WS_EX_LAYERED".

Должен ли яискать вариант стиля «WS_EX_NOREDIRECTIONBITMAP» (для использования с механизмом композиции Windows) вместо «WS_EX_LAYERED» (выполнение тестов попадания пикселей на основе SetLayeredWindowAttributes)?

Если это имеет какое-либо значение, я использую sharpDX как моя DirectX библиотека-оболочка.Мой проект построен с использованием VS2017 и с использованием последних спецификаций языка C # в .NET Framework 4.7.1.

РЕДАКТИРОВАНИЕ 19.03.2009:

Так что яЯ сделал несколько обширных проб и ошибок по этому вопросу, и я пришел к выводу, что ....

без WS_LAYERED, тестов ввода / нажатия мыши и т. д. никогда не провалится в основное окно, несмотря ни на что.

с WS_LAYERED, мое окно перестает получать сообщения WM_NCHITTEST или другие сообщения, связанные с курсором.Я могу получить их, используя хук WH_MOUSE_LL (и связанный с ним обработчик сообщений LowLevelMouseProc ()), но используя событие и возвращая ненулевое значение (чтобы «предотвратить передачу системой остальной части цепочки хуков или цели»оконная процедура ") все еще позволяет другим" не связанным с мышью "сообщениям проходить через, так что даже попытка подавить MOUSE_MOVE, потребляя его и используя SetCursorPos () для перемещения курсора, все еще заставляет окно внизу получать уведомление о наведении курсора или мышиболее (я вижу подсветку кнопок и всплывающие подсказки).

Если я не использую SetCursorPos (), мышь заблокируется на месте, поскольку необходимый код для перемещения курсора не видит движения мыши.Я не уверен, что SetCursorPos () вызывает событие MOUSE_MOVE, но я предполагаю, что это не так, поскольку я в любом случае потребляю эти события (и предотвращаю блокировку с помощью проверки "last == current".) Я понятия не имею, чтогенерируются другие системные события.Информация о низкоуровневой природе входной очереди сообщений крайне отсутствует в сети.

Что касается «не-альфа» цветов, то, похоже, это не имеет никакого значения;все окрашенные цвета, независимо от непрозрачности, все еще проходят через ввод мыши.

Я попробовал вышеупомянутый WS_EX_NOREDIRECTIONBITMAP и реорганизовал мой код рендеринга DX, чтобы вместо него использовать Composition Engine, используя хорошо цитируемую статью MSDNКенни Керр в качестве ссылки, и это не имело никакого значения.

Я действительно озадачен этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...