diff --git a/binding-mri/journal-binding.cpp b/binding-mri/journal-binding.cpp index 96fc713..3a2744b 100644 --- a/binding-mri/journal-binding.cpp +++ b/binding-mri/journal-binding.cpp @@ -11,6 +11,7 @@ static SDL_Thread *thread = NULL; static SDL_mutex *mutex = NULL; static volatile char message_buffer[OUT_BUFFER_SIZE]; static volatile int message_len = 0; +static volatile bool active = false; int server_thread(void *data) { @@ -27,6 +28,7 @@ int server_thread(void *data) ConnectNamedPipe(pipe, NULL); SDL_LockMutex(mutex); WriteFile(pipe, (const void*)message_buffer, OUT_BUFFER_SIZE, NULL, NULL); + active = true; SDL_UnlockMutex(mutex); FlushFileBuffers(pipe); DisconnectNamedPipe(pipe); @@ -59,6 +61,7 @@ RB_METHOD(journalSet) message_len = len; SDL_UnlockMutex(mutex); if (pipe != INVALID_HANDLE_VALUE) { + active = true; WriteFile(pipe, (const void*)message_buffer, OUT_BUFFER_SIZE, NULL, NULL); FlushFileBuffers(pipe); CloseHandle(pipe); @@ -67,10 +70,16 @@ RB_METHOD(journalSet) return Qnil; } +RB_METHOD(journalActive) +{ + return active ? Qtrue : Qfalse; +} + void journalBindingInit() { mutex = SDL_CreateMutex(); VALUE module = rb_define_module("Journal"); _rb_define_module_function(module, "set", journalSet); + _rb_define_module_function(module, "active?", journalActive); } diff --git a/journal/journal.cpp b/journal/journal.cpp index 7540b9d..9a05369 100644 --- a/journal/journal.cpp +++ b/journal/journal.cpp @@ -1,169 +1,170 @@ -#include - -#define DEFAULT_WIDTH 800 -#define DEFAULT_HEIGHT 600 -#define IN_BUFFER_SIZE 256 - -static const WCHAR journal_classname[] = L"journal"; - -static HBITMAP image_handle = NULL; -static HANDLE image_mutex = NULL; - -static HWND window = NULL; - -static void loadImage(const char *name) { - if (image_handle) { - DeleteObject(image_handle); - } - image_handle = LoadBitmapA(GetModuleHandleW(NULL), name); -} - -// Window procedure -LRESULT CALLBACK journal_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_PAINT: { - PAINTSTRUCT ps; - HDC hdc; - HDC hdcMem; - - WaitForSingleObject(image_mutex, INFINITE); - hdc = BeginPaint(hwnd, &ps); - hdcMem = CreateCompatibleDC(hdc); - HANDLE oldBitmap = SelectObject(hdcMem, image_handle); - BitBlt(hdc, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, hdcMem, 0, 0, SRCCOPY); - SelectObject(hdcMem, oldBitmap); - DeleteDC(hdcMem); - EndPaint(hwnd, &ps); - ReleaseMutex(image_mutex); - } break; - - default: - return DefWindowProc(hwnd, msg, wParam, lParam); - } - return 0; -} - -// IPC thread -#include -DWORD WINAPI ipc_thread(LPVOID lpParam) -{ - (void)lpParam; - - char message[IN_BUFFER_SIZE]; - DWORD len; - - HANDLE pipe = CreateNamedPipeW(L"\\\\.\\pipe\\oneshot-game-to-journal", - PIPE_ACCESS_INBOUND, - PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - IN_BUFFER_SIZE, - IN_BUFFER_SIZE, - 0, - NULL); - - for (;;) { - if (!ConnectNamedPipe(pipe, NULL)) - continue; - for (;;) { - if (ReadFile(pipe, (void*)message, IN_BUFFER_SIZE, &len, NULL) - && len == IN_BUFFER_SIZE) - { - WaitForSingleObject(image_mutex, INFINITE); - if (strcmp(message, "default") == 0) { - exit(0); - } - loadImage(message); - InvalidateRect(window, NULL, FALSE); - ReleaseMutex(image_mutex); - } else { - break; - } - } - DisconnectNamedPipe(pipe); - } - - CloseHandle(pipe); - - return 0; -} - -int do_journal() -{ - // Create - HINSTANCE module = GetModuleHandleW(NULL); - - loadImage("default"); - - // Initial image - char message[IN_BUFFER_SIZE]; - DWORD len; - HANDLE pipe = CreateFileW(L"\\\\.\\pipe\\oneshot-journal-to-game", - GENERIC_READ, - 0, - NULL, - OPEN_EXISTING, - 0, - NULL); - if (pipe != INVALID_HANDLE_VALUE) { - if (ReadFile(pipe, (void*)message, IN_BUFFER_SIZE, &len, NULL) - && len == IN_BUFFER_SIZE) - { - loadImage(message); - } - CloseHandle(pipe); - } - - WNDCLASSEXW wc; - wc.cbSize = sizeof(wc); - wc.style = 0; - wc.lpfnWndProc = journal_proc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = module; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - wc.lpszClassName = journal_classname; - wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - - if (!RegisterClassEx(&wc)) - return 1; - - if (!(window = CreateWindowExW(WS_EX_COMPOSITED | WS_EX_LAYERED | WS_EX_TOPMOST, - journal_classname, - L"", - WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME | WS_MAXIMIZEBOX), - CW_USEDEFAULT, CW_USEDEFAULT, - DEFAULT_WIDTH, DEFAULT_HEIGHT, - NULL, NULL, module, NULL))) { - return 1; - } - - SetLayeredWindowAttributes(window, RGB(0, 255, 0), 0, LWA_COLORKEY); - - ShowWindow(window, SW_SHOWNOACTIVATE); - UpdateWindow(window); - - image_mutex = CreateMutexW(NULL, NULL, NULL); - HANDLE thread = CreateThread(NULL, 0, ipc_thread, NULL, 0, NULL); - - // Dispatch messages - for (;;) { - MSG msg; - if (GetMessage(&msg, window, 0, 0) > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } else { - break; - } - } - - // TODO make this less messy? - TerminateThread(thread, 0); - - DestroyWindow(window); - - return 0; -} +#include + +#define DEFAULT_WIDTH 800 +#define DEFAULT_HEIGHT 600 +#define IN_BUFFER_SIZE 256 + +static const WCHAR journal_classname[] = L"journal"; + +static HBITMAP image_handle = NULL; +static HANDLE image_mutex = NULL; + +static HWND window = NULL; + +static void loadImage(const char *name) { + if (image_handle) { + DeleteObject(image_handle); + } + image_handle = LoadBitmapA(GetModuleHandleW(NULL), name); +} + +// Window procedure +LRESULT CALLBACK journal_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_PAINT: { + PAINTSTRUCT ps; + HDC hdc; + HDC hdcMem; + + WaitForSingleObject(image_mutex, INFINITE); + hdc = BeginPaint(hwnd, &ps); + hdcMem = CreateCompatibleDC(hdc); + HANDLE oldBitmap = SelectObject(hdcMem, image_handle); + BitBlt(hdc, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, hdcMem, 0, 0, SRCCOPY); + SelectObject(hdcMem, oldBitmap); + DeleteDC(hdcMem); + EndPaint(hwnd, &ps); + ReleaseMutex(image_mutex); + } break; + + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + +// IPC thread +#include +DWORD WINAPI ipc_thread(LPVOID lpParam) +{ + (void)lpParam; + + char message[IN_BUFFER_SIZE]; + DWORD len; + + HANDLE pipe = CreateNamedPipeW(L"\\\\.\\pipe\\oneshot-game-to-journal", + PIPE_ACCESS_INBOUND, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + IN_BUFFER_SIZE, + IN_BUFFER_SIZE, + 0, + NULL); + + for (;;) { + if (!ConnectNamedPipe(pipe, NULL)) + continue; + for (;;) { + if (ReadFile(pipe, (void*)message, IN_BUFFER_SIZE, &len, NULL) + && len == IN_BUFFER_SIZE) + { + WaitForSingleObject(image_mutex, INFINITE); + if (*message == 0) { + exit(0); + } + loadImage(message); + InvalidateRect(window, NULL, FALSE); + ReleaseMutex(image_mutex); + } else { + break; + } + } + DisconnectNamedPipe(pipe); + } + + CloseHandle(pipe); + + return 0; +} + +int do_journal() +{ + // Create + HINSTANCE module = GetModuleHandleW(NULL); + + loadImage("default"); + + // Initial image + char message[IN_BUFFER_SIZE]; + DWORD len; + HANDLE pipe = CreateFileW(L"\\\\.\\pipe\\oneshot-journal-to-game", + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + if (pipe != INVALID_HANDLE_VALUE) { + if (ReadFile(pipe, (void*)message, IN_BUFFER_SIZE, &len, NULL) + && len == IN_BUFFER_SIZE) + { + if (*message) + loadImage(message); + } + CloseHandle(pipe); + } + + WNDCLASSEXW wc; + wc.cbSize = sizeof(wc); + wc.style = 0; + wc.lpfnWndProc = journal_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = module; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = journal_classname; + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + if (!RegisterClassEx(&wc)) + return 1; + + if (!(window = CreateWindowExW(WS_EX_COMPOSITED | WS_EX_LAYERED | WS_EX_TOPMOST, + journal_classname, + L"", + WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME | WS_MAXIMIZEBOX), + CW_USEDEFAULT, CW_USEDEFAULT, + DEFAULT_WIDTH, DEFAULT_HEIGHT, + NULL, NULL, module, NULL))) { + return 1; + } + + SetLayeredWindowAttributes(window, RGB(0, 255, 0), 0, LWA_COLORKEY); + + ShowWindow(window, SW_SHOWNOACTIVATE); + UpdateWindow(window); + + image_mutex = CreateMutexW(NULL, NULL, NULL); + HANDLE thread = CreateThread(NULL, 0, ipc_thread, NULL, 0, NULL); + + // Dispatch messages + for (;;) { + MSG msg; + if (GetMessage(&msg, window, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + break; + } + } + + // TODO make this less messy? + TerminateThread(thread, 0); + + DestroyWindow(window); + + return 0; +} diff --git a/journal/main.cpp b/journal/main.cpp index 28e46e7..1cca126 100644 --- a/journal/main.cpp +++ b/journal/main.cpp @@ -1,27 +1,27 @@ -#include - -extern int do_niko(int x, int y); -extern int do_journal(); - -int WINAPI WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - (void)hInstance; - (void)hPrevInstance; - (void)lpCmdLine; - (void)nCmdShow; - - int argc; - LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc); - - // argc == 3, assume niko - if (argc == 3) { - int x = _wtoi(argv[1]); - int y = _wtoi(argv[2]); - return do_niko(x, y); - } - // assume journal - return do_journal(); -} +#include + +extern int do_niko(int x, int y); +extern int do_journal(); + +int WINAPI WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + (void)hInstance; + (void)hPrevInstance; + (void)lpCmdLine; + (void)nCmdShow; + + int argc; + LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc); + + // argc == 3, assume niko + if (argc == 3) { + int x = _wtoi(argv[1]); + int y = _wtoi(argv[2]); + return do_niko(x, y); + } + // assume journal + return do_journal(); +} diff --git a/journal/niko.cpp b/journal/niko.cpp index af195a0..62a9555 100644 --- a/journal/niko.cpp +++ b/journal/niko.cpp @@ -1,130 +1,130 @@ -#include - -static const WCHAR niko_classname[] = L"niko"; -static HWND niko = NULL; -static HBITMAP niko_bmps[3] = {NULL}; -static int niko_offset = 0; - -// Window procedure -LRESULT CALLBACK niko_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_CLOSE: - return 0; - - case WM_PAINT: { - static int frame = 0; - if (niko_offset % 32 >= 16) { - frame = 1; - } else { - if ((niko_offset / 32) % 2) - frame = 0; - else - frame = 2; - } - - PAINTSTRUCT ps; - HDC hdc; - BITMAP bitmap; - HDC hdcMem; - HGDIOBJ oldBitmap; - - hdc = BeginPaint(hwnd, &ps); - - hdcMem = CreateCompatibleDC(hdc); - oldBitmap = SelectObject(hdcMem, niko_bmps[frame]); - - GetObject(niko_bmps[frame], sizeof(bitmap), &bitmap); - BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY); - - SelectObject(hdcMem, oldBitmap); - DeleteDC(hdcMem); - - EndPaint(hwnd, &ps); - } - break; - - default: - return DefWindowProc(hwnd, msg, wParam, lParam); - } - return 0; -} - -int do_niko(int x, int y) -{ - // Create - HINSTANCE module = GetModuleHandleW(NULL); - niko_bmps[0] = LoadBitmapW(module, L"NIKO1"); - niko_bmps[1] = LoadBitmapW(module, L"NIKO2"); - niko_bmps[2] = LoadBitmapW(module, L"NIKO3"); - - WNDCLASSEXW wc; - wc.cbSize = sizeof(wc); - wc.style = 0; - wc.lpfnWndProc = niko_proc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = module; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - wc.lpszClassName = niko_classname; - wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - - if (!RegisterClassEx(&wc)) - return 1; - - if (!(niko = CreateWindowExW(WS_EX_COMPOSITED | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW, - niko_classname, - L"Niko", - WS_POPUP, - x, y, - 24 * 2, 32 * 2, - NULL, NULL, module, NULL))) { - return 1; - } - - SetLayeredWindowAttributes(niko, RGB(0, 255, 0), 0, LWA_COLORKEY); - - ShowWindow(niko, SW_SHOWNOACTIVATE); - UpdateWindow(niko); - - // Thread - int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); - - // Get starting position - RECT area; - GetWindowRect(niko, &area); - - // Just keep walking down - for (;;) { - // Dispatch messages - unsigned long tick = GetTickCount(); - for (;;) { - MSG msg; - if (PeekMessage(&msg, niko, 0, 0, PM_REMOVE) > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } else { - if (GetTickCount() - tick >= 1000 / 60) - break; - } - } - - niko_offset += 2; - if (area.top + niko_offset >= screenHeight) - break; - SetWindowPos(niko, NULL, area.left, area.top + niko_offset, 0, 0, SWP_NOSIZE); - InvalidateRect(niko, NULL, FALSE); - } - - DestroyWindow(niko); - - for (int i = 0; i < 3; i++) { - if (niko_bmps[i]) - DeleteObject(niko_bmps[i]); - } - - return 0; -} +#include + +static const WCHAR niko_classname[] = L"niko"; +static HWND niko = NULL; +static HBITMAP niko_bmps[3] = {NULL}; +static int niko_offset = 0; + +// Window procedure +LRESULT CALLBACK niko_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_CLOSE: + return 0; + + case WM_PAINT: { + static int frame = 0; + if (niko_offset % 32 >= 16) { + frame = 1; + } else { + if ((niko_offset / 32) % 2) + frame = 0; + else + frame = 2; + } + + PAINTSTRUCT ps; + HDC hdc; + BITMAP bitmap; + HDC hdcMem; + HGDIOBJ oldBitmap; + + hdc = BeginPaint(hwnd, &ps); + + hdcMem = CreateCompatibleDC(hdc); + oldBitmap = SelectObject(hdcMem, niko_bmps[frame]); + + GetObject(niko_bmps[frame], sizeof(bitmap), &bitmap); + BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY); + + SelectObject(hdcMem, oldBitmap); + DeleteDC(hdcMem); + + EndPaint(hwnd, &ps); + } + break; + + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + +int do_niko(int x, int y) +{ + // Create + HINSTANCE module = GetModuleHandleW(NULL); + niko_bmps[0] = LoadBitmapW(module, L"NIKO1"); + niko_bmps[1] = LoadBitmapW(module, L"NIKO2"); + niko_bmps[2] = LoadBitmapW(module, L"NIKO3"); + + WNDCLASSEXW wc; + wc.cbSize = sizeof(wc); + wc.style = 0; + wc.lpfnWndProc = niko_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = module; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = niko_classname; + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + if (!RegisterClassEx(&wc)) + return 1; + + if (!(niko = CreateWindowExW(WS_EX_COMPOSITED | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW, + niko_classname, + L"Niko", + WS_POPUP, + x, y, + 24 * 2, 32 * 2, + NULL, NULL, module, NULL))) { + return 1; + } + + SetLayeredWindowAttributes(niko, RGB(0, 255, 0), 0, LWA_COLORKEY); + + ShowWindow(niko, SW_SHOWNOACTIVATE); + UpdateWindow(niko); + + // Thread + int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + // Get starting position + RECT area; + GetWindowRect(niko, &area); + + // Just keep walking down + for (;;) { + // Dispatch messages + unsigned long tick = GetTickCount(); + for (;;) { + MSG msg; + if (PeekMessage(&msg, niko, 0, 0, PM_REMOVE) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + if (GetTickCount() - tick >= 1000 / 60) + break; + } + } + + niko_offset += 2; + if (area.top + niko_offset >= screenHeight) + break; + SetWindowPos(niko, NULL, area.left, area.top + niko_offset, 0, 0, SWP_NOSIZE); + InvalidateRect(niko, NULL, FALSE); + } + + DestroyWindow(niko); + + for (int i = 0; i < 3; i++) { + if (niko_bmps[i]) + DeleteObject(niko_bmps[i]); + } + + return 0; +}