diff --git a/configure.ac b/configure.ac index 5ee97d10..8c1d2184 100644 --- a/configure.ac +++ b/configure.ac @@ -58,7 +58,7 @@ AC_CHECK_LIB([pthread], [pthread_create], AC_CHECK_LIB([vulkan], [vkGetInstanceProcAddr], [], [AC_MSG_ERROR([libvulkan not found.])]) -PKG_CHECK_MODULES([XCB], [xcb], [], [AC_MSG_ERROR[libxcb not found.]]) +PKG_CHECK_MODULES([XCB], [xcb xcb-keysyms], [], [AC_MSG_ERROR[libxcb and/or libxcb-keysyms not found.]]) dnl Check for functions VKD3D_CHECK_SYNC_ADD_AND_FETCH_FUNC diff --git a/demos/demo.h b/demos/demo.h index ccac8d4a..1f8d7c5f 100644 --- a/demos/demo.h +++ b/demos/demo.h @@ -41,9 +41,13 @@ #define WIDL_C_INLINE_WRAPPERS #define COBJMACROS #include +#include #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) +#define DEMO_KEY_UNKNOWN 0x0000 +#define DEMO_KEY_ESCAPE 0xff1b + struct demo_vec3 { float x, y, z; @@ -62,6 +66,8 @@ struct demo_swapchain_desc DXGI_FORMAT format; }; +typedef uint32_t demo_key; + static inline void demo_rasterizer_desc_init_default(D3D12_RASTERIZER_DESC *desc) { desc->FillMode = D3D12_FILL_MODE_SOLID; diff --git a/demos/demo_win32.h b/demos/demo_win32.h index 1537a180..e74cf1d4 100644 --- a/demos/demo_win32.h +++ b/demos/demo_win32.h @@ -44,6 +44,7 @@ struct demo_window struct demo *demo; void *user_data; void (*draw_func)(void *user_data); + void (*key_press_func)(struct demo_window *window, demo_key key, void *user_data); }; struct demo_swapchain @@ -74,6 +75,7 @@ static inline struct demo_window *demo_window_create(struct demo *demo, const ch window->instance = GetModuleHandle(NULL); window->draw_func = draw_func; window->user_data = user_data; + window->key_press_func = NULL; style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE; AdjustWindowRect(&rect, style, FALSE); @@ -101,6 +103,13 @@ static inline void demo_window_destroy(struct demo_window *window) free(window); } +static inline demo_key demo_key_from_vkey(DWORD vkey) +{ + if (vkey == VK_ESCAPE) + return DEMO_KEY_ESCAPE; + return DEMO_KEY_UNKNOWN; +} + static inline LRESULT CALLBACK demo_window_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { struct demo_window *window = (void *)GetWindowLongPtrW(hwnd, GWLP_USERDATA); @@ -112,6 +121,12 @@ static inline LRESULT CALLBACK demo_window_proc(HWND hwnd, UINT message, WPARAM window->draw_func(window->user_data); return 0; + case WM_KEYDOWN: + if (!window->key_press_func) + break; + window->key_press_func(window, demo_key_from_vkey(wparam), window->user_data); + return 0; + case WM_DESTROY: window->hwnd = NULL; demo_window_destroy(window); @@ -121,6 +136,12 @@ static inline LRESULT CALLBACK demo_window_proc(HWND hwnd, UINT message, WPARAM return DefWindowProcW(hwnd, message, wparam, lparam); } +static inline void demo_window_set_key_press_func(struct demo_window *window, + void (*key_press_func)(struct demo_window *window, demo_key key, void *user_data)) +{ + window->key_press_func = key_press_func; +} + static inline void demo_process_events(struct demo *demo) { MSG msg = {0}; diff --git a/demos/demo_xcb.h b/demos/demo_xcb.h index fe0aa92a..dccd1936 100644 --- a/demos/demo_xcb.h +++ b/demos/demo_xcb.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ struct demo xcb_connection_t *connection; xcb_atom_t wm_protocols_atom; xcb_atom_t wm_delete_window_atom; + xcb_key_symbols_t *xcb_keysyms; struct demo_window **windows; size_t windows_size; @@ -48,6 +50,7 @@ struct demo_window void *user_data; void (*draw_func)(void *user_data); + void (*key_press_func)(struct demo_window *window, demo_key key, void *user_data); }; struct demo_swapchain @@ -131,7 +134,7 @@ static inline struct demo_window *demo_find_window(struct demo *demo, xcb_window static inline struct demo_window *demo_window_create(struct demo *demo, const char *title, unsigned int width, unsigned int height, void (*draw_func)(void *user_data), void *user_data) { - static const uint32_t window_events = XCB_EVENT_MASK_EXPOSURE; + static const uint32_t window_events = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS; struct demo_window *window; xcb_size_hints_t hints; @@ -150,6 +153,7 @@ static inline struct demo_window *demo_window_create(struct demo *demo, const ch window->demo = demo; window->draw_func = draw_func; window->user_data = user_data; + window->key_press_func = NULL; screen = xcb_setup_roots_iterator(xcb_get_setup(demo->connection)).data; xcb_create_window(demo->connection, XCB_COPY_FROM_PARENT, window->window, screen->root, 0, 0, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, @@ -181,16 +185,23 @@ static inline void demo_window_destroy(struct demo_window *window) free(window); } +static inline void demo_window_set_key_press_func(struct demo_window *window, + void (*key_press_func)(struct demo_window *window, demo_key key, void *user_data)) +{ + window->key_press_func = key_press_func; +} + static inline void demo_process_events(struct demo *demo) { - const xcb_client_message_event_t *client_message; + const struct xcb_client_message_event_t *client_message; + struct xcb_key_press_event_t *key_press; xcb_generic_event_t *event; struct demo_window *window; - bool done = false; + xcb_keysym_t sym; xcb_flush(demo->connection); - while (!done && (event = xcb_wait_for_event(demo->connection))) + while (demo->window_count && (event = xcb_wait_for_event(demo->connection))) { switch (XCB_EVENT_RESPONSE_TYPE(event)) { @@ -199,16 +210,20 @@ static inline void demo_process_events(struct demo *demo) window->draw_func(window->user_data); break; + case XCB_KEY_PRESS: + key_press = (struct xcb_key_press_event_t *)event; + if (!(window = demo_find_window(demo, key_press->event)) || !window->key_press_func) + break; + sym = xcb_key_press_lookup_keysym(demo->xcb_keysyms, key_press, 0); + window->key_press_func(window, sym, window->user_data); + break; + case XCB_CLIENT_MESSAGE: client_message = (xcb_client_message_event_t *)event; if (client_message->type == demo->wm_protocols_atom && client_message->data.data32[0] == demo->wm_delete_window_atom && (window = demo_find_window(demo, client_message->window))) - { demo_window_destroy(window); - if (!demo->window_count) - done = true; - } break; } @@ -226,6 +241,8 @@ static inline bool demo_init(struct demo *demo) goto fail; if ((demo->wm_protocols_atom = demo_get_atom(demo->connection, "WM_PROTOCOLS")) == XCB_NONE) goto fail; + if (!(demo->xcb_keysyms = xcb_key_symbols_alloc(demo->connection))) + goto fail; demo->windows = NULL; demo->windows_size = 0; @@ -241,6 +258,7 @@ fail: static inline void demo_cleanup(struct demo *demo) { free(demo->windows); + xcb_key_symbols_free(demo->xcb_keysyms); xcb_disconnect(demo->connection); } diff --git a/demos/triangle.c b/demos/triangle.c index 381c7a24..7a07eb37 100644 --- a/demos/triangle.c +++ b/demos/triangle.c @@ -358,6 +358,12 @@ static void cxt_load_assets(struct cx_triangle *cxt) cxt_wait_for_previous_frame(cxt); } +static void cxt_key_press(struct demo_window *window, demo_key key, void *user_data) +{ + if (key == DEMO_KEY_ESCAPE) + demo_window_destroy(window); +} + static int cxt_main(void) { unsigned int width = 640, height = 480; @@ -370,6 +376,7 @@ static int cxt_main(void) cxt.window = demo_window_create(&cxt.demo, "Vkd3d Triangle", width, height, cxt_render_frame, &cxt); + demo_window_set_key_press_func(cxt.window, cxt_key_press); cxt.width = width; cxt.height = height;