diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index 3a4a681f9..a78e7fd1e 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -25,19 +25,19 @@ jobs: id: compile env: COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn" - WIN32_FLAGS: "-mwindows -nostartfiles -Wl,-e_main_real -DCC_NOMAIN" + WIN32_FLAGS: "-mwindows -nostartfiles -Wl,-e_main_real -DCC_NOMAIN CCicon_32.res" run: | sudo apt-get -y install gcc-mingw-w64-i686 LATEST_FLAG=-DCC_COMMIT_SHA=\"$(git rev-parse --short "$GITHUB_SHA")\" cp misc/windows/CCicon_32.res src/CCicon_32.res cd src - i686-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN32_FLAGS }} -o cc-w32-d3d9.exe CCicon_32.res $LATEST_FLAG -lwinmm -limagehlp - i686-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN32_FLAGS }} -o cc-w32-ogl.exe CCicon_32.res $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL -lwinmm -limagehlp -lopengl32 - i686-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN32_FLAGS }} -o cc-w32-d3d11.exe CCicon_32.res $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_D3D11 -lwinmm -limagehlp + i686-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN32_FLAGS }} -o cc-w32-d3d9.exe $LATEST_FLAG -lwinmm -limagehlp + i686-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN32_FLAGS }} -o cc-w32-ogl.exe $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL -lwinmm -limagehlp -lopengl32 + i686-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN32_FLAGS }} -o cc-w32-d3d11.exe $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_D3D11 -lwinmm -limagehlp # mingw defaults to i686, but some really old CPUs only support i586 - i686-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN32_FLAGS }} -march=i586 -o cc-w9x-ogl.exe CCicon_32.res $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL -lwinmm -limagehlp -lopengl32 + i686-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN32_FLAGS }} -march=i586 -o cc-w9x-ogl.exe $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL -lwinmm -limagehlp -lopengl32 - uses: ./.github/actions/notify_failure @@ -91,16 +91,16 @@ jobs: id: compile env: COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn" - WIN64_FLAGS: "-mwindows -nostartfiles -Wl,-emain_real -DCC_NOMAIN" + WIN64_FLAGS: "-mwindows -nostartfiles -Wl,-emain_real -DCC_NOMAIN CCicon_64.res" run: | sudo apt-get -y install gcc-mingw-w64-x86-64 LATEST_FLAG=-DCC_COMMIT_SHA=\"$(git rev-parse --short "$GITHUB_SHA")\" cp misc/windows/CCicon_64.res src/CCicon_64.res cd src - x86_64-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN64_FLAGS }} -o cc-w64-d3d9.exe CCicon_64.res $LATEST_FLAG -lwinmm -limagehlp - x86_64-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN64_FLAGS }} -o cc-w64-ogl.exe CCicon_64.res $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_D3D11 -lwinmm -limagehlp -lopengl32 - x86_64-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN64_FLAGS }} -o cc-w64-d3d11.exe CCicon_64.res $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL -lwinmm -limagehlp + x86_64-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN64_FLAGS }} -o cc-w64-d3d9.exe $LATEST_FLAG -lwinmm -limagehlp + x86_64-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN64_FLAGS }} -o cc-w64-ogl.exe $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL -lwinmm -limagehlp -lopengl32 + x86_64-w64-mingw32-gcc *.c ${{ env.COMMON_FLAGS }} ${{ env.WIN64_FLAGS }} -o cc-w64-d3d11.exe $LATEST_FLAG -DCC_GFX_BACKEND=CC_GFX_BACKEND_D3D11 -lwinmm -limagehlp - uses: ./.github/actions/notify_failure diff --git a/src/Window_Terminal.c b/src/Window_Terminal.c index ea6aefc36..c5d5d2229 100644 --- a/src/Window_Terminal.c +++ b/src/Window_Terminal.c @@ -12,26 +12,81 @@ #include #include #include + +#ifdef CC_BUILD_WIN +#include +#else #include #include #include +#endif + #ifdef CC_BUILD_LINUX #include #include #endif +static cc_bool pendingResize, pendingClose; +#define CSI "\x1B[" + +#define ERASE_CMD(cmd) CSI cmd "J" +#define DEC_PM_SET(cmd) CSI "?" cmd "h" +#define DEC_PM_RESET(cmd) CSI "?" cmd "1" + +#ifdef CC_BUILD_WIN +static HANDLE hStdin, hStdout; +static DWORD fdwSaveOldMode; + +static void UpdateDimensions(void) { + CONSOLE_SCREEN_BUFFER_INFO csbi = { 0 }; + int cols, rows; + + GetConsoleScreenBufferInfo(hStdout, &csbi); + cols = csbi.srWindow.Right - csbi.srWindow.Left + 1; + rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + + DisplayInfo.Width = cols; + DisplayInfo.Height = rows * 2; + Window_Main.Width = DisplayInfo.Width; + Window_Main.Height = DisplayInfo.Height; +} + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + +static void HookTerminal(void) { + hStdin = GetStdHandle(STD_INPUT_HANDLE); + hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleMode(hStdin, &fdwSaveOldMode); + + DWORD mode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT; + SetConsoleMode(hStdin, mode); +} + +static void UnhookTerminal(void) { + SetConsoleMode(hStdin, fdwSaveOldMode); +} + +static BOOL WINAPI consoleHandler(DWORD signal) { + if (signal == CTRL_C_EVENT) pendingClose = true; + return true; +} + +static void sigterm_handler(int sig) { pendingClose = true; UnhookTerminal(); } + +static void HookSignals(void) { + SetConsoleCtrlHandler(consoleHandler, TRUE); + + signal(SIGTERM, sigterm_handler); + signal(SIGINT, sigterm_handler); +} +#else // Inspired from https://github.com/Cubified/tuibox/blob/main/tuibox.h#L606 // Uses '▄' to double the vertical resolution // (this trick was inspired from https://github.com/ichinaski/pxl/blob/master/main.go#L30) static struct termios tio; static struct winsize ws; - -#define CSI "\x1B[" - -#define ERASE_CMD(cmd) CSI cmd "J" -#define DEC_PM_SET(cmd) CSI "?" cmd "h" -#define DEC_PM_RESET(cmd) CSI "?" cmd "1" - #ifdef CC_BUILD_LINUX static int orig_KB = K_XLATE; #endif @@ -41,10 +96,6 @@ static void UpdateDimensions(void) { DisplayInfo.Width = ws.ws_col; DisplayInfo.Height = ws.ws_row * 2; - DisplayInfo.Depth = 4; - DisplayInfo.ScaleX = 0.5f; - DisplayInfo.ScaleY = 0.5f; - Window_Main.Width = DisplayInfo.Width; Window_Main.Height = DisplayInfo.Height; } @@ -80,23 +131,28 @@ static void UnhookTerminal(void) { printf(DEC_PM_SET("25")); } -static cc_bool pendingResize, pendingClose; static void sigwinch_handler(int sig) { pendingResize = true; } static void sigterm_handler(int sig) { pendingClose = true; UnhookTerminal(); } -void Window_Init(void) { - Input.Sources = INPUT_SOURCE_NORMAL; - - ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); - //ioctl(STDIN_FILENO , KDGKBMODE, &orig_KB); - //ioctl(STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW); - HookTerminal(); - - UpdateDimensions(); +static void HookSignals(void) { signal(SIGWINCH, sigwinch_handler); signal(SIGTERM, sigterm_handler); signal(SIGINT, sigterm_handler); } +#endif + +void Window_Init(void) { + Input.Sources = INPUT_SOURCE_NORMAL; + DisplayInfo.Depth = 4; + DisplayInfo.ScaleX = 0.5f; + DisplayInfo.ScaleY = 0.5f; + + //ioctl(STDIN_FILENO , KDGKBMODE, &orig_KB); + //ioctl(STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW); + HookTerminal(); + UpdateDimensions(); + HookSignals(); +} void Window_Free(void) { UnhookTerminal(); @@ -145,6 +201,75 @@ void Window_RequestClose(void) { // TODO } +#ifdef CC_BUILD_WIN +static void KeyEventProc(KEY_EVENT_RECORD ker) +{ + printf("Key event: "); + + if(ker.bKeyDown) + printf("key pressed\n"); + else + printf("key released\n"); +} + +static VOID MouseEventProc(MOUSE_EVENT_RECORD mer) { + switch(mer.dwEventFlags) + { + case 0: + if(mer.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED) + { + printf("left button press \n"); + } + else if(mer.dwButtonState == RIGHTMOST_BUTTON_PRESSED) + { + printf("right button press \n"); + } + else + { + printf("button press\n"); + } + break; + case DOUBLE_CLICK: + printf("double click\n"); + break; + case MOUSE_MOVED: + printf("mouse moved\n"); + break; + case MOUSE_WHEELED: + printf("vertical mouse wheel\n"); + break; + default: + printf("unknown\n"); + break; + } +} + +static void ProcessConsoleEvents(float delta) { + DWORD events = 0; + GetNumberOfConsoleInputEvents(hStdin, &events); + if (!events) return; + + INPUT_RECORD buffer[128]; + if (!ReadConsoleInput(hStdin, buffer, 128, &events)) return; + + for (int i = 0; i < events; i++) + { + switch (buffer[i].EventType) + { + case KEY_EVENT: + KeyEventProc(buffer[i].Event.KeyEvent); + break; + case MOUSE_EVENT: + MouseEventProc(buffer[i].Event.MouseEvent); + break; + case WINDOW_BUFFER_SIZE_EVENT: + pendingResize = true; + break; + } + } +} + +#else static int MapNativeMouse(int button) { if (button == 1) return CCMOUSE_L; if (button == 2) return CCMOUSE_M; @@ -164,14 +289,14 @@ static int MapNativeMouse(int button) { } static int stdin_available(void) { - struct pollfd pfd; - pfd.fd = STDIN_FILENO; - pfd.events = POLLIN; + struct pollfd pfd; + pfd.fd = STDIN_FILENO; + pfd.events = POLLIN; - if (poll(&pfd, 1, 0)) { + if (poll(&pfd, 1, 0)) { if (pfd.revents & POLLIN) return 1; - } - return 0; + } + return 0; } #define ExtractXY() \ @@ -181,13 +306,13 @@ static int stdin_available(void) { y = atoi(tok) * 2; static void ProcessMouse(char* buf, int n) { - char cpy[256+2]; + char cpy[256 + 2]; strncpy(cpy, buf, n); char* tok = strtok(cpy + 3, ";"); int x, y, mouse; if (!tok) return; - switch (tok[0]){ + switch (tok[0]){ case '0': mouse = strchr(buf, 'm') == NULL; ExtractXY(); @@ -199,25 +324,61 @@ static void ProcessMouse(char* buf, int n) { ExtractXY(); Pointer_SetPosition(0, x, y); break; - } -} - -static void ProcessKey(int key) { - if (key >= 'a' && key <= 'z') key -= 32; - - if (key >= 'A' && key <= 'Z') { - Input_SetPressed(key); -// Input_SetReleased(key); - } else if (key == ' ') { - Input_SetPressed(CCKEY_SPACE); - Input_SetReleased(CCKEY_SPACE); } } -void Window_ProcessEvents(float delta) { +static int MapKey(int key) { + if (key == ' ') return CCKEY_SPACE; + + if (key >= 'a' && key <= 'z') key -= 32; + if (key >= 'A' && key <= 'Z') return key; + + Platform_Log1("Unknown key: %i", &key); + return 0; +} + +static float event_time; +static float press_start[256]; +static void ProcessKey(int raw) { + int key = MapKey(raw); + if (key) { + Input_SetPressed(key); + press_start[raw] = event_time; + } + + if (raw >= 32 && raw < 127) { + Event_RaiseInt(&InputEvents.Press, raw); + } +} + +static void ProcessConsoleEvents(float delta) { char buf[256]; int n; + + if (!stdin_available()) return; + n = read(STDIN_FILENO, buf, sizeof(buf)); + int A = buf[0]; + //Platform_Log2("IN: %i, %i", &n, &A); + + if (n >= 4 && buf[0] == '\x1b' && buf[1] == '[' && buf[2] == '<') { + ProcessMouse(buf, n); + } else if (buf[0] >= 32 && buf[0] < 127) { + ProcessKey(buf[0]); + } + event_time += delta; + // Auto release keys after a while + for (int i = 0; i < 256; i++) + { + if (press_start[i] && (event_time - press_start[i]) > 1.0f) { + Input_SetReleased(MapKey(i)); + press_start[i] = 0.0f; + } + } +} +#endif + +void Window_ProcessEvents(float delta) { if (pendingResize) { pendingResize = false; UpdateDimensions(); @@ -231,17 +392,7 @@ void Window_ProcessEvents(float delta) { return; } - if (!stdin_available()) return; - n = read(STDIN_FILENO, buf, sizeof(buf)); - int A = buf[0]; - //Platform_Log2("IN: %i, %i", &n, &A); - - if (n >= 4 && buf[0] == '\x1b' && buf[1] == '[' && buf[2] == '<') { - ProcessMouse(buf, n); - } else if (buf[0] >= 32 && buf[0] < 127) { - ProcessKey(buf[0]); - } - // TODO + ProcessConsoleEvents(delta); } void Window_ProcessGamepads(float delta) { } @@ -281,16 +432,22 @@ void Window_AllocFramebuffer(struct Bitmap* bmp) { void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) { for (int y = r.y & ~0x01; y < r.y + r.height; y += 2) - for (int x = r.x; x < r.x + r.width; x++) { - BitmapCol top = Bitmap_GetPixel(bmp, x, y + 0); - BitmapCol bot = Bitmap_GetPixel(bmp, x, y + 1); - - // Use '▄' so each cell can use a background and foreground colour - // This essentially doubles the vertical resolution of the displayed image - printf(CSI "48;2;%i;%i;%im", BitmapCol_R(top), BitmapCol_G(top), BitmapCol_B(top)); - printf(CSI "38;2;%i;%i;%im", BitmapCol_R(bot), BitmapCol_G(bot), BitmapCol_B(bot)); - printf(CSI "%i;%iH\xE2\x96\x84", y / 2, x); + printf(CSI "%i;%iH", y / 2, r.x); // move cursor to start + for (int x = r.x; x < r.x + r.width; x++) + { + BitmapCol top = Bitmap_GetPixel(bmp, x, y + 0); + BitmapCol bot = Bitmap_GetPixel(bmp, x, y + 1); + + // Use '▄' so each cell can use a background and foreground colour + // This essentially doubles the vertical resolution of the displayed image + //printf(CSI "48;2;%i;%i;%im", BitmapCol_R(top), BitmapCol_G(top), BitmapCol_B(top)); + //printf(CSI "38;2;%i;%i;%im", BitmapCol_R(bot), BitmapCol_G(bot), BitmapCol_B(bot)); + //printf("\xE2\x96\x84"); + printf(CSI "48;2;%i;%i;%im" CSI "38;2;%i;%i;%im" "\xE2\x96\x84", + BitmapCol_R(top), BitmapCol_G(top), BitmapCol_B(top), + BitmapCol_R(bot), BitmapCol_G(bot), BitmapCol_B(bot)); + } } }