Merge pull request #91201 from bruvzg/con_type

[OS] Add functions to determine standard I/O device type.
This commit is contained in:
Thaddeus Crews 2024-11-12 12:13:12 -06:00
commit 179321a0a3
No known key found for this signature in database
GPG Key ID: 62181B86FE9E5D84
11 changed files with 377 additions and 22 deletions

View File

@ -44,11 +44,16 @@ void Semaphore::_bind_compatibility_methods() {
// OS // 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<String> &p_arguments) { Dictionary OS::_execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments) {
return execute_with_pipe(p_path, p_arguments, true); return execute_with_pipe(p_path, p_arguments, true);
} }
void OS::_bind_compatibility_methods() { 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); ClassDB::bind_compatibility_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434);
} }

View File

@ -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); return ::OS::get_singleton()->shell_show_in_file_manager(p_path, p_open_folder);
} }
String OS::read_string_from_stdin() { String OS::read_string_from_stdin(int64_t p_buffer_size) {
return ::OS::get_singleton()->get_stdin_string(); 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<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) { int OS::execute(const String &p_path, const Vector<String> &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", "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_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("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", "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("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)); 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_MUSIC);
BIND_ENUM_CONSTANT(SYSTEM_DIR_PICTURES); BIND_ENUM_CONSTANT(SYSTEM_DIR_PICTURES);
BIND_ENUM_CONSTANT(SYSTEM_DIR_RINGTONES); 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 ////// ////// Geometry2D //////

View File

@ -134,6 +134,7 @@ protected:
#ifndef DISABLE_DEPRECATED #ifndef DISABLE_DEPRECATED
Dictionary _execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments); Dictionary _execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments);
String _read_string_from_stdin_bind_compat_91201();
static void _bind_compatibility_methods(); static void _bind_compatibility_methods();
#endif #endif
@ -148,6 +149,14 @@ public:
PackedByteArray get_entropy(int p_bytes); PackedByteArray get_entropy(int p_bytes);
String get_system_ca_certificates(); 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 PackedStringArray get_connected_midi_inputs();
virtual void open_midi_inputs(); virtual void open_midi_inputs();
virtual void close_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; String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
Vector<String> 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; Vector<String> 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 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<String> &p_arguments, Array r_output = ClassDB::default_array_arg, bool p_read_stderr = false, bool p_open_console = false); int execute(const String &p_path, const Vector<String> &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<String> &p_arguments, bool p_blocking = true); Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments, bool p_blocking = true);
int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false); int create_process(const String &p_path, const Vector<String> &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::RenderingDriver);
VARIANT_ENUM_CAST(core_bind::OS::SystemDir); 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::PolyBooleanOperation);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType); VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);

View File

@ -94,7 +94,15 @@ public:
enum RenderThreadMode { enum RenderThreadMode {
RENDER_THREAD_UNSAFE, RENDER_THREAD_UNSAFE,
RENDER_THREAD_SAFE, 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: protected:
@ -146,7 +154,12 @@ public:
void print_rich(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; void print_rich(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
void printerr(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 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. virtual String get_system_ca_certificates() { return ""; } // Concatenated certificates in PEM format.

View File

@ -23,7 +23,7 @@
<return type="void" /> <return type="void" />
<description> <description>
Shuts down the system MIDI driver. Godot will no longer receive [InputEventMIDI]. See also [method open_midi_inputs] and [method get_connected_midi_inputs]. 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.
</description> </description>
</method> </method>
<method name="crash"> <method name="crash">
@ -244,7 +244,7 @@
<return type="PackedStringArray" /> <return type="PackedStringArray" />
<description> <description>
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]. 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.
</description> </description>
</method> </method>
<method name="get_data_dir" qualifiers="const"> <method name="get_data_dir" qualifiers="const">
@ -466,6 +466,24 @@
Returns the amount of static memory being used by the program in bytes. Only works in debug builds. Returns the amount of static memory being used by the program in bytes. Only works in debug builds.
</description> </description>
</method> </method>
<method name="get_stderr_type" qualifiers="const">
<return type="int" enum="OS.StdHandleType" />
<description>
Returns type of the standard error device.
</description>
</method>
<method name="get_stdin_type" qualifiers="const">
<return type="int" enum="OS.StdHandleType" />
<description>
Returns type of the standard input device.
</description>
</method>
<method name="get_stdout_type" qualifiers="const">
<return type="int" enum="OS.StdHandleType" />
<description>
Returns type of the standard output device.
</description>
</method>
<method name="get_system_ca_certificates"> <method name="get_system_ca_certificates">
<return type="String" /> <return type="String" />
<description> <description>
@ -680,15 +698,31 @@
<return type="void" /> <return type="void" />
<description> <description>
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]. 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.
</description>
</method>
<method name="read_buffer_from_stdin">
<return type="PackedByteArray" />
<param index="0" name="buffer_size" type="int" />
<description>
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.
</description> </description>
</method> </method>
<method name="read_string_from_stdin"> <method name="read_string_from_stdin">
<return type="String" /> <return type="String" />
<param index="0" name="buffer_size" type="int" />
<description> <description>
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]). 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.
[b]Note:[/b] This method is implemented on Linux, macOS and Windows. - 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]).
[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. - 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.
</description> </description>
</method> </method>
<method name="request_permission"> <method name="request_permission">
@ -831,5 +865,20 @@
<constant name="SYSTEM_DIR_RINGTONES" value="7" enum="SystemDir"> <constant name="SYSTEM_DIR_RINGTONES" value="7" enum="SystemDir">
Refers to the Ringtones directory path. Refers to the Ringtones directory path.
</constant> </constant>
<constant name="STD_HANDLE_INVALID" value="0" enum="StdHandleType">
Standard I/O device is invalid. No data can be received from or sent to these standard I/O devices.
</constant>
<constant name="STD_HANDLE_CONSOLE" value="1" enum="StdHandleType">
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.
</constant>
<constant name="STD_HANDLE_FILE" value="2" enum="StdHandleType">
Standard I/O device is a regular file. This typically occurs with redirection from a terminal, e.g. [code]godot &gt; stdout.txt[/code], [code]godot &lt; stdin.txt[/code] or [code]godot &gt; stdout_stderr.txt 2&gt;&amp;1[/code].
</constant>
<constant name="STD_HANDLE_PIPE" value="3" enum="StdHandleType">
Standard I/O device is a FIFO/pipe. This typically occurs with pipe usage from a terminal, e.g. [code]echo "Hello" | godot[/code].
</constant>
<constant name="STD_HANDLE_UNKNOWN" value="4" enum="StdHandleType">
Standard I/O device type is unknown.
</constant>
</constants> </constants>
</class> </class>

View File

@ -77,6 +77,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <time.h> #include <time.h>
@ -182,9 +183,87 @@ Vector<String> OS_Unix::get_video_adapter_driver_info() const {
return Vector<String>(); return Vector<String>();
} }
String OS_Unix::get_stdin_string() { String OS_Unix::get_stdin_string(int64_t p_buffer_size) {
char buff[1024]; Vector<uint8_t> data;
return String::utf8(fgets(buff, 1024, stdin)); 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<uint8_t> 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) { Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {

View File

@ -58,7 +58,11 @@ public:
virtual Vector<String> get_video_adapter_driver_info() const override; virtual Vector<String> 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; virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override;

View File

@ -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. 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. 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.

View File

@ -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) { BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) {
if (!EngineDebugger::is_active()) { if (!EngineDebugger::is_active()) {
return FALSE; 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. SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), nullptr); // Null to delete.
} }
String OS_Windows::get_stdin_string() { String OS_Windows::get_stdin_string(int64_t p_buffer_size) {
char buff[1024]; if (get_stdin_type() == STD_HANDLE_INVALID) {
return String();
}
Vector<uint8_t> data;
data.resize(p_buffer_size);
DWORD count = 0; DWORD count = 0;
if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) { if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), data.ptrw(), data.size(), &count, nullptr)) {
return String::utf8((const char *)buff, count); return String::utf8((const char *)data.ptr(), count);
} }
return String(); return String();
} }
PackedByteArray OS_Windows::get_stdin_buffer(int64_t p_buffer_size) {
Vector<uint8_t> 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) { 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); INT_PTR ret = (INT_PTR)ShellExecuteW(nullptr, nullptr, (LPCWSTR)(p_uri.utf16().get_data()), nullptr, nullptr, SW_SHOWNORMAL);
if (ret > 32) { if (ret > 32) {

View File

@ -134,6 +134,8 @@ class OS_Windows : public OS {
DWRITE_FONT_WEIGHT _weight_to_dw(int p_weight) const; DWRITE_FONT_WEIGHT _weight_to_dw(int p_weight) const;
DWRITE_FONT_STRETCH _stretch_to_dw(int p_stretch) 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 // functions used by main to initialize/deinitialize the OS
protected: protected:
virtual void initialize() override; virtual void initialize() override;
@ -143,7 +145,12 @@ protected:
virtual void finalize() override; virtual void finalize() override;
virtual void finalize_core() 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; String _quote_command_line_argument(const String &p_text) const;

View File

@ -30,6 +30,8 @@
#include "windows_terminal_logger.h" #include "windows_terminal_logger.h"
#include "core/os/os.h"
#ifdef WINDOWS_ENABLED #ifdef WINDOWS_ENABLED
#include <stdio.h> #include <stdio.h>
@ -78,7 +80,7 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file
} }
HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); 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); StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
} else { } else {
CONSOLE_SCREEN_BUFFER_INFO sbi; //original CONSOLE_SCREEN_BUFFER_INFO sbi; //original