Почему мой низкоуровневый крюк для клавиш Windows перестает работать? - PullRequest
0 голосов
/ 27 января 2012

Это продолжение моего первоначального вопроса Почему D3D10SDKLayers.dll загружается во время моей игры DX11? Я создаю игру DX11 и использую низкоуровневую клавишу Windows для захвата клавиш Alt + Enterчто я могу переключаться в полноэкранный режим, используя свои собственные методы, вместо того, чтобы Windows делала это автоматически, что неизбежно вызывает проблемы.Описание этого процесса и подробности доступны в связанном вопросе.Моя проблема в том, что перехват клавиш последовательно перестает работать после 6-го Alt + Enter по какой-то причине.Я не отменяю это сам.

Вот код подключения ключа:


LRESULT _stdcall MyClass::WindowsKeyHook( s32 nCode, WPARAM wParam, LPARAM lParam ) {
    printf("Key hook called, nCode: %d. ", nCode);
    if( nCode < 0 || nCode != HC_ACTION )  { // do not process message 
        return CallNextHookEx( MyClassVar.GetWindowsKeyHook(), nCode, wParam, lParam );
    }
    printf(" Key hook status ok.\n");

    BOOL bEatKeystroke = FALSE;
    KBDLLHOOKSTRUCT* p = ( KBDLLHOOKSTRUCT* )lParam;
    switch( wParam ) {
        //NOTE: Alt seems to be a system key when it is PRESSED, but a regular key when it is released...
        case WM_SYSKEYDOWN:
            if(p->vkCode == VK_MENU || p->vkCode == VK_LMENU || p->vkCode == VK_RMENU) {
                MyClassVar.SetAltPressed(TRUE);
            }
            if(MyClassVar.IsAltPressed() && p->vkCode == VK_RETURN) {
                bEatKeystroke = TRUE;
                MyClassVar.SetAltEnterUsed(TRUE);
                printf("Alt+Enter used.\n");
            }
            break;
        case WM_SYSKEYUP:
            //NOTE: releasing alt+enter causes a SYSKEYUP message with code 0x13: PAUSE key...
            break;
        case WM_KEYDOWN:
            break;
        case WM_KEYUP: {
            if(p->vkCode == VK_MENU || p->vkCode == VK_LMENU || p->vkCode == VK_RMENU) {
                MyClassVar.SetAltPressed(FALSE);
            }
            bEatKeystroke = ( !MyClassVar.IsShortcutKeysAllowed() &&
                                ( p->vkCode == VK_LWIN || p->vkCode == VK_RWIN ) );
            break;
        }
    }

    if( bEatKeystroke ) {
        return 1;
    }
    else {
        return CallNextHookEx( MyClassVar.GetWindowsKeyHook(), nCode, wParam, lParam );
    }
}

Если вам нужна дополнительная информация, просто скажите мне, что нужно.Я понятия не имею, почему это происходит, поэтому я не уверен, какую информацию мне нужно предоставить.Насколько я знаю, единственный способ избавиться от зацепки для ключей, кроме того, чтобы отменить ее явную регистрацию, - это если Windows сделает это тайм-аут.Все методы MyClassVar встроены, чтобы быть максимально быстрыми, а Alt + Enter обрабатывается из отдельного потока.

Ответы [ 2 ]

2 голосов
/ 27 января 2012

Единственный способ избавиться от зацепки для ключей, кроме отмены ее явной регистрации, - это, если Windows истечет время ожидания, насколько я знаю.

Это было бы правильно, и вы могли быбыть в состоянии подтвердить время ожидания путем временного увеличения ключа реестра LowLevelHooksTimeout .

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

Из вашего комментария звучит так, будто вы хотите выбрать полноэкранное разрешение, когда DXGI переключается в полноэкранный режим дляyou.

Ниже приводится выдержка из Графическая инфраструктура DirectX (DXGI): Best Practices .Эта информация может помочь, а может и не помочь, так же как и содержание, которое я выбрал до этого отрывка, в котором говорится о WM_SIZE.

Методология предыдущего объяснения следует очень специфическому пути.DXGI по умолчанию устанавливает полноэкранное разрешение на разрешение рабочего стола.Однако многие приложения переключаются на предпочитаемое полноэкранное разрешение.В таком случае DXGI обеспечивает IDXGISwapChain::ResizeTarget.Это следует вызывать перед вызовом SetFullscreenState.Хотя эти методы можно вызывать в обратном порядке (сначала SetFullscreenState, а затем ResizeTarget), в результате этого приложению отправляется дополнительное сообщение WM_SIZE.(Это также может вызвать мерцание, поскольку DXGI может быть вынужден выполнить два изменения режима.) После вызова SetFullscreenState рекомендуется снова вызвать ResizeTarget с обнуленным членом RefreshRate.Это равносильно тому, что в DXGI отсутствует инструкция без операций, но можно избежать проблем с частотой обновления, которые обсуждаются далее.

В DXGI Overview есть еще немного информации оважно, что ResizeTarget может быть не таким полезным, как можно было бы надеяться:

По умолчанию DXGI выбирает вывод, который содержит большую часть клиентской области окна.Это единственная опция, доступная DXGI, когда он откроется в полноэкранном режиме в ответ на alt-enter.

Однако в нем упоминается, что размер определяется клиентской областью окна.Возможно, вы хотите ограничить клиентскую область , вместо того, чтобы устанавливать клавиатуру?

1 голос
/ 12 июня 2012

Вы пытались отключить хук DXGI?

IDXGISwapChain::MakeWindowAssociation( DXGI_MWA_NO_WINDOW_CHANGES )

Кроме того, создание цепочки обмена с DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH приведет к тому, что DXGI найдет режим отображения, наиболее соответствующий размеру вашего окна. Если вы уже изменили ResizeTarget () на 640x480, и доступен хотя бы какой-то режим 640x480, вы должны его получить. Затем вы получите WM_SIZE до 640x480, что дает вам возможность вызвать ResizeBuffers. если ResizeBuffers вызывается так, то после переключения режима он включит перелистывание страниц (новые обратные буферы должны быть связаны с монитором, или система не может напрямую переворачивать страницы). Если перелистывание страниц не включено таким образом, то все вызовы Present будут вызывать операцию blt, которая будет высасывать пропускную способность, которую вам не нужно тратить.

Обратите внимание, что вы можете или не можете получить 640x480. Например, если повернуть дисплей, вы получите следующий самый большой режим, который будет содержать 640x480, который, вероятно, будет 768x1024. Если вы хотите хорошо работать на повернутых дисплеях, вы можете следить за этим и самим использовать почтовый ящик с соотношением сторон 4x3.

Но, как правило, лучше разрешить DXGI выбирать режим отображения, потому что есть много причин, по которым режим рабочего стола может быть лучшим. Пользователь мог подключить компьютер к проектору, который может работать только в одном режиме. Некоторые ЖК-дисплеи отображают разрешение 640x480 в собственном разрешении, то есть маленькую почтовую марку в центре монитора. В идеале, вы должны написать свое приложение, чтобы оно выглядело практически при любом разрешении, но, по крайней мере, с соотношением сторон 4x3, 3x4, 6x9 и 9x6.

Удачного кодирования -Джефф

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