From 0d8627121cb728c5f621b8ff0f868398417a6d09 Mon Sep 17 00:00:00 2001 From: Daijiro Fukuda Date: Thu, 21 Apr 2022 18:58:21 +0900 Subject: [PATCH] Add IME test code This fix is based on `tests/ime.c` of shibukawa's fix: https://github.com/glfw/glfw/pull/658 https://github.com/shibukawa/glfw-1/commit/d36a164423c933948661f3f17576e5a6388ff251 I simplified and restructured it entirely. --- tests/CMakeLists.txt | 3 +- tests/ime.c | 217 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 tests/ime.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f81cfeb9..9ccabb86 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,6 +28,7 @@ add_executable(iconify iconify.c ${GETOPT} ${GLAD_GL}) add_executable(monitors monitors.c ${GETOPT} ${GLAD_GL}) add_executable(reopen reopen.c ${GLAD_GL}) add_executable(cursor cursor.c ${GLAD_GL}) +add_executable(ime ime.c ${GETOPT} ${GLAD_GL}) add_executable(empty WIN32 MACOSX_BUNDLE empty.c ${TINYCTHREAD} ${GLAD_GL}) add_executable(gamma WIN32 MACOSX_BUNDLE gamma.c ${GLAD_GL}) @@ -51,7 +52,7 @@ endif() set(GUI_ONLY_BINARIES empty gamma icon inputlag joysticks tearing threads timeout title triangle-vulkan window) set(CONSOLE_BINARIES allocator clipboard events msaa glfwinfo iconify monitors - reopen cursor) + reopen cursor ime) set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES C_STANDARD 99 diff --git a/tests/ime.c b/tests/ime.c new file mode 100644 index 00000000..3d4a541b --- /dev/null +++ b/tests/ime.c @@ -0,0 +1,217 @@ +//======================================================================== +// IME test +// Copyright (c) Daijiro Fukuda +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== +// +// This test hooks IME callbacks. +// Left-click clears preedit and toggles IME status. +// Right-click updates preedit cursor position to current cursor position. +// +//======================================================================== + +#define GLAD_GL_IMPLEMENTATION +#include +#define GLFW_INCLUDE_NONE +#include + +#include +#include + +#include "getopt.h" + +void usage(void) +{ + printf("Usage: inputlag [-h] [-f]\n"); + printf("Options:\n"); + printf(" -f create full screen window\n"); + printf(" -h show this help\n"); +} + +static size_t encode_utf8(char* s, unsigned int ch) +{ + size_t count = 0; + + if (ch < 0x80) + s[count++] = (char) ch; + else if (ch < 0x800) + { + s[count++] = (ch >> 6) | 0xc0; + s[count++] = (ch & 0x3f) | 0x80; + } + else if (ch < 0x10000) + { + s[count++] = (ch >> 12) | 0xe0; + s[count++] = ((ch >> 6) & 0x3f) | 0x80; + s[count++] = (ch & 0x3f) | 0x80; + } + else if (ch < 0x110000) + { + s[count++] = (ch >> 18) | 0xf0; + s[count++] = ((ch >> 12) & 0x3f) | 0x80; + s[count++] = ((ch >> 6) & 0x3f) | 0x80; + s[count++] = (ch & 0x3f) | 0x80; + } + + return count; +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + if (action == GLFW_PRESS) { + if (button == GLFW_MOUSE_BUTTON_LEFT) { + int currentIMEstatus = glfwGetInputMode(window, GLFW_IME); + glfwSetInputMode(window, GLFW_IME, !currentIMEstatus); + glfwResetPreeditText(window); + printf("Reset preedit text and IME status -> %s\n", currentIMEstatus ? "OFF" : "ON"); + } else if (button == GLFW_MOUSE_BUTTON_RIGHT) { + int preX, preY; + double curX, curY; + glfwGetPreeditCursorPos(window, &preX, &preY, NULL); + glfwGetCursorPos(window, &curX, &curY); + glfwSetPreeditCursorPos(window, curX, curY, 20); + printf("Move preedit text cursor position (%d, %d) -> (%d, %d)\n", + preX, preY, (int)curX, (int)curY); + } + } +} + +static void char_callback(GLFWwindow* window, unsigned int codepoint) +{ + char string[5] = ""; + + encode_utf8(string, codepoint); + printf("Character 0x%08x (%s) input\n", codepoint, string); +} + +static void preedit_callback(GLFWwindow* window, int strLength, unsigned int* string, int blockLength, int* blocks, int focusedBlock) { + int i, blockIndex = -1, blockCount = 0; + int width, height; + char encoded[5] = ""; + printf("Preedit text "); + if (strLength == 0 || blockLength == 0) { + printf("(empty)\n"); + } else { + for (i = 0; i < strLength; i++) { + if (blockCount == 0) { + if (blockIndex == focusedBlock) { + printf("]"); + } + blockIndex++; + blockCount = blocks[blockIndex]; + printf("\n block %d: ", blockIndex); + if (blockIndex == focusedBlock) { + printf("["); + } + } + encode_utf8(encoded, string[i]); + printf("%s", encoded); + blockCount--; + } + if (blockIndex == focusedBlock) { + printf("]"); + } + printf("\n"); + } +} + +static void ime_callback(GLFWwindow* window) { + int currentIMEstatus = glfwGetInputMode(window, GLFW_IME); + printf("IME switched: %s\n", currentIMEstatus ? "ON" : "OFF"); +} + +int main(int argc, char** argv) +{ + int ch, width, height; + int fullscreen = GLFW_FALSE; + GLFWmonitor* monitor = NULL; + GLFWwindow* window; + + while ((ch = getopt(argc, argv, "fh")) != -1) + { + switch (ch) + { + case 'h': + usage(); + exit(EXIT_SUCCESS); + + case 'f': + fullscreen = GLFW_TRUE; + break; + } + } + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + if (fullscreen) + { + const GLFWvidmode* mode; + + monitor = glfwGetPrimaryMonitor(); + mode = glfwGetVideoMode(monitor); + + width = mode->width; + height = mode->height; + } + else + { + width = 640; + height = 480; + } + + window = glfwCreateWindow(width, height, "IME test", monitor, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwSetMouseButtonCallback(window, mouse_button_callback); + glfwSetCharCallback(window, char_callback); + glfwSetPreeditCallback(window, preedit_callback); + glfwSetIMEStatusCallback(window, ime_callback); + + glfwMakeContextCurrent(window); + gladLoadGL(glfwGetProcAddress); + glfwSwapInterval(1); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); + glfwWaitEvents(); + // Workaround for an issue with msvcrt and mintty + fflush(stdout); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} +