diff --git a/core/core_bind.compat.inc b/core/core_bind.compat.inc index 3e8ac3c5de6..22c78623dab 100644 --- a/core/core_bind.compat.inc +++ b/core/core_bind.compat.inc @@ -44,11 +44,16 @@ void Semaphore::_bind_compatibility_methods() { // OS +String OS::_read_string_from_stdin_bind_compat_91201() { + return read_string_from_stdin(1024); +} + Dictionary OS::_execute_with_pipe_bind_compat_94434(const String &p_path, const Vector &p_arguments) { return execute_with_pipe(p_path, p_arguments, true); } void OS::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin"), &OS::_read_string_from_stdin_bind_compat_91201); ClassDB::bind_compatibility_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434); } diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 967a7fba757..925551d933f 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -308,8 +308,24 @@ Error OS::shell_show_in_file_manager(const String &p_path, bool p_open_folder) { return ::OS::get_singleton()->shell_show_in_file_manager(p_path, p_open_folder); } -String OS::read_string_from_stdin() { - return ::OS::get_singleton()->get_stdin_string(); +String OS::read_string_from_stdin(int64_t p_buffer_size) { + return ::OS::get_singleton()->get_stdin_string(p_buffer_size); +} + +PackedByteArray OS::read_buffer_from_stdin(int64_t p_buffer_size) { + return ::OS::get_singleton()->get_stdin_buffer(p_buffer_size); +} + +OS::StdHandleType OS::get_stdin_type() const { + return (OS::StdHandleType)::OS::get_singleton()->get_stdin_type(); +} + +OS::StdHandleType OS::get_stdout_type() const { + return (OS::StdHandleType)::OS::get_singleton()->get_stdout_type(); +} + +OS::StdHandleType OS::get_stderr_type() const { + return (OS::StdHandleType)::OS::get_singleton()->get_stderr_type(); } int OS::execute(const String &p_path, const Vector &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) { @@ -633,7 +649,13 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_system_font_path", "font_name", "weight", "stretch", "italic"), &OS::get_system_font_path, DEFVAL(400), DEFVAL(100), DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_system_font_path_for_text", "font_name", "text", "locale", "script", "weight", "stretch", "italic"), &OS::get_system_font_path_for_text, DEFVAL(String()), DEFVAL(String()), DEFVAL(400), DEFVAL(100), DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path); - ClassDB::bind_method(D_METHOD("read_string_from_stdin"), &OS::read_string_from_stdin); + + ClassDB::bind_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin); + ClassDB::bind_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin); + ClassDB::bind_method(D_METHOD("get_stdin_type"), &OS::get_stdin_type); + ClassDB::bind_method(D_METHOD("get_stdout_type"), &OS::get_stdout_type); + ClassDB::bind_method(D_METHOD("get_stderr_type"), &OS::get_stderr_type); + ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL_ARRAY, DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("execute_with_pipe", "path", "arguments", "blocking"), &OS::execute_with_pipe, DEFVAL(true)); ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false)); @@ -725,6 +747,12 @@ void OS::_bind_methods() { BIND_ENUM_CONSTANT(SYSTEM_DIR_MUSIC); BIND_ENUM_CONSTANT(SYSTEM_DIR_PICTURES); BIND_ENUM_CONSTANT(SYSTEM_DIR_RINGTONES); + + BIND_ENUM_CONSTANT(STD_HANDLE_INVALID); + BIND_ENUM_CONSTANT(STD_HANDLE_CONSOLE); + BIND_ENUM_CONSTANT(STD_HANDLE_FILE); + BIND_ENUM_CONSTANT(STD_HANDLE_PIPE); + BIND_ENUM_CONSTANT(STD_HANDLE_UNKNOWN); } ////// Geometry2D ////// diff --git a/core/core_bind.h b/core/core_bind.h index 3ae54017fe5..d013e348bd8 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -134,6 +134,7 @@ protected: #ifndef DISABLE_DEPRECATED Dictionary _execute_with_pipe_bind_compat_94434(const String &p_path, const Vector &p_arguments); + String _read_string_from_stdin_bind_compat_91201(); static void _bind_compatibility_methods(); #endif @@ -148,6 +149,14 @@ public: PackedByteArray get_entropy(int p_bytes); String get_system_ca_certificates(); + enum StdHandleType { + STD_HANDLE_INVALID, + STD_HANDLE_CONSOLE, + STD_HANDLE_FILE, + STD_HANDLE_PIPE, + STD_HANDLE_UNKNOWN, + }; + virtual PackedStringArray get_connected_midi_inputs(); virtual void open_midi_inputs(); virtual void close_midi_inputs(); @@ -168,7 +177,13 @@ public: String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const; Vector get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const; String get_executable_path() const; - String read_string_from_stdin(); + + String read_string_from_stdin(int64_t p_buffer_size = 1024); + PackedByteArray read_buffer_from_stdin(int64_t p_buffer_size = 1024); + StdHandleType get_stdin_type() const; + StdHandleType get_stdout_type() const; + StdHandleType get_stderr_type() const; + int execute(const String &p_path, const Vector &p_arguments, Array r_output = ClassDB::default_array_arg, bool p_read_stderr = false, bool p_open_console = false); Dictionary execute_with_pipe(const String &p_path, const Vector &p_arguments, bool p_blocking = true); int create_process(const String &p_path, const Vector &p_arguments, bool p_open_console = false); @@ -644,6 +659,7 @@ VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags); VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver); VARIANT_ENUM_CAST(core_bind::OS::SystemDir); +VARIANT_ENUM_CAST(core_bind::OS::StdHandleType); VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation); VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType); diff --git a/core/os/os.h b/core/os/os.h index 4bb177eb77a..ffdb905abaf 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -94,7 +94,15 @@ public: enum RenderThreadMode { RENDER_THREAD_UNSAFE, RENDER_THREAD_SAFE, - RENDER_SEPARATE_THREAD + RENDER_SEPARATE_THREAD, + }; + + enum StdHandleType { + STD_HANDLE_INVALID, + STD_HANDLE_CONSOLE, + STD_HANDLE_FILE, + STD_HANDLE_PIPE, + STD_HANDLE_UNKNOWN, }; protected: @@ -146,7 +154,12 @@ public: void print_rich(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; - virtual String get_stdin_string() = 0; + virtual String get_stdin_string(int64_t p_buffer_size = 1024) = 0; + virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) = 0; + + virtual StdHandleType get_stdin_type() const { return STD_HANDLE_UNKNOWN; } + virtual StdHandleType get_stdout_type() const { return STD_HANDLE_UNKNOWN; } + virtual StdHandleType get_stderr_type() const { return STD_HANDLE_UNKNOWN; } virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) = 0; // Should return cryptographically-safe random bytes. virtual String get_system_ca_certificates() { return ""; } // Concatenated certificates in PEM format. diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 49350597f55..5ab7c27f4f4 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -23,7 +23,7 @@ Shuts down the system MIDI driver. Godot will no longer receive [InputEventMIDI]. See also [method open_midi_inputs] and [method get_connected_midi_inputs]. - [b]Note:[/b] This method is implemented on Linux, macOS and Windows. + [b]Note:[/b] This method is implemented on Linux, macOS, and Windows. @@ -244,7 +244,7 @@ Returns an array of connected MIDI device names, if they exist. Returns an empty array if the system MIDI driver has not previously been initialized with [method open_midi_inputs]. See also [method close_midi_inputs]. - [b]Note:[/b] This method is implemented on Linux, macOS and Windows. + [b]Note:[/b] This method is implemented on Linux, macOS, and Windows. @@ -466,6 +466,24 @@ Returns the amount of static memory being used by the program in bytes. Only works in debug builds. + + + + Returns type of the standard error device. + + + + + + Returns type of the standard input device. + + + + + + Returns type of the standard output device. + + @@ -680,15 +698,31 @@ Initializes the singleton for the system MIDI driver, allowing Godot to receive [InputEventMIDI]. See also [method get_connected_midi_inputs] and [method close_midi_inputs]. - [b]Note:[/b] This method is implemented on Linux, macOS and Windows. + [b]Note:[/b] This method is implemented on Linux, macOS, and Windows. + + + + + + + Reads a user input as raw data from the standard input. This operation can be [i]blocking[/i], which causes the window to freeze if [method read_string_from_stdin] is called on the main thread. + - If standard input is console, this method will block until the program receives a line break in standard input (usually by the user pressing [kbd]Enter[/kbd]). + - If standard input is pipe, this method will block until a specific amount of data is read or pipe is closed. + - If standard input is a file, this method will read a specific amount of data (or less if end-of-file is reached) and return immediately. + [b]Note:[/b] This method is implemented on Linux, macOS, and Windows. + [b]Note:[/b] On exported Windows builds, run the console wrapper executable to access the terminal. If standard input is console, calling this method without console wrapped will freeze permanently. If standard input is pipe or file, it can be used without console wrapper. If you need a single executable with full console support, use a custom build compiled with the [code]windows_subsystem=console[/code] flag. + - Reads a user input string from the standard input (usually the terminal). This operation is [i]blocking[/i], which causes the window to freeze if [method read_string_from_stdin] is called on the main thread. The thread calling [method read_string_from_stdin] will block until the program receives a line break in standard input (usually by the user pressing [kbd]Enter[/kbd]). - [b]Note:[/b] This method is implemented on Linux, macOS and Windows. - [b]Note:[/b] On exported Windows builds, run the console wrapper executable to access the terminal. Otherwise, the standard input will not work correctly. If you need a single executable with console support, use a custom build compiled with the [code]windows_subsystem=console[/code] flag. + Reads a user input as a UTF-8 encoded string from the standard input. This operation can be [i]blocking[/i], which causes the window to freeze if [method read_string_from_stdin] is called on the main thread. + - If standard input is console, this method will block until the program receives a line break in standard input (usually by the user pressing [kbd]Enter[/kbd]). + - If standard input is pipe, this method will block until a specific amount of data is read or pipe is closed. + - If standard input is a file, this method will read a specific amount of data (or less if end-of-file is reached) and return immediately. + [b]Note:[/b] This method is implemented on Linux, macOS, and Windows. + [b]Note:[/b] On exported Windows builds, run the console wrapper executable to access the terminal. If standard input is console, calling this method without console wrapped will freeze permanently. If standard input is pipe or file, it can be used without console wrapper. If you need a single executable with full console support, use a custom build compiled with the [code]windows_subsystem=console[/code] flag. @@ -831,5 +865,20 @@ Refers to the Ringtones directory path. + + Standard I/O device is invalid. No data can be received from or sent to these standard I/O devices. + + + Standard I/O device is a console. This typically occurs when Godot is run from a terminal with no redirection. This is also used for all standard I/O devices when running Godot from the editor, at least on desktop platforms. + + + Standard I/O device is a regular file. This typically occurs with redirection from a terminal, e.g. [code]godot > stdout.txt[/code], [code]godot < stdin.txt[/code] or [code]godot > stdout_stderr.txt 2>&1[/code]. + + + Standard I/O device is a FIFO/pipe. This typically occurs with pipe usage from a terminal, e.g. [code]echo "Hello" | godot[/code]. + + + Standard I/O device type is unknown. + diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index b23dba7a499..92855d1a439 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -182,9 +183,87 @@ Vector OS_Unix::get_video_adapter_driver_info() const { return Vector(); } -String OS_Unix::get_stdin_string() { - char buff[1024]; - return String::utf8(fgets(buff, 1024, stdin)); +String OS_Unix::get_stdin_string(int64_t p_buffer_size) { + Vector data; + data.resize(p_buffer_size); + if (fgets((char *)data.ptrw(), data.size(), stdin)) { + return String::utf8((char *)data.ptr()); + } + return String(); +} + +PackedByteArray OS_Unix::get_stdin_buffer(int64_t p_buffer_size) { + Vector data; + data.resize(p_buffer_size); + size_t sz = fread((void *)data.ptrw(), 1, data.size(), stdin); + if (sz > 0) { + data.resize(sz); + return data; + } + return PackedByteArray(); +} + +OS_Unix::StdHandleType OS_Unix::get_stdin_type() const { + int h = fileno(stdin); + if (h == -1) { + return STD_HANDLE_INVALID; + } + + if (isatty(h)) { + return STD_HANDLE_CONSOLE; + } + struct stat statbuf; + if (fstat(h, &statbuf) < 0) { + return STD_HANDLE_UNKNOWN; + } + if (S_ISFIFO(statbuf.st_mode)) { + return STD_HANDLE_PIPE; + } else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) { + return STD_HANDLE_FILE; + } + return STD_HANDLE_UNKNOWN; +} + +OS_Unix::StdHandleType OS_Unix::get_stdout_type() const { + int h = fileno(stdout); + if (h == -1) { + return STD_HANDLE_INVALID; + } + + if (isatty(h)) { + return STD_HANDLE_CONSOLE; + } + struct stat statbuf; + if (fstat(h, &statbuf) < 0) { + return STD_HANDLE_UNKNOWN; + } + if (S_ISFIFO(statbuf.st_mode)) { + return STD_HANDLE_PIPE; + } else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) { + return STD_HANDLE_FILE; + } + return STD_HANDLE_UNKNOWN; +} + +OS_Unix::StdHandleType OS_Unix::get_stderr_type() const { + int h = fileno(stderr); + if (h == -1) { + return STD_HANDLE_INVALID; + } + + if (isatty(h)) { + return STD_HANDLE_CONSOLE; + } + struct stat statbuf; + if (fstat(h, &statbuf) < 0) { + return STD_HANDLE_UNKNOWN; + } + if (S_ISFIFO(statbuf.st_mode)) { + return STD_HANDLE_PIPE; + } else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) { + return STD_HANDLE_FILE; + } + return STD_HANDLE_UNKNOWN; } Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) { diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 3add5df055e..2c7920c1426 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -58,7 +58,11 @@ public: virtual Vector get_video_adapter_driver_info() const override; - virtual String get_stdin_string() override; + virtual String get_stdin_string(int64_t p_buffer_size = 1024) override; + virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) override; + virtual StdHandleType get_stdin_type() const override; + virtual StdHandleType get_stdout_type() const override; + virtual StdHandleType get_stderr_type() const override; virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override; diff --git a/misc/extension_api_validation/4.3-stable.expected b/misc/extension_api_validation/4.3-stable.expected index 37706641152..4f5ebc7a68e 100644 --- a/misc/extension_api_validation/4.3-stable.expected +++ b/misc/extension_api_validation/4.3-stable.expected @@ -108,3 +108,10 @@ GH-97257 Validate extension JSON: Error: Field 'classes/EditorFeatureProfile/enums/Feature/values/FEATURE_MAX': value changed value in new API, from 8.0 to 9. New entry to the `EditorFeatureProfile.Feature` enum added. Those need to go before `FEATURE_MAX`, which will always cause a compatibility break. + + +GH-91201 +-------- +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/OS/methods/read_string_from_stdin': arguments + +Added optional argument. Compatibility method registered. diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 294a34bb91e..4d253059b24 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -156,6 +156,52 @@ void RedirectIOToConsole() { } } +bool OS_Windows::is_using_con_wrapper() const { + static String exe_renames[] = { + ".console.exe", + "_console.exe", + " console.exe", + "console.exe", + String(), + }; + + bool found_exe = false; + bool found_conwrap_exe = false; + String exe_name = get_executable_path().to_lower(); + String exe_dir = exe_name.get_base_dir(); + String exe_fname = exe_name.get_file().get_basename(); + + DWORD pids[256]; + DWORD count = GetConsoleProcessList(&pids[0], 256); + for (DWORD i = 0; i < count; i++) { + HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pids[i]); + if (process != NULL) { + WCHAR proc_name[MAX_PATH]; + DWORD len = MAX_PATH; + if (QueryFullProcessImageNameW(process, 0, &proc_name[0], &len)) { + String name = String::utf16((const char16_t *)&proc_name[0], len).replace("\\", "/").to_lower(); + if (name == exe_name) { + found_exe = true; + } + for (int j = 0; !exe_renames[j].is_empty(); j++) { + if (name == exe_dir.path_join(exe_fname + exe_renames[j])) { + found_conwrap_exe = true; + } + } + } + CloseHandle(process); + if (found_conwrap_exe && found_exe) { + break; + } + } + } + if (!found_exe) { + return true; // Unable to read console info, assume true. + } + + return found_conwrap_exe; +} + BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) { if (!EngineDebugger::is_active()) { return FALSE; @@ -1682,16 +1728,115 @@ void OS_Windows::unset_environment(const String &p_var) const { SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), nullptr); // Null to delete. } -String OS_Windows::get_stdin_string() { - char buff[1024]; +String OS_Windows::get_stdin_string(int64_t p_buffer_size) { + if (get_stdin_type() == STD_HANDLE_INVALID) { + return String(); + } + + Vector data; + data.resize(p_buffer_size); DWORD count = 0; - if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) { - return String::utf8((const char *)buff, count); + if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), data.ptrw(), data.size(), &count, nullptr)) { + return String::utf8((const char *)data.ptr(), count); } return String(); } +PackedByteArray OS_Windows::get_stdin_buffer(int64_t p_buffer_size) { + Vector data; + data.resize(p_buffer_size); + DWORD count = 0; + if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), data.ptrw(), data.size(), &count, nullptr)) { + return data; + } + + return PackedByteArray(); +} + +OS_Windows::StdHandleType OS_Windows::get_stdin_type() const { + HANDLE h = GetStdHandle(STD_INPUT_HANDLE); + if (h == 0 || h == INVALID_HANDLE_VALUE) { + return STD_HANDLE_INVALID; + } + DWORD ftype = GetFileType(h); + if (ftype == FILE_TYPE_UNKNOWN && GetLastError() != ERROR_SUCCESS) { + return STD_HANDLE_UNKNOWN; + } + ftype &= ~(FILE_TYPE_REMOTE); + + if (ftype == FILE_TYPE_DISK) { + return STD_HANDLE_FILE; + } else if (ftype == FILE_TYPE_PIPE) { + return STD_HANDLE_PIPE; + } else { + DWORD conmode = 0; + BOOL res = GetConsoleMode(h, &conmode); + if (!res && (GetLastError() == ERROR_INVALID_HANDLE)) { + return STD_HANDLE_UNKNOWN; // Unknown character device. + } else { +#ifndef WINDOWS_SUBSYSTEM_CONSOLE + if (!is_using_con_wrapper()) { + return STD_HANDLE_INVALID; // Window app can't read stdin input without werapper. + } +#endif + return STD_HANDLE_CONSOLE; + } + } +} + +OS_Windows::StdHandleType OS_Windows::get_stdout_type() const { + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + if (h == 0 || h == INVALID_HANDLE_VALUE) { + return STD_HANDLE_INVALID; + } + DWORD ftype = GetFileType(h); + if (ftype == FILE_TYPE_UNKNOWN && GetLastError() != ERROR_SUCCESS) { + return STD_HANDLE_UNKNOWN; + } + ftype &= ~(FILE_TYPE_REMOTE); + + if (ftype == FILE_TYPE_DISK) { + return STD_HANDLE_FILE; + } else if (ftype == FILE_TYPE_PIPE) { + return STD_HANDLE_PIPE; + } else { + DWORD conmode = 0; + BOOL res = GetConsoleMode(h, &conmode); + if (!res && (GetLastError() == ERROR_INVALID_HANDLE)) { + return STD_HANDLE_UNKNOWN; // Unknown character device. + } else { + return STD_HANDLE_CONSOLE; + } + } +} + +OS_Windows::StdHandleType OS_Windows::get_stderr_type() const { + HANDLE h = GetStdHandle(STD_ERROR_HANDLE); + if (h == 0 || h == INVALID_HANDLE_VALUE) { + return STD_HANDLE_INVALID; + } + DWORD ftype = GetFileType(h); + if (ftype == FILE_TYPE_UNKNOWN && GetLastError() != ERROR_SUCCESS) { + return STD_HANDLE_UNKNOWN; + } + ftype &= ~(FILE_TYPE_REMOTE); + + if (ftype == FILE_TYPE_DISK) { + return STD_HANDLE_FILE; + } else if (ftype == FILE_TYPE_PIPE) { + return STD_HANDLE_PIPE; + } else { + DWORD conmode = 0; + BOOL res = GetConsoleMode(h, &conmode); + if (!res && (GetLastError() == ERROR_INVALID_HANDLE)) { + return STD_HANDLE_UNKNOWN; // Unknown character device. + } else { + return STD_HANDLE_CONSOLE; + } + } +} + Error OS_Windows::shell_open(const String &p_uri) { INT_PTR ret = (INT_PTR)ShellExecuteW(nullptr, nullptr, (LPCWSTR)(p_uri.utf16().get_data()), nullptr, nullptr, SW_SHOWNORMAL); if (ret > 32) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index c200ba5b43a..a32e535f0b0 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -134,6 +134,8 @@ class OS_Windows : public OS { DWRITE_FONT_WEIGHT _weight_to_dw(int p_weight) const; DWRITE_FONT_STRETCH _stretch_to_dw(int p_stretch) const; + bool is_using_con_wrapper() const; + // functions used by main to initialize/deinitialize the OS protected: virtual void initialize() override; @@ -143,7 +145,12 @@ protected: virtual void finalize() override; virtual void finalize_core() override; - virtual String get_stdin_string() override; + + virtual String get_stdin_string(int64_t p_buffer_size = 1024) override; + virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) override; + virtual StdHandleType get_stdin_type() const override; + virtual StdHandleType get_stdout_type() const override; + virtual StdHandleType get_stderr_type() const override; String _quote_command_line_argument(const String &p_text) const; diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp index 6c54faa13af..e25c612008c 100644 --- a/platform/windows/windows_terminal_logger.cpp +++ b/platform/windows/windows_terminal_logger.cpp @@ -30,6 +30,8 @@ #include "windows_terminal_logger.h" +#include "core/os/os.h" + #ifdef WINDOWS_ENABLED #include @@ -78,7 +80,7 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file } HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); - if (!hCon || hCon == INVALID_HANDLE_VALUE) { + if (OS::get_singleton()->get_stdout_type() != OS::STD_HANDLE_CONSOLE || !hCon || hCon == INVALID_HANDLE_VALUE) { StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type); } else { CONSOLE_SCREEN_BUFFER_INFO sbi; //original