win32 без мышки, как назначить сочетания клавиш на кнопки - PullRequest
0 голосов
/ 28 апреля 2020

Я написал простое приложение win32 GUI с кнопками и другими элементами управления, в чистом виде C, без MF C. Я хочу сделать его более доступным для тех, кто не может использовать мышь.

  1. Во-первых, мой пример кода не отвечает на клавишу Tab для перемещения фокуса с одной кнопки на другую. Я могу нажать кнопку пользовательского интерфейса с помощью мыши, после чего она становится сфокусированной, и я могу активировать кнопку с помощью Space-bar, но я не могу переместить фокус на другие кнопки с помощью Tab или Shift+Tab. Как я могу это исправить?

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

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

Вот код, который у меня есть. Я компилирую и запускаю его на Linux, используя WINE + Tiny CC


#include <stdio.h>
#include <windows.h>

/* Yeres distributed forums node v0001 */

/* compile: wine tcc_win/tcc/tcc.exe win_yeres */


HWND status_text_hwnd = NULL;
HWND shutdown_hs_button_hwnd = NULL;

unsigned int button_height = 26;
unsigned int window_length = 400;
#define V_BUTTON_PADDING 2

int tor_running = 0;
int select_running = 0;


#include "yeres_bind.c"
#include "win_yeres_w1_proc.c"


int APIENTRY WinMain(
        HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow
        ) {

  MSG msg;
  WNDCLASS wc;
  HWND hwnd;

  printf("\n  **  YERES v0001  **\n\n");


  // Fill in window class structure with parameters that describe
  // the main window.

  ZeroMemory(&wc, sizeof wc);
  wc.hInstance     = hInstance;
  wc.lpszClassName = "yeres_wcl";
  wc.lpfnWndProc   = (WNDPROC)w1_proc;
  wc.style         = CS_DBLCLKS|CS_VREDRAW|CS_HREDRAW;
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 0);
  wc.hIcon         = LoadIcon(NULL, IDI_EXCLAMATION);
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);

  if (FALSE == RegisterClass(&wc)) return 0;

  RECT client_rect;
  client_rect.left = 0;
  client_rect.top = 0;
  client_rect.right = window_length;
  client_rect.bottom = 500;

  /* calculate window size from known client area size */
  if (0 == AdjustWindowRect(&client_rect, wc.style, 0)) return 0;

  // create main window
  hwnd = CreateWindow(
    "yeres_wcl",
    "YERES control panel",
    WS_OVERLAPPEDWINDOW|WS_VISIBLE,
    30,
    30,
    client_rect.right,   //CW_USEDEFAULT
    client_rect.bottom,
    0,
    0,
    hInstance,
    0);

  if (NULL == hwnd) return 0;

  // Main message loop:
  while (GetMessage(&msg, NULL, 0, 0) > 0) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  return msg.wParam;
}

#define ID_TOR_CONTROL_PORT 1
#define ID_BIND 2
#define ID_UNBIND 3
#define ID_TOR_SHUTDOWN_HS 4
#define ID_PORT_NUM 5
#define ID_QUIT 6


LRESULT CALLBACK w1_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

  int y = 4;
  int x;
  RECT rc;
  switch (message) {

    case WM_CREATE:

    ZeroMemory(&rc, sizeof(rc));
    GetClientRect(hwnd, &rc);
    if (rc.right) window_length = rc.right - rc.left;

    status_text_hwnd = CreateWindow("Static",
                "** YERES v0001 **\n\nPress 'Bind to localhost'..",
                WS_CHILD | WS_VISIBLE | SS_CENTER,
                3, y, window_length, (button_height * 3),
                hwnd, (HMENU) 1, NULL, NULL);
    y += button_height * 3;

    x = 2;
    CreateWindow("Static", "Port:",
                WS_CHILD | WS_VISIBLE | SS_CENTER,
                x, y, 60, button_height,
                hwnd, (HMENU) 1, NULL, NULL);
    x += 60;
    /* editable field here */
    CreateWindow("Edit", "19407", 
                WS_CHILD | WS_VISIBLE | WS_BORDER,
                x, y, 90, button_height, hwnd, (HMENU) ID_PORT_NUM,
                NULL, NULL);
    x += 120;

    CreateWindow("Button", "Bind to localhost",
                WS_VISIBLE | WS_CHILD ,
                x, y, 140, button_height,
                hwnd, (HMENU) ID_BIND, NULL, NULL);
    x += 140;
    CreateWindow("Button", "Unbind",
                WS_VISIBLE | WS_CHILD ,
                x, y, window_length - 2 - x, button_height,
                hwnd, (HMENU) ID_UNBIND, NULL, NULL);

    y += button_height + V_BUTTON_PADDING;

    CreateWindow("Button", "Use tor control port to start HiddenService",
                WS_VISIBLE | WS_CHILD ,
                2, y, window_length - 4, button_height,
                hwnd, (HMENU) ID_TOR_CONTROL_PORT, NULL, NULL);
    y += button_height + V_BUTTON_PADDING;

    shutdown_hs_button_hwnd = CreateWindow("Button", "Shutdown HiddenService",
                WS_VISIBLE | WS_CHILD ,
                2, y, window_length - 4, button_height,
                hwnd, (HMENU) ID_TOR_SHUTDOWN_HS, NULL, NULL);
    EnableWindow(shutdown_hs_button_hwnd, 0); /* inactive button */
    y += button_height + V_BUTTON_PADDING;

    CreateWindow("Button", "Shutdown EVERYTHING and QUIT",
                WS_VISIBLE | WS_CHILD ,
                2, y, window_length - 4, button_height,
                hwnd, (HMENU) ID_QUIT, NULL, NULL);
    y += button_height + V_BUTTON_PADDING;

    break;

    case WM_DESTROY:
    if (!tor_running && !select_running) PostQuitMessage(0);
    break;


    case WM_COMMAND:
    switch (LOWORD(wParam)) {
      case ID_BIND:
      yeres_bind();
      break;

      case ID_QUIT:
      PostQuitMessage(0);
      break;

      default: DefWindowProc(hwnd, message, wParam, lParam);
    }
    break;

    default:
    return DefWindowProc(hwnd, message, wParam, lParam);

  };
  return 0;
};

PS Извините, мой плохой Engli sh:)

1 Ответ

0 голосов
/ 29 апреля 2020

Это было просто. В обработке основного сообщения l oop, я звоню IsDialogMessage() с правильным HWND. Затем, если эта функция возвращает ноль, я вызываю обычные функции TranslateMessage и DispatchMessage. Вот код:

while(GetMessage(&msg, NULL, 0, 0) > 0) {
  if(!IsDialogMessage(hwnd, &msg)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  };

  yeres_select(); /* scan incoming connections on sockets using select(), activated by timer and/or other messages */

}

Для каждой кнопки в окне установлен бит WS_TABSTOP, поэтому, когда я нажимаю Tab, IsDialogMessage() перехватит сообщение и переместит фокус на следующую кнопку. Редактируемый также может быть выбран таким образом.

WS_GROUP не работал для меня. В теории это должно позволить мне перемещаться с помощью клавиш со стрелками. Я поместил бит WS_GROUP в первую кнопку.

CreateWindow("Button", "&Bind to localhost",
            WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP,
            x, y, 140, button_height,
            hwnd, (HMENU) ID_BIND, NULL, NULL);

Мнемоника амперсанда работает даже без вызова TranslateAccelerator(), просто поместите его в текст метки "&Bind to localhost", и кнопку можно активировать с помощью Alt+B или так. Он не чувствителен к регистру.

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

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