mirror of
https://github.com/kichikuou/system3-sdl2.git
synced 2026-10-12 09:18:21 +03:00
Add texthook option
`-texthook print` prints text to console, and `-texthook copy` automatically copies text to clipboard (for use with text hooker tools). On Windows, copy mode can be toggled from the menu bar.
This commit is contained in:
@@ -118,6 +118,13 @@ tone generator emulation.
|
||||
Specifies the MIDI device number to use. If not specified, the first available
|
||||
device is used.
|
||||
|
||||
#### `-texthook` _mode_
|
||||
Specifies the text hook mode. This option is used for capturing in-game text
|
||||
for translation or other purposes. The available modes are:
|
||||
- `none`: Disable text hooking.
|
||||
- `print`: Print the captured text to the console.
|
||||
- `copy`: Copy the captured text to the clipboard.
|
||||
|
||||
#### `-game` _game_id_
|
||||
As System1-3 have slight variations depending on the game, `system3` uses the
|
||||
fingerprint of the scenario file (ADISK.DAT) to identify the game being played.
|
||||
|
||||
@@ -77,6 +77,21 @@ std::pair<char*, char*> parse_keyval(char *line)
|
||||
return { trim(line), trim(eq + 1) };
|
||||
}
|
||||
|
||||
TexthookMode parse_texthook_mode(const char *s, int lineno = -1)
|
||||
{
|
||||
if (!strcasecmp(s, "none"))
|
||||
return TEXTHOOK_NONE;
|
||||
if (!strcasecmp(s, "print"))
|
||||
return TEXTHOOK_PRINT;
|
||||
if (!strcasecmp(s, "copy"))
|
||||
return TEXTHOOK_COPY;
|
||||
if (lineno == -1)
|
||||
ERROR("Command line: Invalid texthook mode '%s'", s);
|
||||
else
|
||||
ERROR(INIFILENAME ":%d Invalid texthook mode '%s'", lineno, s);
|
||||
return TEXTHOOK_NONE;
|
||||
}
|
||||
|
||||
void init_string(std::string& s, Encoding* encoding, const char *dflt)
|
||||
{
|
||||
char *encoded = encoding->fromUtf8(s.empty() ? dflt : s.c_str());
|
||||
@@ -120,6 +135,8 @@ Config::Config(int argc, char *argv[])
|
||||
title = argv[++i];
|
||||
else if (strcmp(argv[i], "-scanline") == 0)
|
||||
scanline = true;
|
||||
else if (strcmp(argv[i], "-texthook") == 0)
|
||||
texthook_mode = parse_texthook_mode(argv[++i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +195,8 @@ void Config::load_ini()
|
||||
title = val;
|
||||
else if (!strcasecmp(key, "scanline"))
|
||||
scanline = to_bool(val, lineno);
|
||||
else if (!strcasecmp(key, "texthook"))
|
||||
texthook_mode = parse_texthook_mode(val, lineno);
|
||||
else
|
||||
WARNING(INIFILENAME ":%d unknown key '%s'", lineno, key);
|
||||
} else if (current_section == STRING) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define CONFIG_H_
|
||||
|
||||
#include <string>
|
||||
#include "texthook.h"
|
||||
|
||||
class Encoding;
|
||||
|
||||
@@ -32,6 +33,7 @@ struct Config {
|
||||
bool use_fm = false;
|
||||
bool no_antialias = false;
|
||||
bool scanline = false;
|
||||
TexthookMode texthook_mode = TEXTHOOK_NONE;
|
||||
|
||||
private:
|
||||
void load_ini();
|
||||
|
||||
@@ -97,6 +97,8 @@ int main(int argc, char *argv[])
|
||||
EM_ASM( xsystem35.shell.windowSizeChanged(); );
|
||||
#endif
|
||||
|
||||
texthook_set_mode(config.texthook_mode);
|
||||
|
||||
int exit_code = NACT_RESTART;
|
||||
while (exit_code == NACT_RESTART) {
|
||||
exit_code = g_nact->mainloop();
|
||||
|
||||
+129
-43
@@ -1,9 +1,15 @@
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <SDL.h>
|
||||
#include "texthook.h"
|
||||
|
||||
#ifdef __EMSCRIPTEN__ // ----------------------------------------------
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
|
||||
void texthook_set_mode(TexthookMode m) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
void texthook_character(int page, int character) {
|
||||
EM_ASM_({ xsystem35.texthook.message(String.fromCharCode($0), $1); },
|
||||
character, page);
|
||||
@@ -21,59 +27,139 @@ EM_JS(void, texthook_keywait, (void), {
|
||||
xsystem35.texthook.keywait();
|
||||
});
|
||||
|
||||
#elif defined(TEXTHOOK_PRINT) // --------------------------------------
|
||||
#else
|
||||
|
||||
static int newlines = 0;
|
||||
namespace {
|
||||
|
||||
class TextHookHandler {
|
||||
public:
|
||||
virtual void character(int page, int c) = 0;
|
||||
virtual void newline(void) = 0;
|
||||
virtual void nextpage(void) = 0;
|
||||
virtual void keywait(void) = 0;
|
||||
};
|
||||
|
||||
class None : public TextHookHandler {
|
||||
public:
|
||||
void character(int page, int c) override {}
|
||||
void newline(void) override {}
|
||||
void nextpage(void) override {}
|
||||
void keywait(void) override {}
|
||||
} none;
|
||||
|
||||
class Print : public TextHookHandler {
|
||||
public:
|
||||
void character(int page, int c) override {
|
||||
if (newlines)
|
||||
printf("%d:", page);
|
||||
newlines = 0;
|
||||
|
||||
if (c <= 0x7f) {
|
||||
putchar(c);
|
||||
} else if (c <= 0x7ff) {
|
||||
putchar(0xc0 | c >> 6);
|
||||
putchar(0x80 | (c & 0x3f));
|
||||
} else {
|
||||
putchar(0xe0 | c >> 12);
|
||||
putchar(0x80 | (c >> 6 & 0x3f));
|
||||
putchar(0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
void newline(void) override {
|
||||
if (newlines < 2) {
|
||||
putchar('\n');
|
||||
fflush(stdout);
|
||||
newlines++;
|
||||
}
|
||||
}
|
||||
|
||||
void nextpage(void) override {
|
||||
while (newlines < 2) {
|
||||
putchar('\n');
|
||||
fflush(stdout);
|
||||
newlines++;
|
||||
}
|
||||
}
|
||||
|
||||
void keywait(void) override {
|
||||
newline();
|
||||
}
|
||||
|
||||
private:
|
||||
int newlines = 0;
|
||||
} print;
|
||||
|
||||
class Copy : public TextHookHandler {
|
||||
public:
|
||||
void character(int page, int c) override {
|
||||
if (c <= 0x7f) {
|
||||
buf += c;
|
||||
} else if (c <= 0x7ff) {
|
||||
buf += static_cast<char>(0xc0 | c >> 6);
|
||||
buf += static_cast<char>(0x80 | (c & 0x3f));
|
||||
} else {
|
||||
buf += static_cast<char>(0xe0 | c >> 12);
|
||||
buf += static_cast<char>(0x80 | (c >> 6 & 0x3f));
|
||||
buf += static_cast<char>(0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
void newline(void) override {
|
||||
buf += "\n";
|
||||
}
|
||||
|
||||
void nextpage(void) override {
|
||||
if (!buf.empty())
|
||||
copy_to_clipboard();
|
||||
}
|
||||
|
||||
void keywait(void) override {
|
||||
if (!buf.empty())
|
||||
copy_to_clipboard();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string buf;
|
||||
|
||||
void copy_to_clipboard(void) {
|
||||
SDL_SetClipboardText(buf.c_str());
|
||||
buf.clear();
|
||||
}
|
||||
} copy;
|
||||
|
||||
TextHookHandler *handler = &none;
|
||||
|
||||
} // namespace
|
||||
|
||||
void texthook_set_mode(TexthookMode mode) {
|
||||
switch (mode) {
|
||||
case TEXTHOOK_NONE:
|
||||
handler = &none;
|
||||
break;
|
||||
case TEXTHOOK_PRINT:
|
||||
handler = &print;
|
||||
break;
|
||||
case TEXTHOOK_COPY:
|
||||
handler = ©
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void texthook_character(int page, int c) {
|
||||
if (newlines)
|
||||
printf("%d:", page);
|
||||
newlines = 0;
|
||||
|
||||
if (c <= 0x7f) {
|
||||
putchar(c);
|
||||
} else if (c <= 0x7ff) {
|
||||
putchar(0xc0 | c >> 6);
|
||||
putchar(0x80 | (c & 0x3f));
|
||||
} else {
|
||||
putchar(0xe0 | c >> 12);
|
||||
putchar(0x80 | (c >> 6 & 0x3f));
|
||||
putchar(0x80 | (c & 0x3f));
|
||||
}
|
||||
handler->character(page, c);
|
||||
}
|
||||
|
||||
void texthook_newline(void) {
|
||||
if (newlines < 2) {
|
||||
putchar('\n');
|
||||
fflush(stdout);
|
||||
newlines++;
|
||||
}
|
||||
handler->newline();
|
||||
}
|
||||
|
||||
void texthook_nextpage(void) {
|
||||
while (newlines < 2) {
|
||||
putchar('\n');
|
||||
fflush(stdout);
|
||||
newlines++;
|
||||
}
|
||||
handler->nextpage();
|
||||
}
|
||||
|
||||
void texthook_keywait(void) {
|
||||
texthook_newline();
|
||||
handler->keywait();
|
||||
}
|
||||
|
||||
#else // --------------------------------------------------------------
|
||||
|
||||
void texthook_character(int page, int c) {
|
||||
}
|
||||
|
||||
void texthook_newline(void) {
|
||||
}
|
||||
|
||||
void texthook_nextpage(void) {
|
||||
}
|
||||
|
||||
void texthook_keywait(void) {
|
||||
}
|
||||
|
||||
#endif // -------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
enum TexthookMode {
|
||||
TEXTHOOK_NONE,
|
||||
TEXTHOOK_PRINT,
|
||||
TEXTHOOK_COPY,
|
||||
};
|
||||
|
||||
void texthook_set_mode(TexthookMode mode);
|
||||
void texthook_character(int page, int character);
|
||||
void texthook_newline(void);
|
||||
void texthook_nextpage(void);
|
||||
|
||||
+15
-3
@@ -8,12 +8,15 @@
|
||||
#include "ags.h"
|
||||
#include "mako.h"
|
||||
#include "msgskip.h"
|
||||
#include "texthook.h"
|
||||
#include "resource.h"
|
||||
|
||||
extern SDL_Window* g_window;
|
||||
|
||||
namespace {
|
||||
|
||||
bool auto_copy_enabled = false;
|
||||
|
||||
HWND get_hwnd(SDL_Window* window) {
|
||||
SDL_SysWMinfo info;
|
||||
SDL_VERSION(&info.version);
|
||||
@@ -21,15 +24,18 @@ HWND get_hwnd(SDL_Window* window) {
|
||||
return info.info.win.window;
|
||||
}
|
||||
|
||||
void init_menu(bool mouse_move_enabled, bool scanline_enabled)
|
||||
void init_menu(bool mouse_move_enabled, const Config& config)
|
||||
{
|
||||
HINSTANCE hinst = (HINSTANCE)GetModuleHandle(NULL);
|
||||
HMENU hmenu = LoadMenu(hinst, MAKEINTRESOURCE(IDR_MENU1));
|
||||
SetMenu(get_hwnd(g_window), hmenu);
|
||||
if (mouse_move_enabled)
|
||||
CheckMenuItem(hmenu, ID_OPTION_MOUSE_MOVE, MF_BYCOMMAND | MFS_CHECKED);
|
||||
if (scanline_enabled)
|
||||
if (config.scanline)
|
||||
CheckMenuItem(hmenu, ID_SCANLINE, MF_BYCOMMAND | MFS_CHECKED);
|
||||
auto_copy_enabled = config.texthook_mode == TEXTHOOK_COPY;
|
||||
if (auto_copy_enabled)
|
||||
CheckMenuItem(hmenu, ID_TEXT_AUTO_COPY, MF_BYCOMMAND | MFS_CHECKED);
|
||||
}
|
||||
|
||||
void init_console(int sys_ver)
|
||||
@@ -131,7 +137,7 @@ void NACT::text_dialog()
|
||||
|
||||
void NACT::platform_initialize()
|
||||
{
|
||||
init_menu(mouse_move_enabled, config.scanline);
|
||||
init_menu(mouse_move_enabled, config);
|
||||
init_console(sys_ver);
|
||||
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
|
||||
}
|
||||
@@ -217,6 +223,12 @@ bool NACT::handle_platform_event(const SDL_Event& e)
|
||||
CheckMenuItem(GetMenu(get_hwnd(g_window)), ID_TEXT_WAIT, MF_BYCOMMAND |
|
||||
text_wait_enb ? MFS_CHECKED : MFS_UNCHECKED);
|
||||
break;
|
||||
case ID_TEXT_AUTO_COPY:
|
||||
auto_copy_enabled = !auto_copy_enabled;
|
||||
CheckMenuItem(GetMenu(get_hwnd(g_window)), ID_TEXT_AUTO_COPY, MF_BYCOMMAND |
|
||||
auto_copy_enabled ? MFS_CHECKED : MFS_UNCHECKED);
|
||||
texthook_set_mode(auto_copy_enabled ? TEXTHOOK_COPY : TEXTHOOK_NONE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MM_MCINOTIFY:
|
||||
|
||||
@@ -31,5 +31,6 @@
|
||||
#define ID_OPTION_CD 40023
|
||||
#define ID_TEXT_SKIP 40030
|
||||
#define ID_TEXT_WAIT 40031
|
||||
#define ID_TEXT_AUTO_COPY 40032
|
||||
|
||||
#endif // _RESOURCE_H_
|
||||
|
||||
@@ -112,6 +112,7 @@ BEGIN
|
||||
BEGIN
|
||||
MENUITEM "Skip", ID_TEXT_SKIP
|
||||
MENUITEM "Wait", ID_TEXT_WAIT
|
||||
MENUITEM "Auto Copy to Clipboard", ID_TEXT_AUTO_COPY
|
||||
END
|
||||
END
|
||||
|
||||
@@ -170,6 +171,7 @@ BEGIN
|
||||
BEGIN
|
||||
MENUITEM "スキップ", ID_TEXT_SKIP
|
||||
MENUITEM "ウェイトあり", ID_TEXT_WAIT
|
||||
MENUITEM "クリップボードに自動コピー", ID_TEXT_AUTO_COPY
|
||||
END
|
||||
END
|
||||
|
||||
@@ -228,6 +230,7 @@ BEGIN
|
||||
BEGIN
|
||||
MENUITEM "跳过", ID_TEXT_SKIP
|
||||
MENUITEM "等待", ID_TEXT_WAIT
|
||||
MENUITEM "Auto Copy to Clipboard", ID_TEXT_AUTO_COPY
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
@@ -35,6 +35,12 @@ encoding = shift_jis
|
||||
; original Japanese game title will be used.
|
||||
title = Rance 4.1 ~Save the Medicine Plant!~
|
||||
|
||||
; Text hook mode.
|
||||
; none : No text hook (default)
|
||||
; print : Print text to console
|
||||
; copy : Automatically copy text to clipboard (for use with text hooker tools)
|
||||
texthook = none
|
||||
|
||||
; The [string] section allows you to override Japanese text embedded in the
|
||||
; game engine. The values below are the original Japanese text.
|
||||
[string]
|
||||
|
||||
Reference in New Issue
Block a user