没有鼠标的win32,如何为按钮分配键盘快捷键
win32 without mouse, how to assign keyboard shortcuts to buttons
我用纯 C 语言编写了一个简单的 win32 GUI 应用程序,带有按钮和其他控件,没有 MFC。我想让那些不能使用鼠标的人更容易使用它。
首先,我的示例代码不响应 Tab
键将焦点从一个按钮移动到另一个按钮。我可以使用鼠标按下 UI 按钮,然后它会变成焦点,我可以使用 Space-bar
激活按钮,但我无法使用 Tab
或 Shift+Tab
将焦点移动到其他按钮.我该如何解决这个问题?
我想为按钮分配键盘提示(小下划线),以便用户可以使用键盘快捷键激活按钮。
我有 google 它,但答案很难 google,所以我需要有人指点我一些文档。一小段代码会很有帮助。
这是我的代码。我使用 WINE + TinyCC
在 Linux 上编译并 运行 它
#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;
};
P.S。抱歉我的英语不好:)
很简单。在主消息处理循环中,我用适当的 HWND
调用 IsDialogMessage()
。然后,如果此函数 returns 为零,我将调用正常的 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 */
}
window 中的每个按钮都设置了位 WS_TABSTOP
,因此当我按下 Tab
时,IsDialogMessage()
将捕获消息并将焦点移动到下一个按钮。 Editable也可以这样选择。
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 中工作应该没问题。
我用纯 C 语言编写了一个简单的 win32 GUI 应用程序,带有按钮和其他控件,没有 MFC。我想让那些不能使用鼠标的人更容易使用它。
首先,我的示例代码不响应
Tab
键将焦点从一个按钮移动到另一个按钮。我可以使用鼠标按下 UI 按钮,然后它会变成焦点,我可以使用Space-bar
激活按钮,但我无法使用Tab
或Shift+Tab
将焦点移动到其他按钮.我该如何解决这个问题?我想为按钮分配键盘提示(小下划线),以便用户可以使用键盘快捷键激活按钮。
我有 google 它,但答案很难 google,所以我需要有人指点我一些文档。一小段代码会很有帮助。
这是我的代码。我使用 WINE + TinyCC
在 Linux 上编译并 运行 它
#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;
};
P.S。抱歉我的英语不好:)
很简单。在主消息处理循环中,我用适当的 HWND
调用 IsDialogMessage()
。然后,如果此函数 returns 为零,我将调用正常的 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 */
}
window 中的每个按钮都设置了位 WS_TABSTOP
,因此当我按下 Tab
时,IsDialogMessage()
将捕获消息并将焦点移动到下一个按钮。 Editable也可以这样选择。
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 中工作应该没问题。