1
0
mirror of https://github.com/DragonMinded/jubeatmenu.git synced 2024-11-14 10:17:36 +01:00

Initial commit of Jubeat menu.

This commit is contained in:
Jennifer Taylor 2019-07-01 22:50:59 -07:00
commit e8d967723d
10 changed files with 1250 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.ncb
*.suo
*.user
Debug/

20
JubeatMenu.sln Normal file
View File

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JubeatMenu", "JubeatMenu\JubeatMenu.vcproj", "{1952667F-999D-4B62-9A06-107541B52B02}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1952667F-999D-4B62-9A06-107541B52B02}.Debug|Win32.ActiveCfg = Debug|Win32
{1952667F-999D-4B62-9A06-107541B52B02}.Debug|Win32.Build.0 = Debug|Win32
{1952667F-999D-4B62-9A06-107541B52B02}.Release|Win32.ActiveCfg = Release|Win32
{1952667F-999D-4B62-9A06-107541B52B02}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

427
JubeatMenu/Display.cpp Normal file
View File

@ -0,0 +1,427 @@
#include <stdio.h>
#include <windows.h>
#include "Display.h"
static Menu *globalMenu;
static bool globalQuit;
static unsigned int globalButtonsHeld;
static unsigned int globalSelected;
static unsigned int globalPage;
static unsigned int globalSeconds;
static const unsigned int SELECTION_MAPPING[12] = {
0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11
};
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
globalQuit = true;
return 0;
case WM_DESTROY:
PostQuitMessage(0);
globalQuit = true;
return 0;
case WM_QUIT:
globalQuit = true;
return 0;
case WM_PAINT:
/* Grab the maximum number of menu items */
unsigned int maxEntries = globalMenu->NumberOfEntries();
/* Start patinting */
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
/* Paint the window background */
HBRUSH background = CreateSolidBrush(RGB(0,0,0));
FillRect(hdc, &ps.rcPaint, background);
DeleteObject(background);
/* Set up text display */
SetTextColor(hdc, RGB(240, 240, 240));
SetBkMode(hdc, TRANSPARENT);
HFONT hItemFont = CreateFont(ITEM_FONT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, L"Verdana");
HFONT hInstructionsFont = CreateFont(INSTRUCTIONS_FONT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, L"Verdana");
HFONT hArrowFont = CreateFont(ARROW_FONT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, L"Verdana");
/* Draw top instructions */
{
RECT rect;
rect.top = VIEWPORT_TOP + TEXT_PADDING;
rect.bottom = VIEWPORT_BOTTOM - TEXT_PADDING;
rect.left = TEXT_PADDING;
rect.right = SCREEN_WIDTH - TEXT_PADDING;
char instruction_text[1024];
sprintf_s(
instruction_text,
1024,
"Select a game by tapping its panel.\n"
"Start %s by tapping the Start Game panel.\n"
"The selected game will auto-start in %d seconds.",
globalMenu->GetEntryName(globalSelected),
globalSeconds
);
wchar_t* wString = new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, instruction_text, -1, wString, 4096);
SelectObject(hdc, hInstructionsFont);
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_LEFT | DT_TOP | DT_WORDBREAK);
delete wString;
}
/* Draw hover icons for every square, regardless of whether we put graphics in them */
for( unsigned int position = 0; position < 15; position++ )
{
unsigned int xPos = position % 4;
unsigned int yPos = position / 4;
/* There is an extra pixel of bump for the second half of the squares */
unsigned int xBump = xPos >= 2 ? 1 : 0;
unsigned int yBump = yPos >= 2 ? 1 : 0;
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * yPos) + yBump;
unsigned int bottom = top + BUTTON_WIDTH;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * xPos) + xBump;
unsigned int right = left + BUTTON_HEIGHT;
/* Set up background colors */
SelectObject(hdc, GetStockObject(DC_BRUSH));
SetDCBrushColor(hdc, RGB(0,0,0));
// Set up border color to show current held buttons
SelectObject(hdc, GetStockObject(DC_PEN));
if ((globalButtonsHeld >> position) & 1)
{
SetDCPenColor(hdc, RGB(255,0,0));
}
else
{
continue;
}
// Draw bounding rectangle
Rectangle(hdc, left, top, right, bottom);
}
/* Draw selection button */
{
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * 3) + 1;
unsigned int bottom = top + BUTTON_WIDTH;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * 3) + 1;
unsigned int right = left + BUTTON_HEIGHT;
SelectObject(hdc, GetStockObject(DC_BRUSH));
SetDCBrushColor(hdc, RGB(24,24,24));
SetDCPenColor(hdc, RGB(255,255,255));
Rectangle(hdc, left, top, right, bottom);
RECT rect;
rect.top = top + TEXT_PADDING;
rect.bottom = bottom - TEXT_PADDING;
rect.left = left + TEXT_PADDING;
rect.right = right - TEXT_PADDING;
char start_text[64];
sprintf_s(start_text, 64, "Start Game\n\n%d seconds left", globalSeconds);
wchar_t* wString = new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, start_text, -1, wString, 4096);
SelectObject(hdc, hItemFont);
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_TOP);
delete wString;
}
/* Draw previous/next page buttons */
if (maxEntries > GAMES_PER_PAGE)
{
unsigned int max_pages = ((maxEntries - GAMES_PER_PAGE) + 2) / 3;
/* Scroll left button */
if (globalPage < max_pages)
{
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * 3) + 1;
unsigned int bottom = top + BUTTON_WIDTH;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * 0) + 1;
unsigned int right = left + BUTTON_HEIGHT;
SelectObject(hdc, GetStockObject(DC_BRUSH));
SetDCBrushColor(hdc, RGB(24,24,24));
if ((globalButtonsHeld >> 12) & 1)
{
SetDCPenColor(hdc, RGB(255,0,0));
}
else
{
SetDCPenColor(hdc, RGB(255,255,255));
}
// Draw bounding rectangle
Rectangle(hdc, left, top, right, bottom);
// Draw text
RECT rect;
rect.top = top + TEXT_PADDING;
rect.bottom = bottom - TEXT_PADDING;
rect.left = left + TEXT_PADDING;
rect.right = right - TEXT_PADDING;
wchar_t* wString = new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, "<<", -1, wString, 4096);
SelectObject(hdc, hArrowFont);
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE);
delete wString;
}
/* Scroll right button */
if (globalPage > 0)
{
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * 3) + 1;
unsigned int bottom = top + BUTTON_WIDTH;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * 1) + 1;
unsigned int right = left + BUTTON_HEIGHT;
SelectObject(hdc, GetStockObject(DC_BRUSH));
SetDCBrushColor(hdc, RGB(24,24,24));
if ((globalButtonsHeld >> 13) & 1)
{
SetDCPenColor(hdc, RGB(255,0,0));
}
else
{
SetDCPenColor(hdc, RGB(255,255,255));
}
// Draw bounding rectangle
Rectangle(hdc, left, top, right, bottom);
// Draw text
RECT rect;
rect.top = top + TEXT_PADDING;
rect.bottom = bottom - TEXT_PADDING;
rect.left = left + TEXT_PADDING;
rect.right = right - TEXT_PADDING;
wchar_t* wString = new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, ">>", -1, wString, 4096);
SelectObject(hdc, hArrowFont);
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE);
delete wString;
}
}
/* Draw each menu item */
for( unsigned int position = 0; position < 12; position++ ) {
unsigned int xPos = position % 4;
unsigned int yPos = position / 4;
/* Look up the actual item at this position */
unsigned int item = SELECTION_MAPPING[position] + (globalPage * 3);
if (item >= maxEntries) { continue; }
/* There is an extra pixel of bump for the second half of the squares */
unsigned int xBump = xPos >= 2 ? 1 : 0;
unsigned int yBump = yPos >= 2 ? 1 : 0;
unsigned int top = BUTTON_TOP + (BUTTON_VERTICAL_STRIDE * yPos) + yBump;
unsigned int bottom = top + BUTTON_WIDTH;
unsigned int left = BUTTON_LEFT + (BUTTON_HORIZONTAL_STRIDE * xPos) + xBump;
unsigned int right = left + BUTTON_HEIGHT;
/* Set up background colors */
SelectObject(hdc, GetStockObject(DC_BRUSH));
if (globalSelected == item)
{
SetDCBrushColor(hdc, RGB(96,96,96));
}
else
{
SetDCBrushColor(hdc, RGB(24,24,24));
}
// Set up border color to show current held buttons
SelectObject(hdc, GetStockObject(DC_PEN));
if ((globalButtonsHeld >> position) & 1)
{
SetDCPenColor(hdc, RGB(255,0,0));
}
else
{
SetDCPenColor(hdc, RGB(255,255,255));
}
// Draw bounding rectangle
Rectangle(hdc, left, top, right, bottom);
// Set text color
SelectObject(hdc, GetStockObject(DC_PEN));
SetDCPenColor(hdc, RGB(255,255,255));
// Draw text
RECT rect;
rect.top = top + TEXT_PADDING;
rect.bottom = bottom - TEXT_PADDING;
rect.left = left + TEXT_PADDING;
rect.right = right - TEXT_PADDING;
wchar_t* wString = new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, globalMenu->GetEntryName(item), -1, wString, 4096);
SelectObject(hdc, hItemFont);
DrawText(hdc, wString, -1, &rect, DT_HIDEPREFIX | DT_CENTER | DT_TOP | DT_WORDBREAK);
delete wString;
}
DeleteObject(hItemFont);
DeleteObject(hInstructionsFont);
DeleteObject(hArrowFont);
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Display::Display(HINSTANCE hInstance, IO *ioInst, Menu *mInst)
{
inst = hInstance;
globalMenu = mInst;
io = ioInst;
menu = mInst;
page = 0;
selected = 0;
// Register the callback
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = inst;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
globalQuit = false;
globalButtonsHeld = 0;
globalSelected = selected;
globalPage = page;
globalSeconds = menu->SecondsLeft();
// Create an empty window
hwnd = CreateWindow(CLASS_NAME, 0, WS_BORDER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, inst, NULL);
LONG lStyle = GetWindowLong(hwnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLong(hwnd, GWL_STYLE, lStyle);
LONG lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle);
/* Display it */
SetWindowPos(hwnd, NULL, 0,0,0,0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
ShowCursor(false);
}
Display::~Display(void)
{
ShowCursor(true);
DestroyWindow(hwnd);
UnregisterClass(CLASS_NAME, inst);
}
void Display::Tick(void)
{
/* Handle windows message pump */
MSG msg = { };
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/* Grab the currently held buttons, calculate newly pressed */
bool moved = false;
unsigned int buttonsHeld = io->ButtonsHeld();
/* Figure out actions */
if (menu->NumberOfEntries() > GAMES_PER_PAGE)
{
unsigned int max_pages = ((menu->NumberOfEntries() - GAMES_PER_PAGE) + 2) / 3;
/* Activate page left/right buttons */
if (io->ButtonPressed(BUTTON_13))
{
/* Scroll left */
if (page < max_pages)
{
page++;
moved = true;
}
}
if (io->ButtonPressed(BUTTON_14))
{
/* Scroll right */
if (page > 0)
{
page--;
moved = true;
}
}
}
if (!moved) {
/* Allow button presses to make selections */
for (unsigned int btn = 0; btn < 12; btn++) {
if (io->ButtonPressed(1 << btn)) {
unsigned int item = SELECTION_MAPPING[btn] + (globalPage * 3);
if (item < menu->NumberOfEntries())
{
selected = item;
}
}
}
}
/* Update the screen to show any button presses or selection
changes. */
bool update = false;
if (globalButtonsHeld != buttonsHeld)
{
globalButtonsHeld = buttonsHeld;
update = true;
}
if (globalSelected != selected)
{
globalSelected = selected;
update = true;
}
if (globalPage != page)
{
globalPage = page;
update = true;
}
if (globalSeconds != menu->SecondsLeft()) {
globalSeconds = menu->SecondsLeft();
update = true;
}
if (update)
{
InvalidateRect(hwnd, NULL, NULL);
UpdateWindow(hwnd);
}
}
bool Display::WasClosed()
{
return globalQuit;
}
unsigned int Display::GetSelectedItem()
{
return selected;
}

56
JubeatMenu/Display.h Normal file
View File

@ -0,0 +1,56 @@
#pragma once
#include <stdio.h>
#include <windows.h>
#include "Menu.h"
#include "IO.h"
#define CLASS_NAME L"Jubeat Touch Launcher"
#define ITEM_FONT_SIZE 20
#define INSTRUCTIONS_FONT_SIZE 28
#define ARROW_FONT_SIZE 40
#define SCREEN_WIDTH 768
#define SCREEN_HEIGHT 1360
#define VIEWPORT_TOP 0
#define VIEWPORT_BOTTOM 463
#define BUTTON_LEFT 8
#define BUTTON_TOP 602
#define BUTTON_WIDTH 159
#define BUTTON_HEIGHT 159
#define BUTTON_HORIZONTAL_STRIDE 197
#define BUTTON_VERTICAL_STRIDE 197
#define TEXT_PADDING 10
/* Number of games to display on one screen */
#define GAMES_PER_PAGE 12
class Display
{
public:
Display(HINSTANCE hInstance, IO *ioInst, Menu *mInst);
~Display(void);
void Tick();
bool WasClosed();
void ButtonPress(int button);
void ButtonRelease(int button);
unsigned int GetSelectedItem();
private:
HINSTANCE inst;
HWND hwnd;
Menu *menu;
IO *io;
unsigned int page;
unsigned int selected;
};

148
JubeatMenu/IO.cpp Normal file
View File

@ -0,0 +1,148 @@
#include "IO.h"
IO::IO()
{
/* Start with not being ready */
is_ready = false;
/* Load the log function so we can output debugging */
log_function = NULL;
core = GetModuleHandleA("avs2-core.dll");
if (core != NULL) {
log_function = (log_func)GetProcAddress(core, "XCgsqzn000017c");
} else {
core = GetModuleHandleA("libavs-win32.dll");
if (core != NULL) {
log_function = (log_func)GetProcAddress(core, "XCd229cc000018");
}
}
debug("Initializing device.dll");
device = GetModuleHandleA("device.dll");
if (device == NULL) {
debug("Missing device.dll. Did you run this from the right directory?");
return;
}
device_initialize = (INT_RET_ONE_ARG) GetProcAddress(device, "device_initialize");
device_is_initialized = (INT_RET_NO_ARGS) GetProcAddress(device, "device_is_initialized");
device_get_status = (INT_RET_NO_ARGS) GetProcAddress(device, "device_get_status");
device_set_panel_mode = (INT_RET_ONE_ARG) GetProcAddress(device, "device_set_panel_mode");
device_get_panel_trg_on = (INT_RET_THREE_ARGS) GetProcAddress(device, "device_get_panel_trg_on");
device_get_panel_trg_off = (INT_RET_THREE_ARGS) GetProcAddress(device, "device_get_panel_trg_off");
device_get_panel_trg_short_on = (INT_RET_THREE_ARGS) GetProcAddress(device, "device_get_panel_trg_short_on");
device_update = (INT_RET_NO_ARGS) GetProcAddress(device, "device_update");
device_finalize = (INT_RET_NO_ARGS) GetProcAddress(device, "device_finalize");
if (
device_initialize == NULL ||
device_is_initialized == NULL ||
device_get_status == NULL ||
device_set_panel_mode == NULL ||
device_update == NULL ||
device_get_panel_trg_on == NULL ||
device_get_panel_trg_off == NULL ||
device_get_panel_trg_short_on == NULL ||
device_finalize == NULL
) {
debug("Couldn't find correct functions to call! Did you use the right DLLs?");
FreeLibrary(device);
return;
}
// First, initialize and verify.
debug("Initializing P4IO device");
device_initialize(0);
if (!device_is_initialized()) {
debug("Couldn't initialize P4IO device");
FreeLibrary(device);
return;
}
if (device_get_status() < 0) {
debug("P4IO device status returns error!");
FreeLibrary(device);
return;
}
// Configure to read panels
debug("Configuring P4IO driver");
device_set_panel_mode(0);
// We're ready to roll
debug("P4IO driver ready for input");
is_ready = true;
buttons = 0;
lastButtons = 0;
}
IO::~IO(void)
{
if (!is_ready) { return; }
debug("Finalizing P4IO driver");
device_finalize();
FreeLibrary(device);
}
bool IO::Ready()
{
return is_ready;
}
void IO::ErrorMessage(char *msg)
{
debug(msg);
}
void IO::Tick()
{
if (!is_ready) { return; }
if(device_is_initialized()) {
device_update();
}
// Remember last buttons so we can calculate newly
// pressed buttons.
lastButtons = buttons;
for (int panel = 0; panel < 16; panel++) {
int output[2] = { 0 };
device_get_panel_trg_on(panel % 4, panel / 4, output);
if (output[0] != 0) {
// Track the button release
buttons &= ~(1 << panel);
}
device_get_panel_trg_off(panel % 4, panel / 4, output);
if (output[0] != 0) {
// Track the button press
buttons |= (1 << panel);
}
}
}
unsigned int IO::ButtonsHeld()
{
return buttons;
}
bool IO::ButtonHeld(unsigned int button)
{
return (ButtonsHeld() & button) != 0;
}
unsigned int IO::ButtonsPressed()
{
return buttons & (~lastButtons);
}
bool IO::ButtonPressed(unsigned int button)
{
return (ButtonsPressed() & button) != 0;
}

67
JubeatMenu/IO.h Normal file
View File

@ -0,0 +1,67 @@
#pragma once
#include <tchar.h>
#include <windows.h>
// Types and setup for logging to AVS standard output.
typedef int (*log_func)(char *cat, char *fmt, ...);
// Types for interacting with device.dll
typedef int(*INT_RET_NO_ARGS)();
typedef int(*INT_RET_ONE_ARG)(int in);
typedef int(*INT_RET_THREE_ARGS)(int x, int y, int *out);
// Debug that outputs to AVS logs.
#define debug(...) do { if (log_function != NULL) { log_function("menu", __VA_ARGS__); } } while(0)
// Button definitions
#define BUTTON_1 0x0001
#define BUTTON_2 0x0002
#define BUTTON_3 0x0004
#define BUTTON_4 0x0008
#define BUTTON_5 0x0010
#define BUTTON_6 0x0020
#define BUTTON_7 0x0040
#define BUTTON_8 0x0080
#define BUTTON_9 0x0100
#define BUTTON_10 0x0200
#define BUTTON_11 0x0400
#define BUTTON_12 0x0800
#define BUTTON_13 0x1000
#define BUTTON_14 0x2000
#define BUTTON_15 0x4000
#define BUTTON_16 0x8000
class IO
{
public:
IO();
~IO(void);
bool Ready();
void Tick();
void ErrorMessage(char *msg);
unsigned int ButtonsHeld();
unsigned int ButtonsPressed();
bool ButtonHeld(unsigned int button);
bool ButtonPressed(unsigned int button);
private:
HMODULE core;
HMODULE device;
INT_RET_ONE_ARG device_initialize;
INT_RET_NO_ARGS device_is_initialized;
INT_RET_NO_ARGS device_get_status;
INT_RET_ONE_ARG device_set_panel_mode;
INT_RET_THREE_ARGS device_get_panel_trg_on;
INT_RET_THREE_ARGS device_get_panel_trg_off;
INT_RET_THREE_ARGS device_get_panel_trg_short_on;
INT_RET_NO_ARGS device_update;
INT_RET_NO_ARGS device_finalize;
log_func log_function;
bool is_ready;
unsigned int buttons;
unsigned int lastButtons;
};

116
JubeatMenu/JubeatMenu.cpp Normal file
View File

@ -0,0 +1,116 @@
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <tchar.h>
#include "Display.h"
#include "Menu.h"
#include "IO.h"
// Instance for passing to a window we render
static HMODULE globalModule = NULL;
static Menu *globalMenu = NULL;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
/* Remember our own instance*/
globalModule = hModule;
/* Load the original DLL to force dependencies to load.
This must be done BEFORE calling dll_entry_init or
this menu can't be run with a hook DLL. */
LoadLibraryA("jubeat.dll");
/* Initialize the menu before any hooks run so our
file operations don't get intercepted. */
globalMenu = new Menu(L"games.ini");
}
return TRUE;
}
extern "C" __declspec(dllexport) int __cdecl dll_entry_init(int a1, int a2)
{
// Initialize the IO
IO *io = new IO();
if (!io->Ready())
{
// Failed to initialize, give up
ExitProcess(0);
return 0;
}
// Initialize the menu
Menu *menu = globalMenu;
if( menu->NumberOfEntries() < 1 )
{
io->ErrorMessage("No games configured to launch in games.ini!");
delete menu;
delete io;
ExitProcess(0);
return 0;
}
// Create menu screen
Display *display = new Display(globalModule, io, menu);
/* Actual game to load */
char *path = NULL;
/* It may have taken a long time to init */
menu->ResetTimeout();
// Input loop
while(true) {
io->Tick();
menu->Tick();
display->Tick();
/* See if somebody killed the display window */
if (display->WasClosed())
{
io->ErrorMessage("Main window closed, exiting!");
break;
}
/* Check to see if we ran out of time waiting for input */
if (menu->ShouldBootDefault())
{
io->ErrorMessage("Ran out of time, booting current selection!");
int entry = display->GetSelectedItem();
path = menu->GetEntryPath(entry);
break;
}
/* Check to see if the user confirmed a selection */
if (io->ButtonPressed(BUTTON_16)) {
int entry = display->GetSelectedItem();
path = menu->GetEntryPath(entry);
break;
}
}
// Close and free libraries
delete display;
delete menu;
delete io;
if (path != NULL)
{
/* Launch actual game */
system(path);
}
// Return failure so launcher.exe doesn't attempt to
// further initialize other threads such as the net thread.
ExitProcess(0);
return 0;
}
extern "C" __declspec(dllexport) int __cdecl dll_entry_main()
{
return 0;
}

View File

@ -0,0 +1,217 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="JubeatMenu"
ProjectGUID="{1952667F-999D-4B62-9A06-107541B52B02}"
RootNamespace="JubeatMenu"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="false"
BasicRuntimeChecks="3"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="0"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\Display.cpp"
>
</File>
<File
RelativePath=".\IO.cpp"
>
</File>
<File
RelativePath=".\JubeatMenu.cpp"
>
</File>
<File
RelativePath=".\Menu.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\Display.h"
>
</File>
<File
RelativePath=".\IO.h"
>
</File>
<File
RelativePath=".\Menu.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

155
JubeatMenu/Menu.cpp Normal file
View File

@ -0,0 +1,155 @@
#include <stdio.h>
#include <windows.h>
#include "Menu.h"
Menu::Menu(_TCHAR *inifile)
{
/* Read settings */
settings = LoadSettings( inifile, &num_programs );
/* For exiting on defaults */
ftime(&beginning);
}
Menu::~Menu(void)
{
}
void Menu::ResetTimeout()
{
ftime(&beginning);
}
void Menu::Tick()
{
ftime(&current);
}
bool Menu::ShouldBootDefault()
{
ftime(&current);
return (current.time - beginning.time) > TIMEOUT_SECONDS;
}
unsigned int Menu::SecondsLeft()
{
ftime(&current);
int seconds = (int)(TIMEOUT_SECONDS - (current.time - beginning.time));
return seconds >= 0 ? seconds : 0;
}
/**
* Loads an INI file with the following format:
*
* [Name of game to launch]
* launch=<location of batch/executable>
*/
launcher_program_t *Menu::LoadSettings( _TCHAR *ini_file, unsigned int *final_length )
{
launcher_program_t *progs = 0;
*final_length = 0;
unsigned int got_name = 0;
launcher_program_t temp;
// Open the file
HANDLE hFile = CreateFile(ini_file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
char buffer[16384];
unsigned int eof = 0;
unsigned int eol = 0;
unsigned int buflen = 0;
if (hFile == 0)
{
return progs;
}
memset( &temp, 0, sizeof(temp) );
memset( buffer, 0, sizeof(buffer) );
while( !eof )
{
DWORD length;
ReadFile( hFile, buffer + buflen, 1, &length, 0 );
if (length == 0)
{
eof = 1;
eol = 1;
}
else if( *(buffer + buflen) == '\r' )
{
/* Ignore \r completely */
*(buffer + buflen) = 0;
}
else if( *(buffer + buflen) == '\n' )
{
/* End of line */
*(buffer + buflen) = 0;
eol = 1;
}
else
{
/* Valid thing */
buflen++;
}
if ( eol == 1 )
{
/* Process line */
if (buffer[0] == '[' && buffer[buflen - 1] == ']' && buflen > 2)
{
buffer[buflen - 1] = 0;
char *game = buffer + 1;
/* Copy this into temp structure */
strcpy_s( temp.name, MAX_GAME_NAME_LENGTH, game );
got_name = 1;
}
else
{
if (strncmp(buffer, "launch", 6) == 0) {
unsigned int loc = 6;
// Find equals sign after space
while (loc < buflen && (buffer[loc] == ' ' || buffer[loc] == '\t')) { loc++; }
if (loc < buflen)
{
if (buffer[loc] == '=')
{
loc++;
while (loc < buflen && (buffer[loc] == ' ' || buffer[loc] == '\t')) { loc++; }
if (loc < buflen)
{
char *launch = buffer + loc;
if( got_name == 1 )
{
/* We have a name to associate with this */
strcpy_s( temp.location, MAX_GAME_LOCATION_LENGTH, launch );
got_name = 0;
/* Make a new spot for this, copy in */
(*final_length)++;
progs = (launcher_program_t *)realloc( progs, sizeof(launcher_program_t) * (*final_length) );
memcpy( progs + ((*final_length) - 1), &temp, sizeof(launcher_program_t) );
memset( &temp, 0, sizeof(temp) );
}
}
}
}
}
}
/* Reset buffer */
if (buflen > 0)
{
memset( buffer, 0, sizeof(buffer) );
buflen = 0;
}
/* Not end of line anymore */
eol = 0;
}
}
return progs;
}

40
JubeatMenu/Menu.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include <tchar.h>
#include <sys/timeb.h>
/* Seconds to wait for a selection before booting the default option */
#define TIMEOUT_SECONDS 60
/* Constants for limitations on how long INI file pieces can be */
#define MAX_GAME_NAME_LENGTH 63
#define MAX_GAME_LOCATION_LENGTH 511
typedef struct
{
char location[MAX_GAME_LOCATION_LENGTH + 1];
char name[MAX_GAME_NAME_LENGTH + 1];
} launcher_program_t;
class Menu
{
public:
Menu(_TCHAR *inifile);
~Menu(void);
unsigned int NumberOfEntries() { return num_programs; }
char *GetEntryName(unsigned int game) { return settings[game].name; }
char *GetEntryPath(unsigned int game) { return settings[game].location; }
void Tick();
void ResetTimeout();
bool ShouldBootDefault();
unsigned int SecondsLeft();
private:
unsigned int num_programs;
launcher_program_t *settings;
struct timeb beginning;
struct timeb current;
launcher_program_t *LoadSettings( _TCHAR *ini_file, unsigned int *final_length );
};