Ускорители клавиатуры Windows и дочерние окна

Я создал программу с графическим интерфейсом Windows, используя C и Windows API, и хочу, чтобы программа использовала ускорители клавиатуры. Я настроил некоторые ускорители, которые работают правильно, но когда фокус переходит к дочернему окну главного окна моей программы, например элементу управления списком или строке состояния, кажется, что клавиатурные ускорители переводятся в сообщения WM_COMMAND для дочерних окон, а не главного окна. Из-за этого моя обработка соответствующих сообщений WM_COMMAND в WndProc главного окна игнорируется, когда фокус находится на дочернем элементе управления.

Как мне решить эту проблему?

2 ответа

Решение

Я нашел ответ. Дочерние окна главного окна должны быть разделены на подклассы, чтобы сообщения WM_COMMAND, генерируемые ускорителями клавиатуры, могли быть перехвачены и переданы в родительское окно.

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

Оконную процедуру можно изменить с помощью SetWindowLongPtr с GWLP_WNDPROC.

Вот простой пример того, как сделать это путем сохранения указателя на исходную оконную процедуру в значении пользовательских данных элемента управления (GWLP_USERDATA):

Код для изменения процедуры окна и сохранения исходной процедуры в GWLP_USERDATA:

SetWindowLongPtr( hWnd, GWLP_USERDATA, ( LONG_PTR )SetWindowLongPtr( hWnd, GWLP_WNDPROC, ( LONG_PTR )WndProc ) );

Процедура перехватывающего окна:

static LRESULT CALLBACK WndProc( const HWND hWnd, const UINT message, const WPARAM wParam, const LPARAM lParam )
{
    switch( message )
    {
        case WM_COMMAND:
            SendMessage( GetParent( hWnd ), message, wParam, lParam );
            return 0;
        default:
        //Assume that GWLP_USERDATA has been set to the original window procedure.
            return CallWindowProc( ( WNDPROC )GetWindowLongPtr( hWnd, GWLP_USERDATA ), hWnd, message, wParam, lParam );
    }
}

Другой способ - избегать использования TranslateAccelerator для дочернего окна, пример кода:

if (mainWidget() && msg.hwnd == mainWidget()->hwnd()) {
            if (TranslateAccelerator(msg.hwnd, hMainAccelTable, &msg)) {
                continue;
            }
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);

если сообщение не относится к mainWidget, мы не переводим ускоритель для него, используя таблицу ускорителей основного виджета.

Другие вопросы по тегам