summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/linux_builds.yml2
-rw-r--r--CHANGELOG.md2
-rw-r--r--core/config/project_settings.cpp69
-rw-r--r--core/core_constants.cpp80
-rw-r--r--core/error/error_macros.cpp4
-rw-r--r--core/error/error_macros.h48
-rw-r--r--core/input/input.cpp14
-rw-r--r--core/input/input.h2
-rw-r--r--core/input/input_event.cpp115
-rw-r--r--core/input/input_event.h8
-rw-r--r--core/io/marshalls.h2
-rw-r--r--core/math/a_star.cpp38
-rw-r--r--core/math/a_star.h2
-rw-r--r--core/math/a_star_grid_2d.cpp2
-rw-r--r--core/math/bvh_abb.h2
-rw-r--r--core/math/bvh_split.inc8
-rw-r--r--core/math/color.cpp2
-rw-r--r--core/math/expression.cpp9
-rw-r--r--core/os/keyboard.cpp119
-rw-r--r--core/os/keyboard.h87
-rw-r--r--doc/classes/@GlobalScope.xml232
-rw-r--r--doc/classes/AcceptDialog.xml4
-rw-r--r--doc/classes/AnimatableBody3D.xml1
-rw-r--r--doc/classes/AnimationNodeStateMachinePlayback.xml6
-rw-r--r--doc/classes/AnimationTree.xml2
-rw-r--r--doc/classes/Area3D.xml1
-rw-r--r--doc/classes/AudioStreamPlaybackPolyphonic.xml61
-rw-r--r--doc/classes/AudioStreamPolyphonic.xml17
-rw-r--r--doc/classes/CharacterBody3D.xml5
-rw-r--r--doc/classes/CollisionObject3D.xml1
-rw-r--r--doc/classes/CollisionPolygon3D.xml1
-rw-r--r--doc/classes/CollisionShape3D.xml1
-rw-r--r--doc/classes/Color.xml2
-rw-r--r--doc/classes/ConfirmationDialog.xml4
-rw-r--r--doc/classes/Curve3D.xml2
-rw-r--r--doc/classes/EditorPlugin.xml1
-rw-r--r--doc/classes/Input.xml9
-rw-r--r--doc/classes/InputEventKey.xml52
-rw-r--r--doc/classes/InputEventWithModifiers.xml6
-rw-r--r--doc/classes/Light3D.xml2
-rw-r--r--doc/classes/LightmapGI.xml18
-rw-r--r--doc/classes/Marshalls.xml2
-rw-r--r--doc/classes/Node.xml3
-rw-r--r--doc/classes/OS.xml2
-rw-r--r--doc/classes/Object.xml2
-rw-r--r--doc/classes/PhysicalBone3D.xml1
-rw-r--r--doc/classes/PhysicsBody3D.xml3
-rw-r--r--doc/classes/ProjectSettings.xml16
-rw-r--r--doc/classes/RigidBody3D.xml1
-rw-r--r--doc/classes/StaticBody3D.xml5
-rw-r--r--doc/classes/StyleBox.xml37
-rw-r--r--doc/classes/StyleBoxTexture.xml58
-rw-r--r--doc/classes/TextEdit.xml2
-rw-r--r--doc/classes/TileSet.xml2
-rw-r--r--doc/classes/VehicleBody3D.xml1
-rw-r--r--doc/classes/Window.xml10
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp2
-rw-r--r--drivers/gles3/storage/texture_storage.cpp8
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp2
-rw-r--r--drivers/vulkan/vulkan_context.cpp4
-rw-r--r--editor/action_map_editor.cpp8
-rw-r--r--editor/connections_dialog.cpp2
-rw-r--r--editor/editor_data.h1
-rw-r--r--editor/editor_feature_profile.cpp2
-rw-r--r--editor/editor_file_system.cpp5
-rw-r--r--editor/editor_help.cpp4
-rw-r--r--editor/editor_inspector.cpp12
-rw-r--r--editor/editor_inspector.h1
-rw-r--r--editor/editor_node.cpp596
-rw-r--r--editor/editor_node.h47
-rw-r--r--editor/editor_plugin.cpp2
-rw-r--r--editor/editor_properties.cpp67
-rw-r--r--editor/editor_properties.h5
-rw-r--r--editor/editor_resource_picker.cpp2
-rw-r--r--editor/editor_spin_slider.cpp8
-rw-r--r--editor/editor_themes.cpp98
-rw-r--r--editor/editor_toaster.cpp2
-rw-r--r--editor/event_listener_line_edit.cpp36
-rw-r--r--editor/filesystem_dock.cpp33
-rw-r--r--editor/filesystem_dock.h2
-rw-r--r--editor/icons/Keyboard.svg2
-rw-r--r--editor/icons/KeyboardError.svg1
-rw-r--r--editor/icons/KeyboardLabel.svg1
-rw-r--r--editor/icons/KeyboardPhysical.svg2
-rw-r--r--editor/import/editor_import_collada.cpp2
-rw-r--r--editor/input_event_configuration_dialog.cpp154
-rw-r--r--editor/input_event_configuration_dialog.h17
-rw-r--r--editor/inspector_dock.cpp3
-rw-r--r--editor/plugin_config_dialog.cpp4
-rw-r--r--editor/plugin_config_dialog.h2
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp4
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp4
-rw-r--r--editor/plugins/bit_map_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp77
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h6
-rw-r--r--editor/plugins/gradient_editor.cpp183
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.cpp56
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/script_text_editor.cpp2
-rw-r--r--editor/plugins/shader_editor_plugin.cpp4
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp24
-rw-r--r--editor/plugins/theme_editor_plugin.cpp10
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp2
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp29
-rw-r--r--editor/progress_dialog.cpp10
-rw-r--r--editor/progress_dialog.h2
-rw-r--r--editor/project_converter_3_to_4.cpp1
-rw-r--r--editor/scene_tree_dock.cpp13
-rw-r--r--editor/scene_tree_editor.cpp2
-rw-r--r--main/main.cpp24
-rwxr-xr-xmisc/scripts/codespell.sh4
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp67
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h25
-rw-r--r--modules/gdscript/gdscript_codegen.h6
-rw-r--r--modules/gdscript/gdscript_compiler.cpp17
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp21
-rw-r--r--modules/gdscript/gdscript_function.h10
-rw-r--r--modules/gdscript/gdscript_parser.cpp48
-rw-r--r--modules/gdscript/gdscript_parser.h7
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp62
-rw-r--r--modules/gdscript/gdscript_tokenizer.h7
-rw-r--r--modules/gdscript/gdscript_warning.cpp5
-rw-r--r--modules/gdscript/gdscript_warning.h1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_match.gd7
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_match.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd35
-rw-r--r--modules/gdscript/tests/scripts/parser/features/unicode_identifiers.out14
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.out6
-rw-r--r--modules/gltf/gltf_document.cpp1
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs2
-rw-r--r--modules/multiplayer/editor/replication_editor.cpp2
-rw-r--r--modules/multiplayer/scene_replication_interface.cpp2
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.cpp30
-rw-r--r--modules/navigation/nav_map.cpp4
-rw-r--r--modules/openxr/doc_classes/OpenXRAction.xml4
-rw-r--r--modules/openxr/openxr_api.cpp2
-rw-r--r--modules/openxr/openxr_api.h2
-rw-r--r--modules/openxr/register_types.cpp4
-rw-r--r--modules/text_server_adv/text_server_adv.cpp17
-rw-r--r--platform/android/android_input_handler.cpp10
-rw-r--r--platform/android/android_input_handler.h2
-rw-r--r--platform/android/android_keys_utils.cpp38
-rw-r--r--platform/android/android_keys_utils.h3
-rw-r--r--platform/android/java/lib/res/values/strings.xml2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java10
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java22
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java2
-rw-r--r--platform/android/java_godot_lib_jni.cpp4
-rw-r--r--platform/android/java_godot_lib_jni.h2
-rw-r--r--platform/ios/SCsub1
-rw-r--r--platform/ios/detect.py12
-rw-r--r--platform/ios/display_layer.h3
-rw-r--r--platform/ios/display_layer.mm29
-rw-r--r--platform/ios/display_server_ios.h10
-rw-r--r--platform/ios/display_server_ios.mm79
-rw-r--r--platform/ios/godot_view.mm18
-rw-r--r--platform/ios/key_mapping_ios.h46
-rw-r--r--platform/ios/key_mapping_ios.mm186
-rw-r--r--platform/ios/keyboard_input_view.mm18
-rw-r--r--platform/ios/view_controller.mm59
-rw-r--r--platform/linuxbsd/detect.py3
-rw-r--r--platform/linuxbsd/x11/SCsub1
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp377
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h22
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xkbcommon-so_wrap.c859
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xkbcommon-so_wrap.h322
-rw-r--r--platform/linuxbsd/x11/key_mapping_x11.cpp3032
-rw-r--r--platform/linuxbsd/x11/key_mapping_x11.h6
-rw-r--r--platform/macos/detect.py2
-rw-r--r--platform/macos/display_server_macos.h5
-rw-r--r--platform/macos/display_server_macos.mm26
-rw-r--r--platform/macos/godot_application.h1
-rw-r--r--platform/macos/godot_application.mm74
-rw-r--r--platform/macos/godot_content_view.h1
-rw-r--r--platform/macos/godot_content_view.mm164
-rw-r--r--platform/macos/key_mapping_macos.h10
-rw-r--r--platform/macos/key_mapping_macos.mm717
-rw-r--r--platform/web/display_server_web.cpp19
-rw-r--r--platform/web/dom_keys.inc56
-rw-r--r--platform/windows/display_server_windows.cpp166
-rw-r--r--platform/windows/display_server_windows.h6
-rw-r--r--platform/windows/joypad_windows.cpp4
-rw-r--r--platform/windows/key_mapping_windows.cpp788
-rw-r--r--platform/windows/key_mapping_windows.h2
-rw-r--r--scene/2d/audio_stream_player_2d.cpp6
-rw-r--r--scene/2d/tile_map.cpp6
-rw-r--r--scene/3d/audio_stream_player_3d.cpp8
-rw-r--r--scene/3d/collision_object_3d.cpp18
-rw-r--r--scene/3d/collision_polygon_3d.cpp12
-rw-r--r--scene/3d/collision_shape_3d.cpp10
-rw-r--r--scene/3d/lightmap_gi.cpp2
-rw-r--r--scene/3d/lightmap_gi.h2
-rw-r--r--scene/3d/physics_body_3d.cpp13
-rw-r--r--scene/3d/soft_body_3d.cpp13
-rw-r--r--scene/animation/animation_node_state_machine.cpp11
-rw-r--r--scene/animation/animation_node_state_machine.h2
-rw-r--r--scene/animation/animation_tree.cpp2
-rw-r--r--scene/audio/audio_stream_player.cpp6
-rw-r--r--scene/gui/color_picker.cpp4
-rw-r--r--scene/gui/dialogs.cpp4
-rw-r--r--scene/gui/line_edit.cpp50
-rw-r--r--scene/gui/menu_bar.cpp8
-rw-r--r--scene/gui/popup_menu.cpp6
-rw-r--r--scene/gui/scroll_bar.cpp6
-rw-r--r--scene/gui/separator.cpp2
-rw-r--r--scene/gui/slider.cpp6
-rw-r--r--scene/gui/text_edit.cpp14
-rw-r--r--scene/gui/text_edit.h2
-rw-r--r--scene/main/multiplayer_api.cpp2
-rw-r--r--scene/main/node.cpp1
-rw-r--r--scene/main/node.h1
-rw-r--r--scene/main/window.cpp20
-rw-r--r--scene/main/window.h6
-rw-r--r--scene/register_scene_types.cpp3
-rw-r--r--scene/resources/audio_stream_polyphonic.cpp274
-rw-r--r--scene/resources/audio_stream_polyphonic.h119
-rw-r--r--scene/resources/camera_attributes.cpp4
-rw-r--r--scene/resources/default_theme/default_theme.cpp24
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--scene/resources/mesh.cpp12
-rw-r--r--scene/resources/packed_scene.cpp19
-rw-r--r--scene/resources/packed_scene.h2
-rw-r--r--scene/resources/polygon_path_finder.cpp4
-rw-r--r--scene/resources/style_box.cpp209
-rw-r--r--scene/resources/style_box.h61
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssao.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssil.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl10
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl26
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp2
-rw-r--r--servers/xr_server.h2
-rw-r--r--tests/core/input/test_input_event_key.h7
-rw-r--r--tests/core/math/test_geometry_3d.h8
-rw-r--r--tests/scene/test_code_edit.h2
249 files changed, 6813 insertions, 4697 deletions
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index 84fdb2180b..ce4f757a19 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -85,7 +85,7 @@ jobs:
sudo apt-get install build-essential pkg-config libx11-dev libxcursor-dev \
libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev \
libdbus-1-dev libudev-dev libxi-dev libxrandr-dev yasm xvfb wget unzip \
- llvm libspeechd-dev speech-dispatcher fontconfig libfontconfig-dev
+ llvm libspeechd-dev speech-dispatcher fontconfig libfontconfig-dev libxkbcommon-dev
- name: Setup Godot build cache
uses: ./.github/actions/godot-cache
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 820a85c3fc..9f2449546e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -404,7 +404,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
#### Shaders
-- Removed `SCREEN_TEXTURE` and `DEPTH_TEXTURE` in favour of uniform hints `hint_screen_texture` and `hint_depth_texture`.
+- Removed `SCREEN_TEXTURE` and `DEPTH_TEXTURE` in favor of uniform hints `hint_screen_texture` and `hint_depth_texture`.
### Fixed
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index ed89bc15d3..db3191334a 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1232,12 +1232,9 @@ ProjectSettings::ProjectSettings() {
singleton = this;
GLOBAL_DEF_BASIC("application/config/name", "");
- GLOBAL_DEF_BASIC("application/config/name_localized", Dictionary());
- custom_prop_info["application/config/name_localized"] = PropertyInfo(Variant::DICTIONARY, "application/config/name_localized", PROPERTY_HINT_LOCALIZABLE_STRING);
- GLOBAL_DEF_BASIC("application/config/description", "");
- custom_prop_info["application/config/description"] = PropertyInfo(Variant::STRING, "application/config/description", PROPERTY_HINT_MULTILINE_TEXT);
- GLOBAL_DEF_BASIC("application/run/main_scene", "");
- custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res");
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::DICTIONARY, "application/config/name_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary());
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/config/description", PROPERTY_HINT_MULTILINE_TEXT), "");
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res"), "");
GLOBAL_DEF("application/run/disable_stdout", false);
GLOBAL_DEF("application/run/disable_stderr", false);
GLOBAL_DEF_RST("application/config/use_hidden_project_data_directory", true);
@@ -1249,22 +1246,15 @@ ProjectSettings::ProjectSettings() {
// - Have a 16:9 aspect ratio,
// - Have both dimensions divisible by 8 to better play along with video recording,
// - Be displayable correctly in windowed mode on a 1366×768 display (tested on Windows 10 with default settings).
- GLOBAL_DEF_BASIC("display/window/size/viewport_width", 1152);
- custom_prop_info["display/window/size/viewport_width"] = PropertyInfo(Variant::INT, "display/window/size/viewport_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/viewport_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 1152); // 8K resolution
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 648); // 8K resolution
- GLOBAL_DEF_BASIC("display/window/size/viewport_height", 648);
- custom_prop_info["display/window/size/viewport_height"] = PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
-
- GLOBAL_DEF_BASIC("display/window/size/mode", 0);
- custom_prop_info["display/window/size/mode"] = PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen");
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen"), 0);
// Keep the enum values in sync with the `DisplayServer::SCREEN_` enum.
- GLOBAL_DEF_BASIC("display/window/size/initial_screen", -2);
- String screen_hints = "Primary Monitor:-2"; // Note: Main Window Monitor:-1 is not used for the main window, skip it.
- for (int i = 0; i < 64; i++) {
- screen_hints += ",Monitor " + itos(i + 1) + ":" + itos(i);
- }
- custom_prop_info["display/window/size/initial_screen"] = PropertyInfo(Variant::INT, "display/window/size/initial_screen", PROPERTY_HINT_ENUM, screen_hints);
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_position_type", PROPERTY_HINT_ENUM, "Absolute,Primary Screen Center,Other Screen Center"), 1);
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::VECTOR2I, "display/window/size/initial_position"), Vector2i());
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "display/window/size/initial_screen", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), 0);
GLOBAL_DEF_BASIC("display/window/size/resizable", true);
GLOBAL_DEF_BASIC("display/window/size/borderless", false);
@@ -1273,20 +1263,15 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("display/window/size/extend_to_title", false);
GLOBAL_DEF("display/window/size/no_focus", false);
- GLOBAL_DEF("display/window/size/window_width_override", 0);
- custom_prop_info["display/window/size/window_width_override"] = PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
- GLOBAL_DEF("display/window/size/window_height_override", 0);
- custom_prop_info["display/window/size/window_height_override"] = PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 0); // 8K resolution
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution
GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor", false);
- GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres");
- custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
- GLOBAL_DEF_RST("audio/general/2d_panning_strength", 0.5f);
- custom_prop_info["audio/general/2d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01");
- GLOBAL_DEF_RST("audio/general/3d_panning_strength", 0.5f);
- custom_prop_info["audio/general/3d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01");
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres"), "res://default_bus_layout.tres");
+ GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"), 0.5f);
+ GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01"), 0.5f);
PackedStringArray extensions;
extensions.push_back("gd");
@@ -1297,11 +1282,9 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("editor/run/main_run_args", "");
- GLOBAL_DEF("editor/script/search_in_file_extensions", extensions);
- custom_prop_info["editor/script/search_in_file_extensions"] = PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions");
+ GLOBAL_DEF(PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions"), extensions);
- GLOBAL_DEF("editor/script/templates_search_path", "res://script_templates");
- custom_prop_info["editor/script/templates_search_path"] = PropertyInfo(Variant::STRING, "editor/script/templates_search_path", PROPERTY_HINT_DIR);
+ GLOBAL_DEF(PropertyInfo(Variant::STRING, "editor/script/templates_search_path", PROPERTY_HINT_DIR), "res://script_templates");
_add_builtin_input_map();
@@ -1313,21 +1296,13 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("physics/2d/run_on_separate_thread", false);
GLOBAL_DEF("physics/3d/run_on_separate_thread", false);
- GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
- custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1");
-
- GLOBAL_DEF("compression/formats/zstd/long_distance_matching", Compression::zstd_long_distance_matching);
- custom_prop_info["compression/formats/zstd/long_distance_matching"] = PropertyInfo(Variant::BOOL, "compression/formats/zstd/long_distance_matching");
- GLOBAL_DEF("compression/formats/zstd/compression_level", Compression::zstd_level);
- custom_prop_info["compression/formats/zstd/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/zstd/compression_level", PROPERTY_HINT_RANGE, "1,22,1");
- GLOBAL_DEF("compression/formats/zstd/window_log_size", Compression::zstd_window_log_size);
- custom_prop_info["compression/formats/zstd/window_log_size"] = PropertyInfo(Variant::INT, "compression/formats/zstd/window_log_size", PROPERTY_HINT_RANGE, "10,30,1");
-
- GLOBAL_DEF("compression/formats/zlib/compression_level", Compression::zlib_level);
- custom_prop_info["compression/formats/zlib/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/zlib/compression_level", PROPERTY_HINT_RANGE, "-1,9,1");
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1"), 16384);
- GLOBAL_DEF("compression/formats/gzip/compression_level", Compression::gzip_level);
- custom_prop_info["compression/formats/gzip/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1");
+ GLOBAL_DEF(PropertyInfo(Variant::BOOL, "compression/formats/zstd/long_distance_matching"), Compression::zstd_long_distance_matching);
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "compression/formats/zstd/compression_level", PROPERTY_HINT_RANGE, "1,22,1"), Compression::zstd_level);
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "compression/formats/zstd/window_log_size", PROPERTY_HINT_RANGE, "10,30,1"), Compression::zstd_window_log_size);
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "compression/formats/zlib/compression_level", PROPERTY_HINT_RANGE, "-1,9,1"), Compression::zlib_level);
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1"), Compression::gzip_level);
GLOBAL_DEF("debug/settings/crash_handler/message",
String("Please include this when reporting the bug to the project developer."));
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index edb72f73cb..e28f7bfc4f 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -274,14 +274,9 @@ void register_global_constants() {
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_7);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_8);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KP_9);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SUPER_L);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SUPER_R);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MENU);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HYPER_L);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HYPER_R);
+ BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HYPER);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HELP);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DIRECTION_L);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DIRECTION_R);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BACK);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, FORWARD);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, STOP);
@@ -289,11 +284,6 @@ void register_global_constants() {
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEDOWN);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEMUTE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, VOLUMEUP);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BASSBOOST);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BASSUP);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BASSDOWN);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, TREBLEUP);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, TREBLEDOWN);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIAPLAY);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIASTOP);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MEDIAPREVIOUS);
@@ -392,72 +382,12 @@ void register_global_constants() {
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BAR);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BRACERIGHT);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASCIITILDE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NOBREAKSPACE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EXCLAMDOWN);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CENT);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, STERLING);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CURRENCY);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, YEN);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, BROKENBAR);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SECTION);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DIAERESIS);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, COPYRIGHT);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ORDFEMININE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GUILLEMOTLEFT);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NOTSIGN);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, HYPHEN);
- BIND_CORE_ENUM_CLASS_CONSTANT_CUSTOM(Key, KEY_REGISTERED, KEY_REGISTERED);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MACRON);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DEGREE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PLUSMINUS);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, TWOSUPERIOR);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, THREESUPERIOR);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ACUTE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MU);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PARAGRAPH);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, PERIODCENTERED);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CEDILLA);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ONESUPERIOR);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MASCULINE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GUILLEMOTRIGHT);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ONEQUARTER);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ONEHALF);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, THREEQUARTERS);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, QUESTIONDOWN);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, AGRAVE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, AACUTE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ACIRCUMFLEX);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ATILDE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ADIAERESIS);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ARING);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, AE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, CCEDILLA);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EGRAVE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EACUTE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ECIRCUMFLEX);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EDIAERESIS);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, IGRAVE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, IACUTE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ICIRCUMFLEX);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, IDIAERESIS);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ETH);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NTILDE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, OGRAVE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, OACUTE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, OCIRCUMFLEX);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, OTILDE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ODIAERESIS);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, MULTIPLY);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, OOBLIQUE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UGRAVE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UACUTE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UCIRCUMFLEX);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UDIAERESIS);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, YACUTE);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, THORN);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SSHARP);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, DIVISION);
- BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, YDIAERESIS);
+ BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GLOBE);
+ BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KEYBOARD);
+ BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_EISU);
+ BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_KANA);
BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(KeyModifierMask, KEY_CODE_MASK, CODE_MASK);
BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(KeyModifierMask, KEY_MODIFIER_MASK, MODIFIER_MASK);
diff --git a/core/error/error_macros.cpp b/core/error/error_macros.cpp
index ddfee3fc5d..8376c0aaf8 100644
--- a/core/error/error_macros.cpp
+++ b/core/error/error_macros.cpp
@@ -118,11 +118,11 @@ void _err_print_error(const char *p_function, const char *p_file, int p_line, co
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message, bool p_editor_notify, bool p_fatal) {
String fstr(p_fatal ? "FATAL: " : "");
String err(fstr + "Index " + p_index_str + " = " + itos(p_index) + " is out of bounds (" + p_size_str + " = " + itos(p_size) + ").");
- _err_print_error(p_function, p_file, p_line, err.utf8().get_data(), p_message);
+ _err_print_error(p_function, p_file, p_line, err.utf8().get_data(), p_message, p_editor_notify, ERR_HANDLER_ERROR);
}
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify, bool p_fatal) {
- _err_print_index_error(p_function, p_file, p_line, p_index, p_size, p_index_str, p_size_str, p_message.utf8().get_data(), p_fatal);
+ _err_print_index_error(p_function, p_file, p_line, p_index, p_size, p_index_str, p_size_str, p_message.utf8().get_data(), p_editor_notify, p_fatal);
}
void _err_flush_stdout() {
diff --git a/core/error/error_macros.h b/core/error/error_macros.h
index 63a2d22416..65804b7796 100644
--- a/core/error/error_macros.h
+++ b/core/error/error_macros.h
@@ -189,12 +189,12 @@ void _err_flush_stdout();
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the application crashes.
*/
-#define CRASH_BAD_INDEX(m_index, m_size) \
- if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
- _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \
- _err_flush_stdout(); \
- GENERATE_TRAP(); \
- } else \
+#define CRASH_BAD_INDEX(m_index, m_size) \
+ if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
+ _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
+ _err_flush_stdout(); \
+ GENERATE_TRAP(); \
+ } else \
((void)0)
/**
@@ -204,12 +204,12 @@ void _err_flush_stdout();
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the application crashes.
*/
-#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
- if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
- _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
- _err_flush_stdout(); \
- GENERATE_TRAP(); \
- } else \
+#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
+ if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
+ _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
+ _err_flush_stdout(); \
+ GENERATE_TRAP(); \
+ } else \
((void)0)
// Unsigned integer index out of bounds error macros.
@@ -292,12 +292,12 @@ void _err_flush_stdout();
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the application crashes.
*/
-#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
- if (unlikely((m_index) >= (m_size))) { \
- _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \
- _err_flush_stdout(); \
- GENERATE_TRAP(); \
- } else \
+#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
+ if (unlikely((m_index) >= (m_size))) { \
+ _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
+ _err_flush_stdout(); \
+ GENERATE_TRAP(); \
+ } else \
((void)0)
/**
@@ -307,12 +307,12 @@ void _err_flush_stdout();
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the application crashes.
*/
-#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
- if (unlikely((m_index) >= (m_size))) { \
- _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
- _err_flush_stdout(); \
- GENERATE_TRAP(); \
- } else \
+#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
+ if (unlikely((m_index) >= (m_size))) { \
+ _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
+ _err_flush_stdout(); \
+ GENERATE_TRAP(); \
+ } else \
((void)0)
// Null reference error macros.
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 0afa004515..1ea9f00fee 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -93,6 +93,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_anything_pressed"), &Input::is_anything_pressed);
ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
ClassDB::bind_method(D_METHOD("is_physical_key_pressed", "keycode"), &Input::is_physical_key_pressed);
+ ClassDB::bind_method(D_METHOD("is_key_label_pressed", "keycode"), &Input::is_key_label_pressed);
ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed);
ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed);
ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact_match"), &Input::is_action_pressed, DEFVAL(false));
@@ -250,6 +251,11 @@ bool Input::is_physical_key_pressed(Key p_keycode) const {
return physical_keys_pressed.has(p_keycode);
}
+bool Input::is_key_label_pressed(Key p_keycode) const {
+ _THREAD_SAFE_METHOD_
+ return key_label_pressed.has(p_keycode);
+}
+
bool Input::is_mouse_button_pressed(MouseButton p_button) const {
_THREAD_SAFE_METHOD_
return mouse_button_mask.has_flag(mouse_button_to_mask(p_button));
@@ -499,6 +505,13 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
physical_keys_pressed.erase(k->get_physical_keycode());
}
}
+ if (k.is_valid() && !k->is_echo() && k->get_key_label() != Key::NONE) {
+ if (k->is_pressed()) {
+ key_label_pressed.insert(k->get_key_label());
+ } else {
+ key_label_pressed.erase(k->get_key_label());
+ }
+ }
Ref<InputEventMouseButton> mb = p_event;
@@ -919,6 +932,7 @@ void Input::release_pressed_events() {
keys_pressed.clear();
physical_keys_pressed.clear();
+ key_label_pressed.clear();
joy_buttons_pressed.clear();
_joy_axis.clear();
diff --git a/core/input/input.h b/core/input/input.h
index 0915588700..f2de56b6b9 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -84,6 +84,7 @@ public:
private:
BitField<MouseButtonMask> mouse_button_mask;
+ RBSet<Key> key_label_pressed;
RBSet<Key> physical_keys_pressed;
RBSet<Key> keys_pressed;
RBSet<JoyButton> joy_buttons_pressed;
@@ -247,6 +248,7 @@ public:
bool is_anything_pressed() const;
bool is_key_pressed(Key p_keycode) const;
bool is_physical_key_pressed(Key p_keycode) const;
+ bool is_key_label_pressed(Key p_keycode) const;
bool is_mouse_button_pressed(MouseButton p_button) const;
bool is_joy_button_pressed(int p_device, JoyButton p_button) const;
bool is_action_pressed(const StringName &p_action, bool p_exact = false) const;
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 0dd7fdc19b..dbe9b55ee3 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -285,6 +285,8 @@ void InputEventWithModifiers::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_meta_pressed", "pressed"), &InputEventWithModifiers::set_meta_pressed);
ClassDB::bind_method(D_METHOD("is_meta_pressed"), &InputEventWithModifiers::is_meta_pressed);
+ ClassDB::bind_method(D_METHOD("get_modifiers_mask"), &InputEventWithModifiers::get_modifiers_mask);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command_or_control_autoremap"), "set_command_or_control_autoremap", "is_command_or_control_autoremap");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alt_pressed"), "set_alt_pressed", "is_alt_pressed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shift_pressed"), "set_shift_pressed", "is_shift_pressed");
@@ -328,6 +330,15 @@ Key InputEventKey::get_keycode() const {
return keycode;
}
+void InputEventKey::set_key_label(Key p_key_label) {
+ key_label = p_key_label;
+ emit_changed();
+}
+
+Key InputEventKey::get_key_label() const {
+ return key_label;
+}
+
void InputEventKey::set_physical_keycode(Key p_keycode) {
physical_keycode = p_keycode;
emit_changed();
@@ -363,13 +374,72 @@ Key InputEventKey::get_physical_keycode_with_modifiers() const {
return physical_keycode | (int64_t)get_modifiers_mask();
}
+Key InputEventKey::get_key_label_with_modifiers() const {
+ return key_label | get_modifiers_mask();
+}
+
+String InputEventKey::as_text_physical_keycode() const {
+ String kc;
+
+ if (physical_keycode != Key::NONE) {
+ kc = keycode_get_string(physical_keycode);
+ } else {
+ kc = "(" + RTR("Unset") + ")";
+ }
+
+ if (kc.is_empty()) {
+ return kc;
+ }
+
+ String mods_text = InputEventWithModifiers::as_text();
+ return mods_text.is_empty() ? kc : mods_text + "+" + kc;
+}
+
+String InputEventKey::as_text_keycode() const {
+ String kc;
+
+ if (keycode != Key::NONE) {
+ kc = keycode_get_string(keycode);
+ } else {
+ kc = "(" + RTR("Unset") + ")";
+ }
+
+ if (kc.is_empty()) {
+ return kc;
+ }
+
+ String mods_text = InputEventWithModifiers::as_text();
+ return mods_text.is_empty() ? kc : mods_text + "+" + kc;
+}
+
+String InputEventKey::as_text_key_label() const {
+ String kc;
+
+ if (key_label != Key::NONE) {
+ kc = keycode_get_string(key_label);
+ } else {
+ kc = "(" + RTR("Unset") + ")";
+ }
+
+ if (kc.is_empty()) {
+ return kc;
+ }
+
+ String mods_text = InputEventWithModifiers::as_text();
+ return mods_text.is_empty() ? kc : mods_text + "+" + kc;
+}
+
String InputEventKey::as_text() const {
String kc;
- if (keycode == Key::NONE) {
+ if (keycode == Key::NONE && physical_keycode == Key::NONE && key_label != Key::NONE) {
+ kc = keycode_get_string(key_label) + " (Unicode)";
+ } else if (keycode != Key::NONE) {
+ kc = keycode_get_string(keycode);
+ } else if (physical_keycode != Key::NONE) {
kc = keycode_get_string(physical_keycode) + " (" + RTR("Physical") + ")";
} else {
- kc = keycode_get_string(keycode);
+ kc = "(" + RTR("Unset") + ")";
}
if (kc.is_empty()) {
@@ -386,11 +456,16 @@ String InputEventKey::to_string() {
String kc = "";
String physical = "false";
- if (keycode == Key::NONE) {
+
+ if (keycode == Key::NONE && physical_keycode == Key::NONE && unicode != 0) {
+ kc = "U+" + String::num_uint64(unicode, 16) + " (" + String::chr(unicode) + ")";
+ } else if (keycode != Key::NONE) {
+ kc = itos((int64_t)keycode) + " (" + keycode_get_string(keycode) + ")";
+ } else if (physical_keycode != Key::NONE) {
kc = itos((int64_t)physical_keycode) + " (" + keycode_get_string(physical_keycode) + ")";
physical = "true";
} else {
- kc = itos((int64_t)keycode) + " (" + keycode_get_string(keycode) + ")";
+ kc = "(" + RTR("Unset") + ")";
}
String mods = InputEventWithModifiers::as_text();
@@ -403,6 +478,7 @@ Ref<InputEventKey> InputEventKey::create_reference(Key p_keycode) {
Ref<InputEventKey> ie;
ie.instantiate();
ie->set_keycode(p_keycode & KeyModifierMask::CODE_MASK);
+ ie->set_key_label(p_keycode & KeyModifierMask::CODE_MASK);
ie->set_unicode(char32_t(p_keycode & KeyModifierMask::CODE_MASK));
if ((p_keycode & KeyModifierMask::SHIFT) != Key::NONE) {
@@ -435,11 +511,16 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool p_exact_ma
}
bool match;
- if (keycode != Key::NONE) {
+ if (keycode == Key::NONE && physical_keycode == Key::NONE && key_label != Key::NONE) {
+ match = key_label == key->key_label;
+ } else if (keycode != Key::NONE) {
match = keycode == key->keycode;
+ } else if (physical_keycode != Key::NONE) {
+ match = physical_keycode == key->physical_keycode;
} else {
- match = get_physical_keycode() == key->get_physical_keycode();
+ match = false;
}
+
Key action_mask = (Key)(int64_t)get_modifiers_mask();
Key key_mask = (Key)(int64_t)key->get_modifiers_mask();
if (key->is_pressed()) {
@@ -470,12 +551,17 @@ bool InputEventKey::is_match(const Ref<InputEvent> &p_event, bool p_exact_match)
return false;
}
- if (keycode == Key::NONE) {
- return physical_keycode == key->physical_keycode &&
+ if (keycode == Key::NONE && physical_keycode == Key::NONE && key_label != Key::NONE) {
+ return (key_label == key->key_label) &&
(!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask());
- } else {
- return keycode == key->keycode &&
+ } else if (keycode != Key::NONE) {
+ return (keycode == key->keycode) &&
(!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask());
+ } else if (physical_keycode != Key::NONE) {
+ return (physical_keycode == key->physical_keycode) &&
+ (!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask());
+ } else {
+ return false;
}
}
@@ -488,6 +574,9 @@ void InputEventKey::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_physical_keycode", "physical_keycode"), &InputEventKey::set_physical_keycode);
ClassDB::bind_method(D_METHOD("get_physical_keycode"), &InputEventKey::get_physical_keycode);
+ ClassDB::bind_method(D_METHOD("set_key_label", "key_label"), &InputEventKey::set_key_label);
+ ClassDB::bind_method(D_METHOD("get_key_label"), &InputEventKey::get_key_label);
+
ClassDB::bind_method(D_METHOD("set_unicode", "unicode"), &InputEventKey::set_unicode);
ClassDB::bind_method(D_METHOD("get_unicode"), &InputEventKey::get_unicode);
@@ -495,10 +584,16 @@ void InputEventKey::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_keycode_with_modifiers"), &InputEventKey::get_keycode_with_modifiers);
ClassDB::bind_method(D_METHOD("get_physical_keycode_with_modifiers"), &InputEventKey::get_physical_keycode_with_modifiers);
+ ClassDB::bind_method(D_METHOD("get_key_label_with_modifiers"), &InputEventKey::get_key_label_with_modifiers);
+
+ ClassDB::bind_method(D_METHOD("as_text_keycode"), &InputEventKey::as_text_keycode);
+ ClassDB::bind_method(D_METHOD("as_text_physical_keycode"), &InputEventKey::as_text_physical_keycode);
+ ClassDB::bind_method(D_METHOD("as_text_key_label"), &InputEventKey::as_text_key_label);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
ADD_PROPERTY(PropertyInfo(Variant::INT, "keycode"), "set_keycode", "get_keycode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "physical_keycode"), "set_physical_keycode", "get_physical_keycode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "key_label"), "set_key_label", "get_key_label");
ADD_PROPERTY(PropertyInfo(Variant::INT, "unicode"), "set_unicode", "get_unicode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "echo"), "set_echo", "is_echo");
}
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 2d7a72e327..797761b208 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -153,6 +153,7 @@ class InputEventKey : public InputEventWithModifiers {
Key keycode = Key::NONE; // Key enum, without modifier masks.
Key physical_keycode = Key::NONE;
+ Key key_label = Key::NONE;
uint32_t unicode = 0; ///unicode
bool echo = false; /// true if this is an echo key
@@ -170,6 +171,9 @@ public:
void set_physical_keycode(Key p_keycode);
Key get_physical_keycode() const;
+ void set_key_label(Key p_key_label);
+ Key get_key_label() const;
+
void set_unicode(char32_t p_unicode);
char32_t get_unicode() const;
@@ -178,12 +182,16 @@ public:
Key get_keycode_with_modifiers() const;
Key get_physical_keycode_with_modifiers() const;
+ Key get_key_label_with_modifiers() const;
virtual bool action_match(const Ref<InputEvent> &p_event, bool p_exact_match, float p_deadzone, bool *r_pressed, float *r_strength, float *r_raw_strength) const override;
virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override;
virtual bool is_action_type() const override { return true; }
+ virtual String as_text_physical_keycode() const;
+ virtual String as_text_keycode() const;
+ virtual String as_text_key_label() const;
virtual String as_text() const override;
virtual String to_string() override;
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
index 5e760c7565..6f015ac386 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -44,7 +44,7 @@ typedef uint32_t uintr_t;
#endif
/**
- * Miscellaneous helpers for marshalling data types, and encoding
+ * Miscellaneous helpers for marshaling data types, and encoding
* in an endian independent way
*/
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index a54804c5dc..646bdea758 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -106,11 +106,11 @@ void AStar3D::remove_point(int64_t p_id) {
bool p_exists = points.lookup(p_id, p);
ERR_FAIL_COND_MSG(!p_exists, vformat("Can't remove point. Point with id: %d doesn't exist.", p_id));
- for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
+ for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbors.iter(); it.valid; it = p->neighbors.next_iter(it)) {
Segment s(p_id, (*it.key));
segments.erase(s);
- (*it.value)->neighbours.remove(p->id);
+ (*it.value)->neighbors.remove(p->id);
(*it.value)->unlinked_neighbours.remove(p->id);
}
@@ -118,7 +118,7 @@ void AStar3D::remove_point(int64_t p_id) {
Segment s(p_id, (*it.key));
segments.erase(s);
- (*it.value)->neighbours.remove(p->id);
+ (*it.value)->neighbors.remove(p->id);
(*it.value)->unlinked_neighbours.remove(p->id);
}
@@ -138,10 +138,10 @@ void AStar3D::connect_points(int64_t p_id, int64_t p_with_id, bool bidirectional
bool to_exists = points.lookup(p_with_id, b);
ERR_FAIL_COND_MSG(!to_exists, vformat("Can't connect points. Point with id: %d doesn't exist.", p_with_id));
- a->neighbours.set(b->id, b);
+ a->neighbors.set(b->id, b);
if (bidirectional) {
- b->neighbours.set(a->id, a);
+ b->neighbors.set(a->id, a);
} else {
b->unlinked_neighbours.set(a->id, a);
}
@@ -155,7 +155,7 @@ void AStar3D::connect_points(int64_t p_id, int64_t p_with_id, bool bidirectional
if (element) {
s.direction |= element->direction;
if (s.direction == Segment::BIDIRECTIONAL) {
- // Both are neighbours of each other now
+ // Both are neighbors of each other now
a->unlinked_neighbours.remove(b->id);
b->unlinked_neighbours.remove(a->id);
}
@@ -183,9 +183,9 @@ void AStar3D::disconnect_points(int64_t p_id, int64_t p_with_id, bool bidirectio
// Erase the directions to be removed
s.direction = (element->direction & ~remove_direction);
- a->neighbours.remove(b->id);
+ a->neighbors.remove(b->id);
if (bidirectional) {
- b->neighbours.remove(a->id);
+ b->neighbors.remove(a->id);
if (element->direction != Segment::BIDIRECTIONAL) {
a->unlinked_neighbours.remove(b->id);
b->unlinked_neighbours.remove(a->id);
@@ -226,7 +226,7 @@ Vector<int64_t> AStar3D::get_point_connections(int64_t p_id) {
Vector<int64_t> point_list;
- for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
+ for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbors.iter(); it.valid; it = p->neighbors.next_iter(it)) {
point_list.push_back((*it.key));
}
@@ -346,8 +346,8 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) {
open_list.remove_at(open_list.size() - 1);
p->closed_pass = pass; // Mark the point as closed
- for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
- Point *e = *(it.value); // The neighbour point
+ for (OAHashMap<int64_t, Point *>::Iterator it = p->neighbors.iter(); it.valid; it = p->neighbors.next_iter(it)) {
+ Point *e = *(it.value); // The neighbor point
if (!e->enabled || e->closed_pass == pass) {
continue;
@@ -794,7 +794,7 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
bool found_route = false;
- Vector<AStar3D::Point *> open_list;
+ LocalVector<AStar3D::Point *> open_list;
SortArray<AStar3D::Point *, AStar3D::SortPoints> sorter;
begin_point->g_score = 0;
@@ -802,19 +802,19 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
open_list.push_back(begin_point);
while (!open_list.is_empty()) {
- AStar3D::Point *p = open_list[0]; // The currently processed point
+ AStar3D::Point *p = open_list[0]; // The currently processed point.
if (p == end_point) {
found_route = true;
break;
}
- sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list
+ sorter.pop_heap(0, open_list.size(), open_list.ptr()); // Remove the current point from the open list.
open_list.remove_at(open_list.size() - 1);
- p->closed_pass = astar.pass; // Mark the point as closed
+ p->closed_pass = astar.pass; // Mark the point as closed.
- for (OAHashMap<int64_t, AStar3D::Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
- AStar3D::Point *e = *(it.value); // The neighbour point
+ for (OAHashMap<int64_t, AStar3D::Point *>::Iterator it = p->neighbors.iter(); it.valid; it = p->neighbors.next_iter(it)) {
+ AStar3D::Point *e = *(it.value); // The neighbor point.
if (!e->enabled || e->closed_pass == astar.pass) {
continue;
@@ -837,9 +837,9 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
if (new_point) { // The position of the new points is already known.
- sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw());
+ sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr());
} else {
- sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw());
+ sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptr());
}
}
}
diff --git a/core/math/a_star.h b/core/math/a_star.h
index a475e4f2fc..fc4bb09f03 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -52,7 +52,7 @@ class AStar3D : public RefCounted {
real_t weight_scale = 0;
bool enabled = false;
- OAHashMap<int64_t, Point *> neighbours = 4u;
+ OAHashMap<int64_t, Point *> neighbors = 4u;
OAHashMap<int64_t, Point *> unlinked_neighbours = 4u;
// Used for pathfinding.
diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
index 30d50073d7..677e609763 100644
--- a/core/math/a_star_grid_2d.cpp
+++ b/core/math/a_star_grid_2d.cpp
@@ -401,7 +401,7 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
List<Point *> nbors;
_get_nbors(p, nbors);
for (List<Point *>::Element *E = nbors.front(); E; E = E->next()) {
- Point *e = E->get(); // The neighbour point.
+ Point *e = E->get(); // The neighbor point.
real_t weight_scale = 1.0;
if (jumping_enabled) {
diff --git a/core/math/bvh_abb.h b/core/math/bvh_abb.h
index 32b011bd3b..fb0207e0bd 100644
--- a/core/math/bvh_abb.h
+++ b/core/math/bvh_abb.h
@@ -87,7 +87,7 @@ struct BVH_ABB {
return -neg_max - min;
}
- POINT calculate_centre() const {
+ POINT calculate_center() const {
return POINT((calculate_size() * 0.5) + min);
}
diff --git a/core/math/bvh_split.inc b/core/math/bvh_split.inc
index 180bbfb511..875abedb70 100644
--- a/core/math/bvh_split.inc
+++ b/core/math/bvh_split.inc
@@ -25,7 +25,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
return;
}
- POINT centre = full_bound.calculate_centre();
+ POINT center = full_bound.calculate_center();
POINT size = full_bound.calculate_size();
int order[POINT::AXIS_COUNT];
@@ -43,7 +43,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
for (int a = 0; a < num_a; a++) {
uint32_t ind = group_a[a];
- if (temp_bounds[ind].min.coord[split_axis] > centre.coord[split_axis]) {
+ if (temp_bounds[ind].min.coord[split_axis] > center.coord[split_axis]) {
// add to b
group_b[num_b++] = ind;
@@ -75,7 +75,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
for (int a = 0; a < num_a; a++) {
uint32_t ind = group_a[a];
- if (temp_bounds[ind].min.coord[split_axis] > centre.coord[split_axis]) {
+ if (temp_bounds[ind].min.coord[split_axis] > center.coord[split_axis]) {
count++;
}
}
@@ -100,7 +100,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
for (int a = 0; a < num_a; a++) {
uint32_t ind = group_a[a];
- if (temp_bounds[ind].min.coord[split_axis] > centre.coord[split_axis]) {
+ if (temp_bounds[ind].min.coord[split_axis] > center.coord[split_axis]) {
// add to b
group_b[num_b++] = ind;
diff --git a/core/math/color.cpp b/core/math/color.cpp
index 5bae8d25d6..3e5fa7b402 100644
--- a/core/math/color.cpp
+++ b/core/math/color.cpp
@@ -194,7 +194,7 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
a = p_alpha;
if (p_s == 0.0f) {
- // Achromatic (grey)
+ // Achromatic (gray)
r = g = b = p_v;
return;
}
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index da52bb9465..d1ec987d56 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -434,14 +434,13 @@ Error Expression::_get_token(Token &r_token) {
}
return OK;
- } else if (is_ascii_char(cchar) || is_underscore(cchar)) {
- String id;
- bool first = true;
+ } else if (is_unicode_identifier_start(cchar)) {
+ String id = String::chr(cchar);
+ cchar = GET_CHAR();
- while (is_ascii_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) {
+ while (is_unicode_identifier_continue(cchar)) {
id += String::chr(cchar);
cchar = GET_CHAR();
- first = false;
}
str_ofs--; //go back one
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index 5183b77cb1..25a4b320cd 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -127,14 +127,9 @@ static const _KeyCodeText _keycodes[] = {
{Key::KP_7 ,"Kp 7"},
{Key::KP_8 ,"Kp 8"},
{Key::KP_9 ,"Kp 9"},
- {Key::SUPER_L ,"Super L"},
- {Key::SUPER_R ,"Super R"},
{Key::MENU ,"Menu"},
- {Key::HYPER_L ,"Hyper L"},
- {Key::HYPER_R ,"Hyper R"},
+ {Key::HYPER ,"Hyper"},
{Key::HELP ,"Help"},
- {Key::DIRECTION_L ,"Direction L"},
- {Key::DIRECTION_R ,"Direction R"},
{Key::BACK ,"Back"},
{Key::FORWARD ,"Forward"},
{Key::STOP ,"Stop"},
@@ -142,11 +137,6 @@ static const _KeyCodeText _keycodes[] = {
{Key::VOLUMEDOWN ,"VolumeDown"},
{Key::VOLUMEMUTE ,"VolumeMute"},
{Key::VOLUMEUP ,"VolumeUp"},
- {Key::BASSBOOST ,"BassBoost"},
- {Key::BASSUP ,"BassUp"},
- {Key::BASSDOWN ,"BassDown"},
- {Key::TREBLEUP ,"TrebleUp"},
- {Key::TREBLEDOWN ,"TrebleDown"},
{Key::MEDIAPLAY ,"MediaPlay"},
{Key::MEDIASTOP ,"MediaStop"},
{Key::MEDIAPREVIOUS ,"MediaPrevious"},
@@ -174,6 +164,10 @@ static const _KeyCodeText _keycodes[] = {
{Key::LAUNCHD ,"LaunchD"},
{Key::LAUNCHE ,"LaunchE"},
{Key::LAUNCHF ,"LaunchF"},
+ {Key::GLOBE ,"Globe"},
+ {Key::KEYBOARD ,"On-screen keyboard"},
+ {Key::JIS_EISU ,"JIS Eisu"},
+ {Key::JIS_KANA ,"JIS Kana"},
{Key::UNKNOWN ,"Unknown"},
{Key::SPACE ,"Space"},
{Key::EXCLAM ,"Exclam"},
@@ -244,72 +238,6 @@ static const _KeyCodeText _keycodes[] = {
{Key::BAR ,"Bar"},
{Key::BRACERIGHT ,"BraceRight"},
{Key::ASCIITILDE ,"AsciiTilde"},
- {Key::NOBREAKSPACE ,"NoBreakSpace"},
- {Key::EXCLAMDOWN ,"ExclamDown"},
- {Key::CENT ,"Cent"},
- {Key::STERLING ,"Sterling"},
- {Key::CURRENCY ,"Currency"},
- {Key::YEN ,"Yen"},
- {Key::BROKENBAR ,"BrokenBar"},
- {Key::SECTION ,"Section"},
- {Key::DIAERESIS ,"Diaeresis"},
- {Key::COPYRIGHT ,"Copyright"},
- {Key::ORDFEMININE ,"Ordfeminine"},
- {Key::GUILLEMOTLEFT ,"GuillemotLeft"},
- {Key::NOTSIGN ,"NotSign"},
- {Key::HYPHEN ,"Hyphen"},
- {Key::KEY_REGISTERED ,"Registered"},
- {Key::MACRON ,"Macron"},
- {Key::DEGREE ,"Degree"},
- {Key::PLUSMINUS ,"PlusMinus"},
- {Key::TWOSUPERIOR ,"TwoSuperior"},
- {Key::THREESUPERIOR ,"ThreeSuperior"},
- {Key::ACUTE ,"Acute"},
- {Key::MU ,"Mu"},
- {Key::PARAGRAPH ,"Paragraph"},
- {Key::PERIODCENTERED ,"PeriodCentered"},
- {Key::CEDILLA ,"Cedilla"},
- {Key::ONESUPERIOR ,"OneSuperior"},
- {Key::MASCULINE ,"Masculine"},
- {Key::GUILLEMOTRIGHT ,"GuillemotRight"},
- {Key::ONEQUARTER ,"OneQuarter"},
- {Key::ONEHALF ,"OneHalf"},
- {Key::THREEQUARTERS ,"ThreeQuarters"},
- {Key::QUESTIONDOWN ,"QuestionDown"},
- {Key::AGRAVE ,"Agrave"},
- {Key::AACUTE ,"Aacute"},
- {Key::ACIRCUMFLEX ,"AcircumFlex"},
- {Key::ATILDE ,"Atilde"},
- {Key::ADIAERESIS ,"Adiaeresis"},
- {Key::ARING ,"Aring"},
- {Key::AE ,"Ae"},
- {Key::CCEDILLA ,"Ccedilla"},
- {Key::EGRAVE ,"Egrave"},
- {Key::EACUTE ,"Eacute"},
- {Key::ECIRCUMFLEX ,"Ecircumflex"},
- {Key::EDIAERESIS ,"Ediaeresis"},
- {Key::IGRAVE ,"Igrave"},
- {Key::IACUTE ,"Iacute"},
- {Key::ICIRCUMFLEX ,"Icircumflex"},
- {Key::IDIAERESIS ,"Idiaeresis"},
- {Key::ETH ,"Eth"},
- {Key::NTILDE ,"Ntilde"},
- {Key::OGRAVE ,"Ograve"},
- {Key::OACUTE ,"Oacute"},
- {Key::OCIRCUMFLEX ,"Ocircumflex"},
- {Key::OTILDE ,"Otilde"},
- {Key::ODIAERESIS ,"Odiaeresis"},
- {Key::MULTIPLY ,"Multiply"},
- {Key::OOBLIQUE ,"Ooblique"},
- {Key::UGRAVE ,"Ugrave"},
- {Key::UACUTE ,"Uacute"},
- {Key::UCIRCUMFLEX ,"Ucircumflex"},
- {Key::UDIAERESIS ,"Udiaeresis"},
- {Key::YACUTE ,"Yacute"},
- {Key::THORN ,"Thorn"},
- {Key::SSHARP ,"Ssharp"},
- {Key::DIVISION ,"Division"},
- {Key::YDIAERESIS ,"Ydiaeresis"},
{Key::NONE ,nullptr}
/* clang-format on */
};
@@ -378,14 +306,9 @@ bool keycode_has_unicode(Key p_keycode) {
case Key::F33:
case Key::F34:
case Key::F35:
- case Key::SUPER_L:
- case Key::SUPER_R:
case Key::MENU:
- case Key::HYPER_L:
- case Key::HYPER_R:
+ case Key::HYPER:
case Key::HELP:
- case Key::DIRECTION_L:
- case Key::DIRECTION_R:
case Key::BACK:
case Key::FORWARD:
case Key::STOP:
@@ -393,11 +316,6 @@ bool keycode_has_unicode(Key p_keycode) {
case Key::VOLUMEDOWN:
case Key::VOLUMEMUTE:
case Key::VOLUMEUP:
- case Key::BASSBOOST:
- case Key::BASSUP:
- case Key::BASSDOWN:
- case Key::TREBLEUP:
- case Key::TREBLEDOWN:
case Key::MEDIAPLAY:
case Key::MEDIASTOP:
case Key::MEDIAPREVIOUS:
@@ -426,6 +344,10 @@ bool keycode_has_unicode(Key p_keycode) {
case Key::LAUNCHD:
case Key::LAUNCHE:
case Key::LAUNCHF:
+ case Key::GLOBE:
+ case Key::KEYBOARD:
+ case Key::JIS_EISU:
+ case Key::JIS_KANA:
return false;
default: {
}
@@ -522,3 +444,24 @@ int keycode_get_value_by_index(int p_index) {
const char *keycode_get_name_by_index(int p_index) {
return _keycodes[p_index].text;
}
+
+char32_t fix_unicode(char32_t p_char) {
+ if (p_char >= 0x20 && p_char != 0x7F) {
+ return p_char;
+ }
+ return 0;
+}
+
+Key fix_keycode(char32_t p_char, Key p_key) {
+ if (p_char >= 0x20 && p_char <= 0x7E) {
+ return (Key)String::char_uppercase(p_char);
+ }
+ return p_key;
+}
+
+Key fix_key_label(char32_t p_char, Key p_key) {
+ if (p_char >= 0x20 && p_char != 0x7F) {
+ return (Key)String::char_uppercase(p_char);
+ }
+ return p_key;
+}
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index c78fa2a631..6315356510 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -127,11 +127,8 @@ enum class Key {
SUPER_L = SPECIAL | 0x40,
SUPER_R = SPECIAL | 0x41,
MENU = SPECIAL | 0x42,
- HYPER_L = SPECIAL | 0x43,
- HYPER_R = SPECIAL | 0x44,
+ HYPER = SPECIAL | 0x43,
HELP = SPECIAL | 0x45,
- DIRECTION_L = SPECIAL | 0x46,
- DIRECTION_R = SPECIAL | 0x47,
BACK = SPECIAL | 0x48,
FORWARD = SPECIAL | 0x49,
STOP = SPECIAL | 0x4A,
@@ -139,11 +136,6 @@ enum class Key {
VOLUMEDOWN = SPECIAL | 0x4C,
VOLUMEMUTE = SPECIAL | 0x4D,
VOLUMEUP = SPECIAL | 0x4E,
- BASSBOOST = SPECIAL | 0x4F,
- BASSUP = SPECIAL | 0x50,
- BASSDOWN = SPECIAL | 0x51,
- TREBLEUP = SPECIAL | 0x52,
- TREBLEDOWN = SPECIAL | 0x53,
MEDIAPLAY = SPECIAL | 0x54,
MEDIASTOP = SPECIAL | 0x55,
MEDIAPREVIOUS = SPECIAL | 0x56,
@@ -173,7 +165,12 @@ enum class Key {
LAUNCHE = SPECIAL | 0x6E,
LAUNCHF = SPECIAL | 0x6F,
- UNKNOWN = SPECIAL | 0xFFFFFF,
+ GLOBE = SPECIAL | 0x70,
+ KEYBOARD = SPECIAL | 0x71,
+ JIS_EISU = SPECIAL | 0x72,
+ JIS_KANA = SPECIAL | 0x73,
+
+ UNKNOWN = SPECIAL | 0x7FFFFF,
/* PRINTABLE LATIN 1 CODES */
@@ -246,74 +243,8 @@ enum class Key {
BAR = 0x007C,
BRACERIGHT = 0x007D,
ASCIITILDE = 0x007E,
- NOBREAKSPACE = 0x00A0,
- EXCLAMDOWN = 0x00A1,
- CENT = 0x00A2,
- STERLING = 0x00A3,
- CURRENCY = 0x00A4,
YEN = 0x00A5,
- BROKENBAR = 0x00A6,
SECTION = 0x00A7,
- DIAERESIS = 0x00A8,
- COPYRIGHT = 0x00A9,
- ORDFEMININE = 0x00AA,
- GUILLEMOTLEFT = 0x00AB,
- NOTSIGN = 0x00AC,
- HYPHEN = 0x00AD,
- KEY_REGISTERED = 0x00AE, // "REGISTERED" is a reserved word on Windows.
- MACRON = 0x00AF,
- DEGREE = 0x00B0,
- PLUSMINUS = 0x00B1,
- TWOSUPERIOR = 0x00B2,
- THREESUPERIOR = 0x00B3,
- ACUTE = 0x00B4,
- MU = 0x00B5,
- PARAGRAPH = 0x00B6,
- PERIODCENTERED = 0x00B7,
- CEDILLA = 0x00B8,
- ONESUPERIOR = 0x00B9,
- MASCULINE = 0x00BA,
- GUILLEMOTRIGHT = 0x00BB,
- ONEQUARTER = 0x00BC,
- ONEHALF = 0x00BD,
- THREEQUARTERS = 0x00BE,
- QUESTIONDOWN = 0x00BF,
- AGRAVE = 0x00C0,
- AACUTE = 0x00C1,
- ACIRCUMFLEX = 0x00C2,
- ATILDE = 0x00C3,
- ADIAERESIS = 0x00C4,
- ARING = 0x00C5,
- AE = 0x00C6,
- CCEDILLA = 0x00C7,
- EGRAVE = 0x00C8,
- EACUTE = 0x00C9,
- ECIRCUMFLEX = 0x00CA,
- EDIAERESIS = 0x00CB,
- IGRAVE = 0x00CC,
- IACUTE = 0x00CD,
- ICIRCUMFLEX = 0x00CE,
- IDIAERESIS = 0x00CF,
- ETH = 0x00D0,
- NTILDE = 0x00D1,
- OGRAVE = 0x00D2,
- OACUTE = 0x00D3,
- OCIRCUMFLEX = 0x00D4,
- OTILDE = 0x00D5,
- ODIAERESIS = 0x00D6,
- MULTIPLY = 0x00D7,
- OOBLIQUE = 0x00D8,
- UGRAVE = 0x00D9,
- UACUTE = 0x00DA,
- UCIRCUMFLEX = 0x00DB,
- UDIAERESIS = 0x00DC,
- YACUTE = 0x00DD,
- THORN = 0x00DE,
- SSHARP = 0x00DF,
-
- DIVISION = 0x00F7,
- YDIAERESIS = 0x00FF,
- END_LATIN1 = 0x0100,
};
enum class KeyModifierMask {
@@ -407,4 +338,8 @@ int keycode_get_count();
int keycode_get_value_by_index(int p_index);
const char *keycode_get_name_by_index(int p_index);
+char32_t fix_unicode(char32_t p_char);
+Key fix_keycode(char32_t p_char, Key p_key);
+Key fix_key_label(char32_t p_char, Key p_key);
+
#endif // KEYBOARD_H
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 7e7cb07cef..2be15d5100 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1767,30 +1767,15 @@
<constant name="KEY_KP_9" value="4194447" enum="Key">
Number 9 on the numeric keypad.
</constant>
- <constant name="KEY_SUPER_L" value="4194368" enum="Key">
- Left Super key (Windows key).
- </constant>
- <constant name="KEY_SUPER_R" value="4194369" enum="Key">
- Right Super key (Windows key).
- </constant>
<constant name="KEY_MENU" value="4194370" enum="Key">
Context menu key.
</constant>
- <constant name="KEY_HYPER_L" value="4194371" enum="Key">
- Left Hyper key.
- </constant>
- <constant name="KEY_HYPER_R" value="4194372" enum="Key">
- Right Hyper key.
+ <constant name="KEY_HYPER" value="4194371" enum="Key">
+ Hyper key. (On Linux/X11 only).
</constant>
<constant name="KEY_HELP" value="4194373" enum="Key">
Help key.
</constant>
- <constant name="KEY_DIRECTION_L" value="4194374" enum="Key">
- Left Direction key.
- </constant>
- <constant name="KEY_DIRECTION_R" value="4194375" enum="Key">
- Right Direction key.
- </constant>
<constant name="KEY_BACK" value="4194376" enum="Key">
Media back key. Not to be confused with the Back button on an Android device.
</constant>
@@ -1812,21 +1797,6 @@
<constant name="KEY_VOLUMEUP" value="4194382" enum="Key">
Volume up key.
</constant>
- <constant name="KEY_BASSBOOST" value="4194383" enum="Key">
- Bass Boost key.
- </constant>
- <constant name="KEY_BASSUP" value="4194384" enum="Key">
- Bass up key.
- </constant>
- <constant name="KEY_BASSDOWN" value="4194385" enum="Key">
- Bass down key.
- </constant>
- <constant name="KEY_TREBLEUP" value="4194386" enum="Key">
- Treble up key.
- </constant>
- <constant name="KEY_TREBLEDOWN" value="4194387" enum="Key">
- Treble down key.
- </constant>
<constant name="KEY_MEDIAPLAY" value="4194388" enum="Key">
Media play key.
</constant>
@@ -1911,7 +1881,7 @@
<constant name="KEY_LAUNCHF" value="4194415" enum="Key">
Launch Shortcut F key.
</constant>
- <constant name="KEY_UNKNOWN" value="16777215" enum="Key">
+ <constant name="KEY_UNKNOWN" value="8388607" enum="Key">
Unknown key.
</constant>
<constant name="KEY_SPACE" value="32" enum="Key">
@@ -2121,203 +2091,23 @@
<constant name="KEY_ASCIITILDE" value="126" enum="Key">
~ key.
</constant>
- <constant name="KEY_NOBREAKSPACE" value="160" enum="Key">
- Non-breakable space key.
- </constant>
- <constant name="KEY_EXCLAMDOWN" value="161" enum="Key">
- ¡ key.
- </constant>
- <constant name="KEY_CENT" value="162" enum="Key">
- ¢ key.
- </constant>
- <constant name="KEY_STERLING" value="163" enum="Key">
- £ key.
- </constant>
- <constant name="KEY_CURRENCY" value="164" enum="Key">
- ¤ key.
- </constant>
<constant name="KEY_YEN" value="165" enum="Key">
¥ key.
</constant>
- <constant name="KEY_BROKENBAR" value="166" enum="Key">
- ¦ key.
- </constant>
<constant name="KEY_SECTION" value="167" enum="Key">
§ key.
</constant>
- <constant name="KEY_DIAERESIS" value="168" enum="Key">
- ¨ key.
- </constant>
- <constant name="KEY_COPYRIGHT" value="169" enum="Key">
- © key.
- </constant>
- <constant name="KEY_ORDFEMININE" value="170" enum="Key">
- ª key.
- </constant>
- <constant name="KEY_GUILLEMOTLEFT" value="171" enum="Key">
- « key.
- </constant>
- <constant name="KEY_NOTSIGN" value="172" enum="Key">
- ¬ key.
- </constant>
- <constant name="KEY_HYPHEN" value="173" enum="Key">
- Soft hyphen key.
- </constant>
- <constant name="KEY_REGISTERED" value="174" enum="Key">
- ® key.
- </constant>
- <constant name="KEY_MACRON" value="175" enum="Key">
- ¯ key.
- </constant>
- <constant name="KEY_DEGREE" value="176" enum="Key">
- ° key.
- </constant>
- <constant name="KEY_PLUSMINUS" value="177" enum="Key">
- ± key.
- </constant>
- <constant name="KEY_TWOSUPERIOR" value="178" enum="Key">
- ² key.
- </constant>
- <constant name="KEY_THREESUPERIOR" value="179" enum="Key">
- ³ key.
- </constant>
- <constant name="KEY_ACUTE" value="180" enum="Key">
- ´ key.
- </constant>
- <constant name="KEY_MU" value="181" enum="Key">
- µ key.
- </constant>
- <constant name="KEY_PARAGRAPH" value="182" enum="Key">
- ¶ key.
- </constant>
- <constant name="KEY_PERIODCENTERED" value="183" enum="Key">
- · key.
- </constant>
- <constant name="KEY_CEDILLA" value="184" enum="Key">
- ¸ key.
- </constant>
- <constant name="KEY_ONESUPERIOR" value="185" enum="Key">
- ¹ key.
- </constant>
- <constant name="KEY_MASCULINE" value="186" enum="Key">
- º key.
- </constant>
- <constant name="KEY_GUILLEMOTRIGHT" value="187" enum="Key">
- » key.
- </constant>
- <constant name="KEY_ONEQUARTER" value="188" enum="Key">
- ¼ key.
- </constant>
- <constant name="KEY_ONEHALF" value="189" enum="Key">
- ½ key.
- </constant>
- <constant name="KEY_THREEQUARTERS" value="190" enum="Key">
- ¾ key.
- </constant>
- <constant name="KEY_QUESTIONDOWN" value="191" enum="Key">
- ¿ key.
- </constant>
- <constant name="KEY_AGRAVE" value="192" enum="Key">
- À key.
- </constant>
- <constant name="KEY_AACUTE" value="193" enum="Key">
- Á key.
- </constant>
- <constant name="KEY_ACIRCUMFLEX" value="194" enum="Key">
- Â key.
- </constant>
- <constant name="KEY_ATILDE" value="195" enum="Key">
- Ã key.
- </constant>
- <constant name="KEY_ADIAERESIS" value="196" enum="Key">
- Ä key.
- </constant>
- <constant name="KEY_ARING" value="197" enum="Key">
- Å key.
- </constant>
- <constant name="KEY_AE" value="198" enum="Key">
- Æ key.
- </constant>
- <constant name="KEY_CCEDILLA" value="199" enum="Key">
- Ç key.
- </constant>
- <constant name="KEY_EGRAVE" value="200" enum="Key">
- È key.
- </constant>
- <constant name="KEY_EACUTE" value="201" enum="Key">
- É key.
- </constant>
- <constant name="KEY_ECIRCUMFLEX" value="202" enum="Key">
- Ê key.
- </constant>
- <constant name="KEY_EDIAERESIS" value="203" enum="Key">
- Ë key.
- </constant>
- <constant name="KEY_IGRAVE" value="204" enum="Key">
- Ì key.
- </constant>
- <constant name="KEY_IACUTE" value="205" enum="Key">
- Í key.
- </constant>
- <constant name="KEY_ICIRCUMFLEX" value="206" enum="Key">
- Î key.
- </constant>
- <constant name="KEY_IDIAERESIS" value="207" enum="Key">
- Ï key.
- </constant>
- <constant name="KEY_ETH" value="208" enum="Key">
- Ð key.
- </constant>
- <constant name="KEY_NTILDE" value="209" enum="Key">
- Ñ key.
- </constant>
- <constant name="KEY_OGRAVE" value="210" enum="Key">
- Ò key.
- </constant>
- <constant name="KEY_OACUTE" value="211" enum="Key">
- Ó key.
- </constant>
- <constant name="KEY_OCIRCUMFLEX" value="212" enum="Key">
- Ô key.
- </constant>
- <constant name="KEY_OTILDE" value="213" enum="Key">
- Õ key.
- </constant>
- <constant name="KEY_ODIAERESIS" value="214" enum="Key">
- Ö key.
- </constant>
- <constant name="KEY_MULTIPLY" value="215" enum="Key">
- × key.
- </constant>
- <constant name="KEY_OOBLIQUE" value="216" enum="Key">
- Ø key.
- </constant>
- <constant name="KEY_UGRAVE" value="217" enum="Key">
- Ù key.
- </constant>
- <constant name="KEY_UACUTE" value="218" enum="Key">
- Ú key.
- </constant>
- <constant name="KEY_UCIRCUMFLEX" value="219" enum="Key">
- Û key.
- </constant>
- <constant name="KEY_UDIAERESIS" value="220" enum="Key">
- Ü key.
- </constant>
- <constant name="KEY_YACUTE" value="221" enum="Key">
- Ý key.
- </constant>
- <constant name="KEY_THORN" value="222" enum="Key">
- Þ key.
+ <constant name="KEY_GLOBE" value="4194416" enum="Key">
+ "Globe" key on Mac / iPad keyboard.
</constant>
- <constant name="KEY_SSHARP" value="223" enum="Key">
- ß key.
+ <constant name="KEY_KEYBOARD" value="4194417" enum="Key">
+ "On-screen keyboard" key iPad keyboard.
</constant>
- <constant name="KEY_DIVISION" value="247" enum="Key">
- ÷ key.
+ <constant name="KEY_JIS_EISU" value="4194418" enum="Key">
+ 英数 key on Mac keyboard.
</constant>
- <constant name="KEY_YDIAERESIS" value="255" enum="Key">
- ÿ key.
+ <constant name="KEY_JIS_KANA" value="4194419" enum="Key">
+ かな key on Mac keyboard.
</constant>
<constant name="KEY_CODE_MASK" value="8388607" enum="KeyModifierMask" is_bitfield="true">
Key Code mask.
diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml
index 4da9e41ca8..c0e5d6ad07 100644
--- a/doc/classes/AcceptDialog.xml
+++ b/doc/classes/AcceptDialog.xml
@@ -53,7 +53,7 @@
<return type="void" />
<param index="0" name="button" type="Control" />
<description>
- Removes the [param button] from the dialog. Does NOT free the [param button]. The [param button] must be a [Button] added with [method add_button] or [method add_cancel_button] method. After removal, pressing the [param button] will no longer emit this dialog's [signal custom_action] or [signal cancelled] signals.
+ Removes the [param button] from the dialog. Does NOT free the [param button]. The [param button] must be a [Button] added with [method add_button] or [method add_cancel_button] method. After removal, pressing the [param button] will no longer emit this dialog's [signal custom_action] or [signal canceled] signals.
</description>
</method>
</methods>
@@ -81,7 +81,7 @@
<member name="wrap_controls" type="bool" setter="set_wrap_controls" getter="is_wrapping_controls" overrides="Window" default="true" />
</members>
<signals>
- <signal name="cancelled">
+ <signal name="canceled">
<description>
Emitted when the dialog is closed or the button created with [method add_cancel_button] is pressed.
</description>
diff --git a/doc/classes/AnimatableBody3D.xml b/doc/classes/AnimatableBody3D.xml
index 2a08c4c8f1..0733780bf7 100644
--- a/doc/classes/AnimatableBody3D.xml
+++ b/doc/classes/AnimatableBody3D.xml
@@ -7,6 +7,7 @@
Animatable body for 3D physics.
An animatable body can't be moved by external forces or contacts, but can be moved by script or animation to affect other bodies in its path. It is ideal for implementing moving objects in the environment, such as moving platforms or doors.
When the body is moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to [code]physics[/code]), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc).
+ [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead.
</description>
<tutorials>
<link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link>
diff --git a/doc/classes/AnimationNodeStateMachinePlayback.xml b/doc/classes/AnimationNodeStateMachinePlayback.xml
index 7e01be12c4..17a946bb3e 100644
--- a/doc/classes/AnimationNodeStateMachinePlayback.xml
+++ b/doc/classes/AnimationNodeStateMachinePlayback.xml
@@ -38,6 +38,12 @@
Returns the playback position within the current animation state.
</description>
</method>
+ <method name="get_fading_from_node" qualifiers="const">
+ <return type="StringName" />
+ <description>
+ Returns the starting state of currently fading animation.
+ </description>
+ </method>
<method name="get_travel_path" qualifiers="const">
<return type="PackedStringArray" />
<description>
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index a17a727d7e..49bc4ee6af 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -104,7 +104,7 @@
</member>
<member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath(&quot;&quot;)">
The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code].
- If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D] or [constant Animation.TYPE_SCALE_3D] the transformation will be cancelled visually, and the animation will appear to stay in place. See also [method get_root_motion_position], [method get_root_motion_rotation], [method get_root_motion_scale] and [RootMotionView].
+ If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D] or [constant Animation.TYPE_SCALE_3D] the transformation will be canceled visually, and the animation will appear to stay in place. See also [method get_root_motion_position], [method get_root_motion_rotation], [method get_root_motion_scale] and [RootMotionView].
</member>
<member name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root">
The root animation node of this [AnimationTree]. See [AnimationNode].
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index 8923ac8aae..d40bca99d8 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -7,6 +7,7 @@
3D area that detects [CollisionObject3D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to custom audio buses.
To give the area its shape, add a [CollisionShape3D] or a [CollisionPolygon3D] node as a [i]direct[/i] child (or add multiple such nodes as direct children) of the area.
[b]Warning:[/b] See [ConcavePolygonShape3D] (also called "trimesh") for a warning about possibly unexpected behavior when using that shape for an area.
+ [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead.
</description>
<tutorials>
<link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link>
diff --git a/doc/classes/AudioStreamPlaybackPolyphonic.xml b/doc/classes/AudioStreamPlaybackPolyphonic.xml
new file mode 100644
index 0000000000..8b0951153b
--- /dev/null
+++ b/doc/classes/AudioStreamPlaybackPolyphonic.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AudioStreamPlaybackPolyphonic" inherits="AudioStreamPlayback" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Playback instance for [AudioStreamPolyphonic].
+ </brief_description>
+ <description>
+ Playback instance for [AudioStreamPolyphonic]. After setting the [code]stream[/code] property of [AudioStreamPlayer], [AudioStreamPlayer2D], or [AudioStreamPlayer3D], the playback instance can be obtained by calling [method AudioStreamPlayer.get_stream_playback], [method AudioStreamPlayer2D.get_stream_playback] or [method AudioStreamPlayer3D.get_stream_playback] methods.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="is_stream_playing" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="stream" type="int" />
+ <description>
+ Return true whether the stream associated with an integer ID is still playing. Check [method play_stream] for information on when this ID becomes invalid.
+ </description>
+ </method>
+ <method name="play_stream">
+ <return type="int" />
+ <param index="0" name="stream" type="AudioStream" />
+ <param index="1" name="from_offset" type="float" default="0" />
+ <param index="2" name="volume_db" type="float" default="0" />
+ <param index="3" name="pitch_scale" type="float" default="1.0" />
+ <description>
+ Play an [AudioStream] at a given offset, volume and pitch scale. Playback starts immediately.
+ The return value is an unique integer ID that is associated to this playback stream and which can be used to control it.
+ This ID becomes invalid when the stream ends (if it does not loop), when the [AudioStreamPlaybackPolyphonic] is stopped, or when [method stop_stream] is called.
+ This function returns [constant INVALID_ID] if the amount of streams currently playing equals [member AudioStreamPolyphonic.polyphony]. If you need a higher amount of maximum polyphony, raise this value.
+ </description>
+ </method>
+ <method name="set_stream_pitch_scale">
+ <return type="void" />
+ <param index="0" name="stream" type="int" />
+ <param index="1" name="pitch_scale" type="float" />
+ <description>
+ Change the stream pitch scale. The [param stream] argument is an integer ID returned by [method play_stream].
+ </description>
+ </method>
+ <method name="set_stream_volume">
+ <return type="void" />
+ <param index="0" name="stream" type="int" />
+ <param index="1" name="volume_db" type="float" />
+ <description>
+ Change the stream volume (in db). The [param stream] argument is an integer ID returned by [method play_stream].
+ </description>
+ </method>
+ <method name="stop_stream">
+ <return type="void" />
+ <param index="0" name="stream" type="int" />
+ <description>
+ Stop a stream. The [param stream] argument is an integer ID returned by [method play_stream], which becomes invalid after calling this function.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="INVALID_ID" value="-1">
+ Returned by [method play_stream] in case it could not allocate a stream for playback.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/AudioStreamPolyphonic.xml b/doc/classes/AudioStreamPolyphonic.xml
new file mode 100644
index 0000000000..baa1fc7037
--- /dev/null
+++ b/doc/classes/AudioStreamPolyphonic.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="AudioStreamPolyphonic" inherits="AudioStream" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ AudioStream that lets the user play custom streams at any time from code, simultaneously using a single player.
+ </brief_description>
+ <description>
+ AudioStream that lets the user play custom streams at any time from code, simultaneously using a single player.
+ Playback control is done via the [AudioStreamPlaybackPolyphonic] instance set inside the player, which can be obtained via [method AudioStreamPlayer.get_stream_playback], [method AudioStreamPlayer2D.get_stream_playback] or [method AudioStreamPlayer3D.get_stream_playback] methods. Obtaining the playback instance is only valid after the [code]stream[/code] property is set as an [AudioStreamPolyphonic] in those players.
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="polyphony" type="int" setter="set_polyphony" getter="get_polyphony" default="32">
+ Maximum amount of simultaneous streams that can be played.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml
index 821117122c..2ff207acb7 100644
--- a/doc/classes/CharacterBody3D.xml
+++ b/doc/classes/CharacterBody3D.xml
@@ -5,8 +5,9 @@
</brief_description>
<description>
Character bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a rigid body, these are the same as a [AnimatableBody3D]. However, they have two main uses:
- [b]Kinematic characters:[/b] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody3D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics.
- [b]Kinematic motion:[/b] Character bodies can also be used for kinematic motion (same functionality as [AnimatableBody3D]), which allows them to be moved by code and push other bodies on their path.
+ [i]Kinematic characters:[/i] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody3D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics.
+ [i]Kinematic motion:[/i] Character bodies can also be used for kinematic motion (same functionality as [AnimatableBody3D]), which allows them to be moved by code and push other bodies on their path.
+ [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead.
</description>
<tutorials>
<link title="Kinematic character (2D)">$DOCS_URL/tutorials/physics/kinematic_character_2d.html</link>
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index 31b5842930..01b0d88326 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
CollisionObject3D is the base class for physics objects. It can hold any number of collision [Shape3D]s. Each shape must be assigned to a [i]shape owner[/i]. The CollisionObject3D can have any number of shape owners. Shape owners are not nodes and do not appear in the editor, but are accessible through code using the [code]shape_owner_*[/code] methods.
+ [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CollisionPolygon3D.xml b/doc/classes/CollisionPolygon3D.xml
index 7d718cff27..29e55367a8 100644
--- a/doc/classes/CollisionPolygon3D.xml
+++ b/doc/classes/CollisionPolygon3D.xml
@@ -6,6 +6,7 @@
<description>
Allows editing a concave or convex collision polygon's vertices on a selected plane. Can also set a depth perpendicular to that plane. This class is only available in the editor. It will not appear in the scene tree at run-time. Creates several [ConvexPolygonShape3D]s at run-time to represent the original polygon using convex decomposition.
[b]Note:[/b] Since this is an editor-only helper, properties modified during gameplay will have no effect.
+ [b]Warning:[/b] A non-uniformly scaled CollisionPolygon3D node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change its [member polygon]'s vertices instead.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CollisionShape3D.xml b/doc/classes/CollisionShape3D.xml
index 304b46ba27..c5d05670e9 100644
--- a/doc/classes/CollisionShape3D.xml
+++ b/doc/classes/CollisionShape3D.xml
@@ -6,6 +6,7 @@
<description>
Editor facility for creating and editing collision shapes in 3D space. Set the [member shape] property to configure the shape. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject3D.shape_owner_get_shape] to get the actual shape.
You can use this node to represent all sorts of collision shapes, for example, add this to an [Area3D] to give it a detection shape, or add it to a [PhysicsBody3D] to create a solid object.
+ [b]Warning:[/b] A non-uniformly scaled CollisionShape3D node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size of its [member shape] resource instead.
</description>
<tutorials>
<link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link>
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index d1387d088d..57278d9241 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -101,7 +101,7 @@
<return type="Color" />
<param index="0" name="over" type="Color" />
<description>
- Returns a new color resulting from overlaying this color over the given color. In a painting program, you can imagine it as the [param over] color painted over this colour (including alpha).
+ Returns a new color resulting from overlaying this color over the given color. In a painting program, you can imagine it as the [param over] color painted over this color (including alpha).
[codeblocks]
[gdscript]
var bg = Color(0.0, 1.0, 0.0, 0.5) # Green with alpha of 50%
diff --git a/doc/classes/ConfirmationDialog.xml b/doc/classes/ConfirmationDialog.xml
index 48b4df9126..ac2ea5be17 100644
--- a/doc/classes/ConfirmationDialog.xml
+++ b/doc/classes/ConfirmationDialog.xml
@@ -8,10 +8,10 @@
To get cancel action, you can use:
[codeblocks]
[gdscript]
- get_cancel_button().pressed.connect(self.cancelled)
+ get_cancel_button().pressed.connect(self.canceled)
[/gdscript]
[csharp]
- GetCancelButton().Pressed += Cancelled;
+ GetCancelButton().Pressed += Canceled;
[/csharp]
[/codeblocks]
</description>
diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml
index 362d792b39..72ac95a700 100644
--- a/doc/classes/Curve3D.xml
+++ b/doc/classes/Curve3D.xml
@@ -198,7 +198,7 @@
<param index="1" name="tolerance_length" type="float" default="0.2" />
<description>
Returns a list of points along the curve, with almost uniform density. [param max_stages] controls how many subdivisions a curve segment may face before it is considered approximate enough. Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions per curve segment. Increase with care!
- [param tolerance_length] controls the maximal distance between two neighbouring points, before the segment has to be subdivided.
+ [param tolerance_length] controls the maximal distance between two neighboring points, before the segment has to be subdivided.
</description>
</method>
</methods>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 370be8e9f3..326c4f6456 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -41,6 +41,7 @@
<param index="0" name="object" type="Variant" />
<description>
This function is used for plugins that edit specific object types (nodes or resources). It requests the editor to edit the given object.
+ [param object] can be [code]null[/code] if the plugin was editing an object, but there is no longer any selected object handled by this plugin. It can be used to cleanup editing state.
</description>
</method>
<method name="_enable_plugin" qualifiers="virtual">
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 6ecf903fde..3b0cfb3825 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -224,11 +224,18 @@
Returns [code]true[/code] if the system knows the specified device. This means that it sets all button and axis indices. Unknown joypads are not expected to match these constants, but you can still retrieve events from them.
</description>
</method>
+ <method name="is_key_label_pressed" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="keycode" type="int" enum="Key" />
+ <description>
+ Returns [code]true[/code] if you are pressing the key with the [param keycode] printed on it. You can pass a [enum Key] constant or any Unicode character code.
+ </description>
+ </method>
<method name="is_key_pressed" qualifiers="const">
<return type="bool" />
<param index="0" name="keycode" type="int" enum="Key" />
<description>
- Returns [code]true[/code] if you are pressing the key in the current keyboard layout. You can pass a [enum Key] constant.
+ Returns [code]true[/code] if you are pressing the Latin key in the current keyboard layout. You can pass a [enum Key] constant.
[method is_key_pressed] is only recommended over [method is_physical_key_pressed] in non-game applications. This ensures that shortcut keys behave as expected depending on the user's keyboard layout, as keyboard shortcuts are generally dependent on the keyboard layout in non-game applications. If in doubt, use [method is_physical_key_pressed].
[b]Note:[/b] Due to keyboard ghosting, [method is_key_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information.
</description>
diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml
index c3d682de9e..4d10a183d4 100644
--- a/doc/classes/InputEventKey.xml
+++ b/doc/classes/InputEventKey.xml
@@ -5,15 +5,42 @@
</brief_description>
<description>
Stores key presses on the keyboard. Supports key presses, key releases and [member echo] events.
+ [b]Note:[/b] Events received from the keyboard usually have all properties set. Event mappings should have only one of the [member keycode], [member physical_keycode] or [member unicode] set.
+ When events are compared, properties are checked in the following priority - [member keycode], [member physical_keycode] and [member unicode], events with the first matching value will be considered equal.
</description>
<tutorials>
<link title="InputEvent">$DOCS_URL/tutorials/inputs/inputevent.html</link>
</tutorials>
<methods>
+ <method name="as_text_key_label" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns a [String] representation of the event's [member key_label] and modifiers.
+ </description>
+ </method>
+ <method name="as_text_keycode" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns a [String] representation of the event's [member keycode] and modifiers.
+ </description>
+ </method>
+ <method name="as_text_physical_keycode" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns a [String] representation of the event's [member physical_keycode] and modifiers.
+ </description>
+ </method>
+ <method name="get_key_label_with_modifiers" qualifiers="const">
+ <return type="int" enum="Key" />
+ <description>
+ Returns the localized key label combined with modifier keys such as [kbd]Shift[/kbd] or [kbd]Alt[/kbd]. See also [InputEventWithModifiers].
+ To get a human-readable representation of the [InputEventKey] with modifiers, use [code]OS.get_keycode_string(event.get_key_label_with_modifiers())[/code] where [code]event[/code] is the [InputEventKey].
+ </description>
+ </method>
<method name="get_keycode_with_modifiers" qualifiers="const">
<return type="int" enum="Key" />
<description>
- Returns the keycode combined with modifier keys such as [kbd]Shift[/kbd] or [kbd]Alt[/kbd]. See also [InputEventWithModifiers].
+ Returns the Latin keycode combined with modifier keys such as [kbd]Shift[/kbd] or [kbd]Alt[/kbd]. See also [InputEventWithModifiers].
To get a human-readable representation of the [InputEventKey] with modifiers, use [code]OS.get_keycode_string(event.get_keycode_with_modifiers())[/code] where [code]event[/code] is the [InputEventKey].
</description>
</method>
@@ -29,19 +56,36 @@
<member name="echo" type="bool" setter="set_echo" getter="is_echo" default="false">
If [code]true[/code], the key was already pressed before this event. It means the user is holding the key down.
</member>
+ <member name="key_label" type="int" setter="set_key_label" getter="get_key_label" enum="Key" default="0">
+ Represents the localized label printed on the key in the current keyboard layout, which corresponds to one of the [enum Key] constants or any valid Unicode character.
+ For keyboard layouts with a single label on the key, it is equivalent to [member keycode].
+ To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.key_label)[/code] where [code]event[/code] is the [InputEventKey].
+ [codeblock]
+ +-----+ +-----+
+ | Q | | Q | - "Q" - keycode
+ | Й | | ض | - "Й" and "ض" - key_label
+ +-----+ +-----+
+ [/codeblock]
+ </member>
<member name="keycode" type="int" setter="set_keycode" getter="get_keycode" enum="Key" default="0">
- The key keycode, which corresponds to one of the [enum Key] constants. Represent key in the current keyboard layout.
+ Latin label printed on the key in the current keyboard layout, which corresponds to one of the [enum Key] constants.
To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.keycode)[/code] where [code]event[/code] is the [InputEventKey].
+ [codeblock]
+ +-----+ +-----+
+ | Q | | Q | - "Q" - keycode
+ | Й | | ض | - "Й" and "ض" - key_label
+ +-----+ +-----+
+ [/codeblock]
</member>
<member name="physical_keycode" type="int" setter="set_physical_keycode" getter="get_physical_keycode" enum="Key" default="0">
- Key physical keycode, which corresponds to one of the [enum Key] constants. Represent the physical location of a key on the 101/102-key US QWERTY keyboard.
+ Represents the physical location of a key on the 101/102-key US QWERTY keyboard, which corresponds to one of the [enum Key] constants.
To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.keycode)[/code] where [code]event[/code] is the [InputEventKey].
</member>
<member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false">
If [code]true[/code], the key's state is pressed. If [code]false[/code], the key's state is released.
</member>
<member name="unicode" type="int" setter="set_unicode" getter="get_unicode" default="0">
- The key Unicode identifier (when relevant). Unicode identifiers for the composite characters and complex scripts may not be available unless IME input mode is active. See [method Window.set_ime_active] for more information.
+ The key Unicode character code (when relevant), shifted by modifier keys. Unicode character codes for composite characters and complex scripts may not be available unless IME input mode is active. See [method Window.set_ime_active] for more information.
</member>
</members>
</class>
diff --git a/doc/classes/InputEventWithModifiers.xml b/doc/classes/InputEventWithModifiers.xml
index c6311d780c..26b88e6ff2 100644
--- a/doc/classes/InputEventWithModifiers.xml
+++ b/doc/classes/InputEventWithModifiers.xml
@@ -10,6 +10,12 @@
<link title="InputEvent">$DOCS_URL/tutorials/inputs/inputevent.html</link>
</tutorials>
<methods>
+ <method name="get_modifiers_mask" qualifiers="const">
+ <return type="int" enum="KeyModifierMask" />
+ <description>
+ Returns the keycode combination of modifier keys.
+ </description>
+ </method>
<method name="is_command_or_control_pressed" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
index fe7756faaf..95c39d535e 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -80,7 +80,7 @@
A typical household lightbulb can range from around 600 lumens to 1,200 lumens, a candle is about 13 lumens, while a streetlight can be approximately 60,000 lumens.
</member>
<member name="light_intensity_lux" type="float" setter="set_param" getter="get_param">
- Used by [DirectionalLight3D]s when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is [code]true[/code]. Sets the intensity of the light source measured in Lux. Lux is a measure pf luminous flux per unit area, it is equal to one lumen per square metre. Lux is the measure of how much light hits a surface at a given time.
+ Used by [DirectionalLight3D]s when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is [code]true[/code]. Sets the intensity of the light source measured in Lux. Lux is a measure of luminous flux per unit area, it is equal to one lumen per square meter. Lux is the measure of how much light hits a surface at a given time.
On a clear sunny day a surface in direct sunlight may be approximately 100,000 lux, a typical room in a home may be approximately 50 lux, while the moonlit ground may be approximately 0.1 lux.
</member>
<member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false">
diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml
index 53dae1a8e6..723e6bbf21 100644
--- a/doc/classes/LightmapGI.xml
+++ b/doc/classes/LightmapGI.xml
@@ -93,22 +93,28 @@
<constant name="BAKE_ERROR_OK" value="0" enum="BakeError">
Lightmap baking was successful.
</constant>
- <constant name="BAKE_ERROR_NO_LIGHTMAPPER" value="1" enum="BakeError">
+ <constant name="BAKE_ERROR_NO_SCENE_ROOT" value="1" enum="BakeError">
+ Lightmap baking failed because the root node for the edited scene could not be accessed.
+ </constant>
+ <constant name="BAKE_ERROR_FOREIGN_DATA" value="2" enum="BakeError">
+ Lightmap baking failed as the lightmap data resource is embedded in a foreign resource.
+ </constant>
+ <constant name="BAKE_ERROR_NO_LIGHTMAPPER" value="3" enum="BakeError">
Lightmap baking failed as there is no lightmapper available in this Godot build.
</constant>
- <constant name="BAKE_ERROR_NO_SAVE_PATH" value="2" enum="BakeError">
+ <constant name="BAKE_ERROR_NO_SAVE_PATH" value="4" enum="BakeError">
Lightmap baking failed as the [LightmapGIData] save path isn't configured in the resource.
</constant>
- <constant name="BAKE_ERROR_NO_MESHES" value="3" enum="BakeError">
+ <constant name="BAKE_ERROR_NO_MESHES" value="5" enum="BakeError">
Lightmap baking failed as there are no meshes whose [member GeometryInstance3D.gi_mode] is [constant GeometryInstance3D.GI_MODE_STATIC] and with valid UV2 mapping in the current scene. You may need to select 3D scenes in the Import dock and change their global illumination mode accordingly.
</constant>
- <constant name="BAKE_ERROR_MESHES_INVALID" value="4" enum="BakeError">
+ <constant name="BAKE_ERROR_MESHES_INVALID" value="6" enum="BakeError">
Lightmap baking failed as the lightmapper failed to analyze some of the meshes marked as static for baking.
</constant>
- <constant name="BAKE_ERROR_CANT_CREATE_IMAGE" value="5" enum="BakeError">
+ <constant name="BAKE_ERROR_CANT_CREATE_IMAGE" value="7" enum="BakeError">
Lightmap baking failed as the resulting image couldn't be saved or imported by Godot after it was saved.
</constant>
- <constant name="BAKE_ERROR_USER_ABORTED" value="6" enum="BakeError">
+ <constant name="BAKE_ERROR_USER_ABORTED" value="8" enum="BakeError">
The user aborted the lightmap baking operation (typically by clicking the [b]Cancel[/b] button in the progress dialog).
</constant>
<constant name="ENVIRONMENT_MODE_DISABLED" value="0" enum="EnvironmentMode">
diff --git a/doc/classes/Marshalls.xml b/doc/classes/Marshalls.xml
index 102e4b75ed..1eeb0be7ce 100644
--- a/doc/classes/Marshalls.xml
+++ b/doc/classes/Marshalls.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Marshalls" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Data transformation (marshalling) and encoding helpers.
+ Data transformation (marshaling) and encoding helpers.
</brief_description>
<description>
Provides data transformation and encoding utility functions.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 02fd6dae30..7b27f16d82 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -909,6 +909,9 @@
<constant name="NOTIFICATION_ENABLED" value="29">
Notification received when the node is enabled again after being disabled. See [constant PROCESS_MODE_DISABLED].
</constant>
+ <constant name="NOTIFICATION_NODE_RECACHE_REQUESTED" value="30">
+ Notification received when other nodes in the tree may have been removed/replaced and node pointers may require re-caching.
+ </constant>
<constant name="NOTIFICATION_EDITOR_PRE_SAVE" value="9001">
Notification received right before the scene with the node is saved in the editor. This notification is only sent in the Godot editor and will not occur in exported projects.
</constant>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 1bc81ffb42..0058bf8a2f 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -566,7 +566,7 @@
<method name="open_midi_inputs">
<return type="void" />
<description>
- Initialises the singleton for the system MIDI driver.
+ Initializes the singleton for the system MIDI driver.
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index a9e17f4666..1a805007e6 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -883,7 +883,7 @@
<param index="0" name="name" type="StringName" />
<param index="1" name="value" type="Variant" />
<description>
- Adds or changes the entry [param name] inside the object's metadata. The metadata [param value] can be any [Variant], although some types cannot be serialised correctly.
+ Adds or changes the entry [param name] inside the object's metadata. The metadata [param value] can be any [Variant], although some types cannot be serialized correctly.
If [param value] is [code]null[/code], the entry is removed. This is the equivalent of using [method remove_meta]. See also [method has_meta] and [method get_meta].
[b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector dock and should not be edited.
</description>
diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml
index 0768df31cc..f38130fe0c 100644
--- a/doc/classes/PhysicalBone3D.xml
+++ b/doc/classes/PhysicalBone3D.xml
@@ -3,6 +3,7 @@
<brief_description>
</brief_description>
<description>
+ [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml
index 2ef54683f2..3e100e3280 100644
--- a/doc/classes/PhysicsBody3D.xml
+++ b/doc/classes/PhysicsBody3D.xml
@@ -4,7 +4,8 @@
Base class for all objects affected by physics in 3D space.
</brief_description>
<description>
- PhysicsBody3D is an abstract base class for implementing a physics body. All *Body types inherit from it.
+ PhysicsBody3D is an abstract base class for implementing a physics body. All *Body3D types inherit from it.
+ [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead.
</description>
<tutorials>
<link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index de41edc305..ec05be368c 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -384,6 +384,9 @@
<member name="debug/gdscript/warnings/assert_always_true" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to true.
</member>
+ <member name="debug/gdscript/warnings/confusable_identifier" type="int" setter="" getter="" default="1">
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an identifier contains characters that can be confused with something else, like when mixing different alphabets.
+ </member>
<member name="debug/gdscript/warnings/constant_used_as_function" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a constant is used as a function.
</member>
@@ -615,8 +618,17 @@
Main window content is expanded to the full size of the window. Unlike a borderless window, the frame is left intact and can be used to resize the window, and the title bar is transparent, but has minimize/maximize/close buttons.
[b]Note:[/b] This setting is implemented only on macOS.
</member>
- <member name="display/window/size/initial_screen" type="int" setter="" getter="" default="-2">
- Main window initial screen.
+ <member name="display/window/size/initial_position" type="Vector2i" setter="" getter="" default="Vector2i(0, 0)">
+ Main window initial position (in virtual desktop coordinates), this settings is used only if [member display/window/size/initial_position_type] is set to "Absolute" ([code]0[/code]).
+ </member>
+ <member name="display/window/size/initial_position_type" type="int" setter="" getter="" default="1">
+ Main window initial position.
+ [code]0[/code] - "Absolute", [member display/window/size/initial_position] is used to set window position.
+ [code]1[/code] - "Primary Screen Center".
+ [code]2[/code] - "Other Screen Center", [member display/window/size/initial_screen] is used to set window position.
+ </member>
+ <member name="display/window/size/initial_screen" type="int" setter="" getter="" default="0">
+ Main window initial screen, this settings is used only if [member display/window/size/initial_position_type] is set to "Other Screen Center" ([code]2[/code]).
</member>
<member name="display/window/size/mode" type="int" setter="" getter="" default="0">
Main window mode. See [enum DisplayServer.WindowMode] for possible values and how each mode behaves.
diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml
index 8380d56de3..148cdf96ee 100644
--- a/doc/classes/RigidBody3D.xml
+++ b/doc/classes/RigidBody3D.xml
@@ -8,6 +8,7 @@
You can switch the body's behavior using [member lock_rotation], [member freeze], and [member freeze_mode].
[b]Note:[/b] Don't change a RigidBody3D's position every frame or very often. Sporadic changes work fine, but physics runs at a different granularity (fixed Hz) than usual rendering (process callback) and maybe even in a separate thread, so changing this from a process loop may result in strange behavior. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state.
If you need to override the default physics behavior, you can write a custom force integration function. See [member custom_integrator].
+ [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead.
</description>
<tutorials>
<link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link>
diff --git a/doc/classes/StaticBody3D.xml b/doc/classes/StaticBody3D.xml
index 0beaa6bb52..7bebd46004 100644
--- a/doc/classes/StaticBody3D.xml
+++ b/doc/classes/StaticBody3D.xml
@@ -7,8 +7,9 @@
Static body for 3D physics.
A static body is a simple body that doesn't move under physics simulation, i.e. it can't be moved by external forces or contacts but its transformation can still be updated manually by the user. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody3D], it doesn't consume any CPU resources as long as they don't move.
They have extra functionalities to move and affect other bodies:
- [b]Static transform change:[/b] Static bodies can be moved by animation or script. In this case, they are just teleported and don't affect other bodies on their path.
- [b]Constant velocity:[/b] When [member constant_linear_velocity] or [member constant_angular_velocity] is set, static bodies don't move themselves but affect touching bodies as if they were moving. This is useful for simulating conveyor belts or conveyor wheels.
+ [i]Static transform change:[/i] Static bodies can be moved by animation or script. In this case, they are just teleported and don't affect other bodies on their path.
+ [i]Constant velocity:[/i] When [member constant_linear_velocity] or [member constant_angular_velocity] is set, static bodies don't move themselves but affect touching bodies as if they were moving. This is useful for simulating conveyor belts or conveyor wheels.
+ [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead.
</description>
<tutorials>
<link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link>
diff --git a/doc/classes/StyleBox.xml b/doc/classes/StyleBox.xml
index ff6d4d8821..4a63f4488c 100644
--- a/doc/classes/StyleBox.xml
+++ b/doc/classes/StyleBox.xml
@@ -17,21 +17,16 @@
<description>
</description>
</method>
- <method name="_get_center_size" qualifiers="virtual const">
- <return type="Vector2" />
- <description>
- </description>
- </method>
<method name="_get_draw_rect" qualifiers="virtual const">
<return type="Rect2" />
<param index="0" name="rect" type="Rect2" />
<description>
</description>
</method>
- <method name="_get_style_margin" qualifiers="virtual const">
- <return type="float" />
- <param index="0" name="side" type="int" enum="Side" />
+ <method name="_get_minimum_size" qualifiers="virtual const">
+ <return type="Vector2" />
<description>
+ Virtual method to be implemented by the user. Returns a custom minimum size that the stylebox must respect when drawing. By default [method get_minimum_size] only takes content margins into account. This method can be overridden to add another size restriction. A combination of the default behavior and the output of this method will be used, to account for both sizes.
</description>
</method>
<method name="_test_mask" qualifiers="virtual const">
@@ -50,10 +45,11 @@
The [RID] value can either be the result of [method CanvasItem.get_canvas_item] called on an existing [CanvasItem]-derived node, or directly from creating a canvas item in the [RenderingServer] with [method RenderingServer.canvas_item_create].
</description>
</method>
- <method name="get_center_size" qualifiers="const">
- <return type="Vector2" />
+ <method name="get_content_margin" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
- Returns the size of this [StyleBox] without the margins.
+ Returns the default margin of the specified [enum Side].
</description>
</method>
<method name="get_current_item_drawn" qualifiers="const">
@@ -62,13 +58,6 @@
Returns the [CanvasItem] that handles its [constant CanvasItem.NOTIFICATION_DRAW] or [method CanvasItem._draw] callback at this moment.
</description>
</method>
- <method name="get_default_margin" qualifiers="const">
- <return type="float" />
- <param index="0" name="margin" type="int" enum="Side" />
- <description>
- Returns the default margin of the specified [enum Side].
- </description>
- </method>
<method name="get_margin" qualifiers="const">
<return type="float" />
<param index="0" name="margin" type="int" enum="Side" />
@@ -89,7 +78,7 @@
Returns the "offset" of a stylebox. This helper function returns a value equivalent to [code]Vector2(style.get_margin(MARGIN_LEFT), style.get_margin(MARGIN_TOP))[/code].
</description>
</method>
- <method name="set_default_margin">
+ <method name="set_content_margin">
<return type="void" />
<param index="0" name="margin" type="int" enum="Side" />
<param index="1" name="offset" type="float" />
@@ -97,7 +86,7 @@
Sets the default value of the specified [enum Side] to [param offset] pixels.
</description>
</method>
- <method name="set_default_margin_all">
+ <method name="set_content_margin_all">
<return type="void" />
<param index="0" name="offset" type="float" />
<description>
@@ -114,21 +103,21 @@
</method>
</methods>
<members>
- <member name="content_margin_bottom" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0">
+ <member name="content_margin_bottom" type="float" setter="set_content_margin" getter="get_content_margin" default="-1.0">
The bottom margin for the contents of this style box. Increasing this value reduces the space available to the contents from the bottom.
If this value is negative, it is ignored and a child-specific margin is used instead. For example for [StyleBoxFlat] the border thickness (if any) is used instead.
It is up to the code using this style box to decide what these contents are: for example, a [Button] respects this content margin for the textual contents of the button.
[method get_margin] should be used to fetch this value as consumer instead of reading these properties directly. This is because it correctly respects negative values and the fallback mentioned above.
</member>
- <member name="content_margin_left" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0">
+ <member name="content_margin_left" type="float" setter="set_content_margin" getter="get_content_margin" default="-1.0">
The left margin for the contents of this style box. Increasing this value reduces the space available to the contents from the left.
Refer to [member content_margin_bottom] for extra considerations.
</member>
- <member name="content_margin_right" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0">
+ <member name="content_margin_right" type="float" setter="set_content_margin" getter="get_content_margin" default="-1.0">
The right margin for the contents of this style box. Increasing this value reduces the space available to the contents from the right.
Refer to [member content_margin_bottom] for extra considerations.
</member>
- <member name="content_margin_top" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0">
+ <member name="content_margin_top" type="float" setter="set_content_margin" getter="get_content_margin" default="-1.0">
The top margin for the contents of this style box. Increasing this value reduces the space available to the contents from the top.
Refer to [member content_margin_bottom] for extra considerations.
</member>
diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml
index aeba777b43..745187ed63 100644
--- a/doc/classes/StyleBoxTexture.xml
+++ b/doc/classes/StyleBoxTexture.xml
@@ -9,36 +9,36 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_expand_margin_size" qualifiers="const">
+ <method name="get_expand_margin" qualifiers="const">
<return type="float" />
<param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the expand margin size of the specified [enum Side].
</description>
</method>
- <method name="get_margin_size" qualifiers="const">
+ <method name="get_texture_margin" qualifiers="const">
<return type="float" />
<param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the margin size of the specified [enum Side].
</description>
</method>
- <method name="set_expand_margin_all">
+ <method name="set_expand_margin">
<return type="void" />
- <param index="0" name="size" type="float" />
+ <param index="0" name="margin" type="int" enum="Side" />
+ <param index="1" name="size" type="float" />
<description>
- Sets the expand margin to [param size] pixels for all margins.
+ Sets the expand margin to [param size] pixels for the specified [enum Side].
</description>
</method>
- <method name="set_expand_margin_size">
+ <method name="set_expand_margin_all">
<return type="void" />
- <param index="0" name="margin" type="int" enum="Side" />
- <param index="1" name="size" type="float" />
+ <param index="0" name="size" type="float" />
<description>
- Sets the expand margin to [param size] pixels for the specified [enum Side].
+ Sets the expand margin to [param size] pixels for all margins.
</description>
</method>
- <method name="set_margin_size">
+ <method name="set_texture_margin">
<return type="void" />
<param index="0" name="margin" type="int" enum="Side" />
<param index="1" name="size" type="float" />
@@ -46,7 +46,7 @@
Sets the margin to [param size] pixels for the specified [enum Side].
</description>
</method>
- <method name="set_margin_size_all">
+ <method name="set_texture_margin_all">
<return type="void" />
<param index="0" name="size" type="float" />
<description>
@@ -64,48 +64,48 @@
<member name="draw_center" type="bool" setter="set_draw_center" getter="is_draw_center_enabled" default="true">
If [code]true[/code], the nine-patch texture's center tile will be drawn.
</member>
- <member name="expand_margin_bottom" type="float" setter="set_expand_margin_size" getter="get_expand_margin_size" default="0.0">
+ <member name="expand_margin_bottom" type="float" setter="set_expand_margin" getter="get_expand_margin" default="0.0">
Expands the bottom margin of this style box when drawing, causing it to be drawn larger than requested.
</member>
- <member name="expand_margin_left" type="float" setter="set_expand_margin_size" getter="get_expand_margin_size" default="0.0">
+ <member name="expand_margin_left" type="float" setter="set_expand_margin" getter="get_expand_margin" default="0.0">
Expands the left margin of this style box when drawing, causing it to be drawn larger than requested.
</member>
- <member name="expand_margin_right" type="float" setter="set_expand_margin_size" getter="get_expand_margin_size" default="0.0">
+ <member name="expand_margin_right" type="float" setter="set_expand_margin" getter="get_expand_margin" default="0.0">
Expands the right margin of this style box when drawing, causing it to be drawn larger than requested.
</member>
- <member name="expand_margin_top" type="float" setter="set_expand_margin_size" getter="get_expand_margin_size" default="0.0">
+ <member name="expand_margin_top" type="float" setter="set_expand_margin" getter="get_expand_margin" default="0.0">
Expands the top margin of this style box when drawing, causing it to be drawn larger than requested.
</member>
- <member name="margin_bottom" type="float" setter="set_margin_size" getter="get_margin_size" default="0.0">
+ <member name="modulate_color" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)">
+ Modulates the color of the texture when this style box is drawn.
+ </member>
+ <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2(0, 0, 0, 0)">
+ Species a sub-region of the texture to use.
+ This is equivalent to first wrapping the texture in an [AtlasTexture] with the same region.
+ </member>
+ <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ The texture to use when drawing this style box.
+ </member>
+ <member name="texture_margin_bottom" type="float" setter="set_texture_margin" getter="get_texture_margin" default="0.0">
Increases the bottom margin of the 3×3 texture box.
A higher value means more of the source texture is considered to be part of the bottom border of the 3×3 box.
This is also the value used as fallback for [member StyleBox.content_margin_bottom] if it is negative.
</member>
- <member name="margin_left" type="float" setter="set_margin_size" getter="get_margin_size" default="0.0">
+ <member name="texture_margin_left" type="float" setter="set_texture_margin" getter="get_texture_margin" default="0.0">
Increases the left margin of the 3×3 texture box.
A higher value means more of the source texture is considered to be part of the left border of the 3×3 box.
This is also the value used as fallback for [member StyleBox.content_margin_left] if it is negative.
</member>
- <member name="margin_right" type="float" setter="set_margin_size" getter="get_margin_size" default="0.0">
+ <member name="texture_margin_right" type="float" setter="set_texture_margin" getter="get_texture_margin" default="0.0">
Increases the right margin of the 3×3 texture box.
A higher value means more of the source texture is considered to be part of the right border of the 3×3 box.
This is also the value used as fallback for [member StyleBox.content_margin_right] if it is negative.
</member>
- <member name="margin_top" type="float" setter="set_margin_size" getter="get_margin_size" default="0.0">
+ <member name="texture_margin_top" type="float" setter="set_texture_margin" getter="get_texture_margin" default="0.0">
Increases the top margin of the 3×3 texture box.
A higher value means more of the source texture is considered to be part of the top border of the 3×3 box.
This is also the value used as fallback for [member StyleBox.content_margin_top] if it is negative.
</member>
- <member name="modulate_color" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)">
- Modulates the color of the texture when this style box is drawn.
- </member>
- <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2(0, 0, 0, 0)">
- Species a sub-region of the texture to use.
- This is equivalent to first wrapping the texture in an [AtlasTexture] with the same region.
- </member>
- <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
- The texture to use when drawing this style box.
- </member>
</members>
<constants>
<constant name="AXIS_STRETCH_MODE_STRETCH" value="0" enum="AxisStretchMode">
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 1efd0f9326..ccd79cd170 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -696,7 +696,7 @@
<method name="merge_overlapping_carets">
<return type="void" />
<description>
- Merges any overlapping carets. Will favour the newest caret, or the caret with a selection.
+ Merges any overlapping carets. Will favor the newest caret, or the caret with a selection.
[b]Note:[/b] This is not called when a caret changes position but after certain actions, so it is possible to get into a state where carets overlap.
</description>
</method>
diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml
index 7fc6ba8161..a812b52307 100644
--- a/doc/classes/TileSet.xml
+++ b/doc/classes/TileSet.xml
@@ -589,7 +589,7 @@
<param index="0" name="terrain_set" type="int" />
<param index="1" name="mode" type="int" enum="TileSet.TerrainMode" />
<description>
- Sets a terrain mode. Each mode determines which bits of a tile shape is used to match the neighbouring tiles' terrains.
+ Sets a terrain mode. Each mode determines which bits of a tile shape is used to match the neighboring tiles' terrains.
</description>
</method>
</methods>
diff --git a/doc/classes/VehicleBody3D.xml b/doc/classes/VehicleBody3D.xml
index e1689133de..9f905c0ec5 100644
--- a/doc/classes/VehicleBody3D.xml
+++ b/doc/classes/VehicleBody3D.xml
@@ -7,6 +7,7 @@
This node implements all the physics logic needed to simulate a car. It is based on the raycast vehicle system commonly found in physics engines. You will need to add a [CollisionShape3D] for the main body of your vehicle and add [VehicleWheel3D] nodes for the wheels. You should also add a [MeshInstance3D] to this node for the 3D model of your car but this model should not include meshes for the wheels. You should control the vehicle by using the [member brake], [member engine_force], and [member steering] properties and not change the position or orientation of this node directly.
[b]Note:[/b] The origin point of your VehicleBody3D will determine the center of gravity of your vehicle so it is better to keep this low and move the [CollisionShape3D] and [MeshInstance3D] upwards.
[b]Note:[/b] This class has known issues and isn't designed to provide realistic 3D vehicle physics. If you want advanced vehicle physics, you will probably have to write your own physics integration using another [PhysicsBody3D] class.
+ [b]Warning:[/b] With a non-uniform scale this node will probably not function as expected. Please make sure to keep its scale uniform (i.e. the same on all axes), and change the size(s) of its collision shape(s) instead.
</description>
<tutorials>
<link title="3D Truck Town Demo">https://godotengine.org/asset-library/asset/524</link>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index da31e6761e..c4ea11ab66 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -771,8 +771,16 @@
Right-to-left layout direction.
</constant>
<constant name="WINDOW_INITIAL_POSITION_ABSOLUTE" value="0" enum="WindowInitialPosition">
+ Initial window position is determined by [member position].
</constant>
- <constant name="WINDOW_INITIAL_POSITION_CENTER_SCREEN" value="1" enum="WindowInitialPosition">
+ <constant name="WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN" value="1" enum="WindowInitialPosition">
+ Initial window position is a center of the primary screen.
+ </constant>
+ <constant name="WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN" value="2" enum="WindowInitialPosition">
+ Initial window position is a center of the main window screen.
+ </constant>
+ <constant name="WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN" value="3" enum="WindowInitialPosition">
+ Initial window position is a center of [member current_screen] screen.
</constant>
</constants>
<theme_items>
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index 966a09c6c2..219529d2f6 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -632,7 +632,7 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
ERR_FAIL_COND(result != noErr);
if (capture) {
- // Reset audio input to keep synchronisation.
+ // Reset audio input to keep synchronization.
input_position = 0;
input_size = 0;
}
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 12def52d50..67526bc003 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -1596,9 +1596,13 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
+#ifndef IOS_ENABLED
if (use_multiview) {
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count);
} else {
+#else
+ {
+#endif
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
}
@@ -1623,9 +1627,13 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
+#ifndef IOS_ENABLED
if (use_multiview) {
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, rt->depth, 0, 0, rt->view_count);
} else {
+#else
+ {
+#endif
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
}
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 1c1255ce98..e14c3c7f7a 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -264,7 +264,7 @@ Error AudioDriverPulseAudio::init_device() {
samples_in.resize(buffer_frames * channels);
samples_out.resize(pa_buffer_size);
- // Reset audio input to keep synchronisation.
+ // Reset audio input to keep synchronization.
input_position = 0;
input_size = 0;
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 27f96f35af..b5b00fd71e 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -2252,7 +2252,7 @@ Error VulkanContext::swap_buffers() {
// simple that it doesn't do either of those.
}
#endif
- // Wait for the image acquired semaphore to be signalled to ensure
+ // Wait for the image acquired semaphore to be signaled to ensure
// that the image won't be rendered to until the presentation
// engine has fully released ownership to the application, and it is
// okay to render to the image.
@@ -2304,7 +2304,7 @@ Error VulkanContext::swap_buffers() {
if (separate_present_queue) {
// If we are using separate queues, change image ownership to the
// present queue before presenting, waiting for the draw complete
- // semaphore and signalling the ownership released semaphore when finished.
+ // semaphore and signaling the ownership released semaphore when finished.
VkFence nullFence = VK_NULL_HANDLE;
pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit_info.waitSemaphoreCount = 1;
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index cb8d98932d..ae54c20fe2 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -449,10 +449,14 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info
// First Column - Icon
Ref<InputEventKey> k = event;
if (k.is_valid()) {
- if (k->get_physical_keycode() == Key::NONE) {
+ if (k->get_physical_keycode() == Key::NONE && k->get_keycode() == Key::NONE && k->get_key_label() != Key::NONE) {
+ event_item->set_icon(0, action_tree->get_theme_icon(SNAME("KeyboardLabel"), SNAME("EditorIcons")));
+ } else if (k->get_keycode() != Key::NONE) {
event_item->set_icon(0, action_tree->get_theme_icon(SNAME("Keyboard"), SNAME("EditorIcons")));
- } else {
+ } else if (k->get_physical_keycode() != Key::NONE) {
event_item->set_icon(0, action_tree->get_theme_icon(SNAME("KeyboardPhysical"), SNAME("EditorIcons")));
+ } else {
+ event_item->set_icon(0, action_tree->get_theme_icon(SNAME("KeyboardError"), SNAME("EditorIcons")));
}
}
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 6f4736dca7..9ff480f130 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -285,7 +285,7 @@ void ConnectDialog::_notification(int p_what) {
Ref<StyleBox> style = get_theme_stylebox("normal", "LineEdit")->duplicate();
if (style.is_valid()) {
- style->set_default_margin(SIDE_TOP, style->get_default_margin(SIDE_TOP) + 1.0);
+ style->set_content_margin(SIDE_TOP, style->get_content_margin(SIDE_TOP) + 1.0);
from_signal->add_theme_style_override("normal", style);
}
} break;
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 6a89b3572c..d00501280d 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -201,7 +201,6 @@ public:
String get_scene_type(int p_idx) const;
void set_scene_path(int p_idx, const String &p_path);
Ref<Script> get_scene_root_script(int p_idx) const;
- void set_edited_scene_version(uint64_t version, int p_scene_idx = -1);
void set_scene_modified_time(int p_idx, uint64_t p_time);
uint64_t get_scene_modified_time(int p_idx) const;
void clear_edited_scenes();
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index a83a53ad15..33a1fe4b45 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -980,7 +980,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
no_profile_selected_help = memnew(Label(TTR("Create or import a profile to edit available classes and properties.")));
// Add some spacing above the help label.
Ref<StyleBoxEmpty> sb = memnew(StyleBoxEmpty);
- sb->set_default_margin(SIDE_TOP, 20 * EDSCALE);
+ sb->set_content_margin(SIDE_TOP, 20 * EDSCALE);
no_profile_selected_help->add_theme_style_override("normal", sb);
no_profile_selected_help->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
no_profile_selected_help->set_v_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 16ecac4dac..ef33b82390 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1552,6 +1552,11 @@ void EditorFileSystem::_update_script_classes() {
int index = -1;
EditorFileSystemDirectory *efd = find_file(path, &index);
+ if (!efd || index < 0) {
+ // The file was removed
+ continue;
+ }
+
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptLanguage *lang = ScriptServer::get_language(i);
if (lang->supports_documentation() && efd->files[index]->type == lang->get_type()) {
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 9b1a5e028b..4cf947b006 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -195,8 +195,8 @@ void EditorHelp::_class_desc_resized(bool p_force_update_theme) {
display_margin = new_display_margin;
Ref<StyleBox> class_desc_stylebox = EditorNode::get_singleton()->get_theme_base()->get_theme_stylebox(SNAME("background"), SNAME("EditorHelp"))->duplicate();
- class_desc_stylebox->set_default_margin(SIDE_LEFT, display_margin);
- class_desc_stylebox->set_default_margin(SIDE_RIGHT, display_margin);
+ class_desc_stylebox->set_content_margin(SIDE_LEFT, display_margin);
+ class_desc_stylebox->set_content_margin(SIDE_RIGHT, display_margin);
class_desc->add_theme_style_override("normal", class_desc_stylebox);
class_desc->add_theme_style_override("focused", class_desc_stylebox);
}
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 28e89ff0d8..4753761f05 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -3282,6 +3282,11 @@ void EditorInspector::update_tree() {
ped->parse_end(object);
_parse_added_editors(main_vbox, nullptr, ped);
}
+
+ if (_is_main_editor_inspector()) {
+ // Updating inspector might invalidate some editing owners.
+ EditorNode::get_singleton()->hide_unused_editors();
+ }
}
void EditorInspector::update_property(const String &p_prop) {
@@ -3306,6 +3311,9 @@ void EditorInspector::_clear() {
sections.clear();
pending.clear();
restart_request_props.clear();
+ if (_is_main_editor_inspector()) {
+ EditorNode::get_singleton()->hide_unused_editors(this);
+ }
}
Object *EditorInspector::get_edited_object() {
@@ -3640,6 +3648,10 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
}
}
+bool EditorInspector::_is_main_editor_inspector() const {
+ return InspectorDock::get_singleton() && InspectorDock::get_inspector_singleton() == this;
+}
+
void EditorInspector::_property_changed(const String &p_path, const Variant &p_value, const String &p_name, bool p_changing, bool p_update_all) {
// The "changing" variable must be true for properties that trigger events as typing occurs,
// like "text_changed" signal. E.g. text property of Label, Button, RichTextLabel, etc.
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 699a88e657..1690302e6e 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -502,6 +502,7 @@ class EditorInspector : public ScrollContainer {
bool restrict_to_basic = false;
void _edit_set(const String &p_name, const Variant &p_value, bool p_refresh_all, const String &p_changed_field);
+ bool _is_main_editor_inspector() const;
void _property_changed(const String &p_path, const Variant &p_value, const String &p_name = "", bool p_changing = false, bool p_update_all = false);
void _multiple_properties_changed(Vector<String> p_paths, Array p_values, bool p_changing = false);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index bbd927dcd9..c344812065 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -58,6 +58,7 @@
#include "scene/gui/tab_bar.h"
#include "scene/gui/tab_container.h"
#include "scene/main/window.h"
+#include "scene/property_utils.h"
#include "scene/resources/packed_scene.h"
#include "servers/display_server.h"
#include "servers/navigation_server_3d.h"
@@ -997,6 +998,7 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) {
for (const String &E : scenes) {
reload_scene(E);
+ reload_instances_with_path_in_edited_scenes(E);
}
scene_tabs->set_current_tab(current_tab);
@@ -2078,51 +2080,56 @@ bool EditorNode::_is_class_editor_disabled_by_feature_profile(const StringName &
return false;
}
-void EditorNode::edit_item(Object *p_object) {
+void EditorNode::edit_item(Object *p_object, Object *p_editing_owner) {
+ ERR_FAIL_NULL(p_editing_owner);
+
if (p_object && _is_class_editor_disabled_by_feature_profile(p_object->get_class())) {
return;
}
- Vector<EditorPlugin *> top_plugins = editor_plugins_over->get_plugins_list();
Vector<EditorPlugin *> item_plugins;
if (p_object) {
item_plugins = editor_data.get_subeditors(p_object);
}
if (!item_plugins.is_empty()) {
- bool same = true;
- if (item_plugins.size() == top_plugins.size()) {
- for (int i = 0; i < item_plugins.size(); i++) {
- if (item_plugins[i] != top_plugins[i]) {
- same = false;
- }
+ ObjectID owner_id = p_editing_owner->get_instance_id();
+
+ for (EditorPlugin *plugin : active_plugins[owner_id]) {
+ if (!item_plugins.has(plugin)) {
+ plugin->make_visible(false);
+ plugin->edit(nullptr);
}
- } else {
- same = false;
}
- if (!same) {
- _display_top_editors(false);
- _set_top_editors(item_plugins);
+ for (EditorPlugin *plugin : item_plugins) {
+ for (KeyValue<ObjectID, HashSet<EditorPlugin *>> &kv : active_plugins) {
+ if (kv.key != owner_id) {
+ EditorPropertyResource *epres = Object::cast_to<EditorPropertyResource>(ObjectDB::get_instance(kv.key));
+ if (epres && kv.value.has(plugin)) {
+ // If it's resource property editing the same resource type, fold it.
+ epres->fold_resource();
+ }
+ kv.value.erase(plugin);
+ }
+ }
+ active_plugins[owner_id].insert(plugin);
+ editor_plugins_over->add_plugin(plugin);
+ plugin->edit(p_object);
+ plugin->make_visible(true);
}
- _set_editing_top_editors(p_object);
- _display_top_editors(true);
- } else if (!top_plugins.is_empty()) {
- hide_top_editors();
+ } else {
+ hide_unused_editors(p_editing_owner);
}
}
-void EditorNode::edit_item_resource(Ref<Resource> p_resource) {
- edit_item(p_resource.ptr());
-}
-
void EditorNode::push_item(Object *p_object, const String &p_property, bool p_inspector_only) {
if (!p_object) {
InspectorDock::get_inspector_singleton()->edit(nullptr);
NodeDock::get_singleton()->set_node(nullptr);
SceneTreeDock::get_singleton()->set_selected(nullptr);
InspectorDock::get_singleton()->update(nullptr);
- _display_top_editors(false);
+ hide_unused_editors();
return;
}
@@ -2150,22 +2157,34 @@ void EditorNode::_save_default_environment() {
}
}
-void EditorNode::hide_top_editors() {
- _display_top_editors(false);
-
- editor_plugins_over->clear();
-}
-
-void EditorNode::_display_top_editors(bool p_display) {
- editor_plugins_over->make_visible(p_display);
-}
-
-void EditorNode::_set_top_editors(Vector<EditorPlugin *> p_editor_plugins_over) {
- editor_plugins_over->set_plugins_list(p_editor_plugins_over);
-}
+void EditorNode::hide_unused_editors(const Object *p_editing_owner) {
+ if (p_editing_owner) {
+ const ObjectID id = p_editing_owner->get_instance_id();
+ for (EditorPlugin *plugin : active_plugins[id]) {
+ plugin->make_visible(false);
+ plugin->edit(nullptr);
+ editor_plugins_over->remove_plugin(plugin);
+ }
+ active_plugins.erase(id);
+ } else {
+ // If no editing owner is provided, this method will go over all owners and check if they are valid.
+ // This is to sweep properties that were removed from the inspector.
+ List<ObjectID> to_remove;
+ for (KeyValue<ObjectID, HashSet<EditorPlugin *>> &kv : active_plugins) {
+ if (!ObjectDB::get_instance(kv.key)) {
+ to_remove.push_back(kv.key);
+ for (EditorPlugin *plugin : kv.value) {
+ plugin->make_visible(false);
+ plugin->edit(nullptr);
+ editor_plugins_over->remove_plugin(plugin);
+ }
+ }
+ }
-void EditorNode::_set_editing_top_editors(Object *p_current_object) {
- editor_plugins_over->edit(p_current_object);
+ for (const ObjectID &id : to_remove) {
+ active_plugins.erase(id);
+ }
+ }
}
static bool overrides_external_editor(Object *p_object) {
@@ -2199,7 +2218,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
NodeDock::get_singleton()->set_node(nullptr);
InspectorDock::get_singleton()->update(nullptr);
- _display_top_editors(false);
+ hide_unused_editors();
return;
}
@@ -2327,6 +2346,9 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
InspectorDock::get_inspector_singleton()->set_use_folding(!disable_folding);
}
+ Object *editor_owner = is_node ? (Object *)SceneTreeDock::get_singleton() : is_resource ? (Object *)InspectorDock::get_inspector_singleton()
+ : (Object *)this;
+
// Take care of the main editor plugin.
if (!inspector_only) {
@@ -2343,6 +2365,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
}
}
+ ObjectID editor_owner_id = editor_owner->get_instance_id();
if (main_plugin && !skip_main_plugin) {
// Special case if use of external editor is true.
Resource *current_res = Object::cast_to<Resource>(current_obj);
@@ -2353,15 +2376,22 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
}
else if (main_plugin != editor_plugin_screen && (!ScriptEditor::get_singleton() || !ScriptEditor::get_singleton()->is_visible_in_tree() || ScriptEditor::get_singleton()->can_take_away_focus())) {
+ // Unedit previous plugin.
+ editor_plugin_screen->edit(nullptr);
+ active_plugins[editor_owner_id].erase(editor_plugin_screen);
// Update screen main_plugin.
editor_select(plugin_index);
main_plugin->edit(current_obj);
} else {
editor_plugin_screen->edit(current_obj);
}
+ is_main_screen_editing = true;
+ } else if (!main_plugin && editor_plugin_screen && is_main_screen_editing) {
+ editor_plugin_screen->edit(nullptr);
+ is_main_screen_editing = false;
}
- edit_item(current_obj);
+ edit_item(current_obj, editor_owner);
}
InspectorDock::get_singleton()->update(current_obj);
@@ -3626,12 +3656,12 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
if (get_edited_scene()) {
if (current_tab < 2) {
- // Use heuristic instead.
- int n2d = 0, n3d = 0;
- _find_node_types(get_edited_scene(), n2d, n3d);
- if (n2d > n3d) {
+ Node *editor_node = SceneTreeDock::get_singleton()->get_tree_editor()->get_selected();
+ editor_node = editor_node == nullptr ? get_edited_scene() : editor_node;
+
+ if (Object::cast_to<Node2D>(editor_node) || Object::cast_to<Control>(editor_node)) {
editor_select(EDITOR_2D);
- } else if (n3d > n2d) {
+ } else if (Object::cast_to<Node3D>(editor_node)) {
editor_select(EDITOR_3D);
}
}
@@ -3871,7 +3901,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
Ref<SceneState> state = sdata->get_state();
state->set_path(lpath);
new_scene->set_scene_inherited_state(state);
- new_scene->set_scene_file_path(String());
+ new_scene->set_scene_file_path(lpath);
}
new_scene->set_scene_instance_state(Ref<SceneState>());
@@ -3905,6 +3935,134 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
return OK;
}
+HashMap<StringName, Variant> EditorNode::get_modified_properties_for_node(Node *p_node) {
+ HashMap<StringName, Variant> modified_property_map;
+
+ List<PropertyInfo> pinfo;
+ p_node->get_property_list(&pinfo);
+ for (const PropertyInfo &E : pinfo) {
+ if (E.usage & PROPERTY_USAGE_STORAGE) {
+ bool is_valid_revert = false;
+ Variant revert_value = EditorPropertyRevert::get_property_revert_value(p_node, E.name, &is_valid_revert);
+ Variant current_value = p_node->get(E.name);
+ if (is_valid_revert) {
+ if (PropertyUtils::is_property_value_different(current_value, revert_value)) {
+ modified_property_map[E.name] = current_value;
+ }
+ }
+ }
+ }
+
+ return modified_property_map;
+}
+
+void EditorNode::update_diff_data_for_node(
+ Node *p_edited_scene,
+ Node *p_root,
+ Node *p_node,
+ HashMap<NodePath, ModificationNodeEntry> &p_modification_table,
+ List<AdditiveNodeEntry> &p_addition_list) {
+ bool node_part_of_subscene = p_node != p_edited_scene &&
+ p_edited_scene->get_scene_inherited_state().is_valid() &&
+ p_edited_scene->get_scene_inherited_state()->find_node_by_path(p_edited_scene->get_path_to(p_node)) >= 0;
+
+ // Loop through the owners until either we reach the root node or nullptr
+ Node *valid_node_owner = p_node->get_owner();
+ while (valid_node_owner) {
+ if (valid_node_owner == p_root) {
+ break;
+ }
+ valid_node_owner = valid_node_owner->get_owner();
+ }
+
+ if ((valid_node_owner == p_root && (p_root != p_edited_scene || !p_edited_scene->get_scene_file_path().is_empty())) || node_part_of_subscene || p_node == p_root) {
+ HashMap<StringName, Variant> modified_properties = get_modified_properties_for_node(p_node);
+
+ // Find all valid connections to other nodes.
+ List<Connection> connections_to;
+ p_node->get_all_signal_connections(&connections_to);
+
+ List<ConnectionWithNodePath> valid_connections_to;
+ for (const Connection &c : connections_to) {
+ Node *connection_target_node = Object::cast_to<Node>(c.callable.get_object());
+ if (connection_target_node) {
+ // TODO: add support for reinstating custom callables
+ if (!c.callable.is_custom()) {
+ ConnectionWithNodePath connection_to;
+ connection_to.connection = c;
+ connection_to.node_path = p_node->get_path_to(connection_target_node);
+ valid_connections_to.push_back(connection_to);
+ }
+ }
+ }
+
+ // Find all valid connections from other nodes.
+ List<Connection> connections_from;
+ p_node->get_signals_connected_to_this(&connections_from);
+
+ List<Connection> valid_connections_from;
+ for (const Connection &c : connections_from) {
+ Node *source_node = Object::cast_to<Node>(c.signal.get_object());
+
+ Node *valid_source_owner = nullptr;
+ if (source_node) {
+ valid_source_owner = source_node->get_owner();
+ while (valid_source_owner) {
+ if (valid_source_owner == p_root) {
+ break;
+ }
+ valid_source_owner = valid_source_owner->get_owner();
+ }
+ }
+
+ if (!source_node || valid_source_owner == nullptr) {
+ // TODO: add support for reinstating custom callables
+ if (!c.callable.is_custom()) {
+ valid_connections_from.push_back(c);
+ }
+ }
+ }
+
+ // Find all node groups.
+ List<Node::GroupInfo> groups;
+ p_node->get_groups(&groups);
+
+ if (!modified_properties.is_empty() || !valid_connections_to.is_empty() || !valid_connections_from.is_empty() || !groups.is_empty()) {
+ ModificationNodeEntry modification_node_entry;
+ modification_node_entry.property_table = modified_properties;
+ modification_node_entry.connections_to = valid_connections_to;
+ modification_node_entry.connections_from = valid_connections_from;
+ modification_node_entry.groups = groups;
+
+ p_modification_table[p_root->get_path_to(p_node)] = modification_node_entry;
+ }
+ } else {
+ AdditiveNodeEntry new_additive_node_entry;
+ new_additive_node_entry.node = p_node;
+ new_additive_node_entry.parent = p_root->get_path_to(p_node->get_parent());
+ new_additive_node_entry.owner = p_node->get_owner();
+ new_additive_node_entry.index = p_node->get_index();
+
+ Node2D *node_2d = Object::cast_to<Node2D>(p_node);
+ if (node_2d) {
+ new_additive_node_entry.transform_2d = node_2d->get_relative_transform_to_parent(node_2d->get_parent());
+ }
+ Node3D *node_3d = Object::cast_to<Node3D>(p_node);
+ if (node_3d) {
+ new_additive_node_entry.transform_3d = node_3d->get_relative_transform(node_3d->get_parent());
+ }
+ p_addition_list.push_back(new_additive_node_entry);
+
+ return;
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ update_diff_data_for_node(p_edited_scene, p_root, child, p_modification_table, p_addition_list);
+ }
+}
+//
+
void EditorNode::open_request(const String &p_path) {
if (!opening_prev) {
List<String>::Element *prev_scene_item = previous_scenes.find(p_path);
@@ -5761,6 +5919,352 @@ void EditorNode::reload_scene(const String &p_path) {
scene_tabs->set_current_tab(current_tab);
}
+void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, List<Node *> &p_instance_list) {
+ String scene_file_path = p_node->get_scene_file_path();
+
+ // This is going to get messy...
+ if (p_node->get_scene_file_path() == p_instance_path) {
+ p_instance_list.push_back(p_node);
+ } else {
+ Node *current_node = p_node;
+
+ Ref<SceneState> inherited_state = current_node->get_scene_inherited_state();
+ while (inherited_state.is_valid()) {
+ String inherited_path = inherited_state->get_path();
+ if (inherited_path == p_instance_path) {
+ p_instance_list.push_back(p_node);
+ break;
+ }
+
+ inherited_state = inherited_state->get_base_scene_state();
+ }
+ }
+
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ Node *child = p_node->get_child(i);
+ find_all_instances_inheriting_path_in_node(p_root, child, p_instance_path, p_instance_list);
+ }
+}
+
+void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_instance_path) {
+ int original_edited_scene_idx = editor_data.get_edited_scene();
+ HashMap<int, List<Node *>> edited_scene_map;
+
+ // Walk through each opened scene to get a global list of all instances which match
+ // the current reimported scenes.
+ for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+ if (editor_data.get_scene_path(i) != p_instance_path) {
+ Node *edited_scene_root = editor_data.get_edited_scene_root(i);
+
+ if (edited_scene_root) {
+ List<Node *> valid_nodes;
+ find_all_instances_inheriting_path_in_node(edited_scene_root, edited_scene_root, p_instance_path, valid_nodes);
+ if (valid_nodes.size() > 0) {
+ edited_scene_map[i] = valid_nodes;
+ }
+ }
+ }
+ }
+
+ if (edited_scene_map.size() > 0) {
+ // Reload the new instance.
+ Error err;
+ Ref<PackedScene> instance_scene_packed_scene = ResourceLoader::load(p_instance_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE, &err);
+ instance_scene_packed_scene->set_path(p_instance_path, true);
+
+ ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND(instance_scene_packed_scene.is_null());
+
+ HashMap<String, Ref<PackedScene>> local_scene_cache;
+ local_scene_cache[p_instance_path] = instance_scene_packed_scene;
+
+ for (const KeyValue<int, List<Node *>> &edited_scene_map_elem : edited_scene_map) {
+ // Set the current scene.
+ int current_scene_idx = edited_scene_map_elem.key;
+ editor_data.set_edited_scene(current_scene_idx);
+ Node *current_edited_scene = editor_data.get_edited_scene_root(current_scene_idx);
+
+ // Clear the history for this tab (should we allow history to be retained?).
+ EditorUndoRedoManager::get_singleton()->clear_history();
+
+ // Update the version
+ editor_data.is_scene_changed(current_scene_idx);
+
+ for (Node *original_node : edited_scene_map_elem.value) {
+ // Walk the tree for the current node and extract relevant diff data, storing it in the modification table.
+ // For additional nodes which are part of the current scene, they get added to the addition table.
+ HashMap<NodePath, ModificationNodeEntry> modification_table;
+ List<AdditiveNodeEntry> addition_list;
+ update_diff_data_for_node(current_edited_scene, original_node, original_node, modification_table, addition_list);
+
+ // Disconnect all relevant connections, all connections from and persistent connections to.
+ for (const KeyValue<NodePath, ModificationNodeEntry> &modification_table_entry : modification_table) {
+ for (Connection conn : modification_table_entry.value.connections_from) {
+ conn.signal.get_object()->disconnect(conn.signal.get_name(), conn.callable);
+ }
+ for (ConnectionWithNodePath cwnp : modification_table_entry.value.connections_to) {
+ Connection conn = cwnp.connection;
+ if (conn.flags & CONNECT_PERSIST) {
+ conn.signal.get_object()->disconnect(conn.signal.get_name(), conn.callable);
+ }
+ }
+ }
+
+ // Store all the paths for any selected nodes which are ancestors of the node we're replacing.
+ List<NodePath> selected_node_paths;
+ for (Node *selected_node : editor_selection->get_selected_node_list()) {
+ if (selected_node == original_node || original_node->is_ancestor_of(selected_node)) {
+ selected_node_paths.push_back(original_node->get_path_to(selected_node));
+ editor_selection->remove_node(selected_node);
+ }
+ }
+
+ // Remove all nodes which were added as additional elements (they will be restored later).
+ for (AdditiveNodeEntry additive_node_entry : addition_list) {
+ Node *addition_node = additive_node_entry.node;
+ addition_node->get_parent()->remove_child(addition_node);
+ }
+
+ // Clear ownership of the nodes (kind of hack to workaround an issue with
+ // replace_by when called on nodes in other tabs).
+ List<Node *> nodes_owned_by_original_node;
+ original_node->get_owned_by(original_node, &nodes_owned_by_original_node);
+ for (Node *owned_node : nodes_owned_by_original_node) {
+ owned_node->set_owner(nullptr);
+ }
+
+ // Delete all the remaining node children.
+ while (original_node->get_child_count()) {
+ Node *child = original_node->get_child(0);
+
+ original_node->remove_child(child);
+ child->queue_free();
+ }
+
+ // Reset the editable instance state.
+ bool is_editable = true;
+ Node *owner = original_node->get_owner();
+ if (owner) {
+ is_editable = owner->is_editable_instance(original_node);
+ }
+
+ // Load a replacement scene for the node.
+ Ref<PackedScene> current_packed_scene;
+ if (original_node->get_scene_file_path() == p_instance_path) {
+ // If the node file name directly matches the scene we're replacing,
+ // just load it since we already cached it.
+ current_packed_scene = instance_scene_packed_scene;
+ } else {
+ // Otherwise, check the inheritance chain, reloading and caching any scenes
+ // we require along the way.
+ List<String> required_load_paths;
+ String scene_path = original_node->get_scene_file_path();
+ // Do we need to check if the paths are empty?
+ if (!scene_path.is_empty()) {
+ required_load_paths.push_front(scene_path);
+ }
+ Ref<SceneState> inherited_state = original_node->get_scene_inherited_state();
+ while (inherited_state.is_valid()) {
+ String inherited_path = inherited_state->get_path();
+ // Do we need to check if the paths are empty?
+ if (!inherited_path.is_empty()) {
+ required_load_paths.push_front(inherited_path);
+ }
+ inherited_state = inherited_state->get_base_scene_state();
+ }
+
+ // Ensure the inheritance chain is loaded in the correct order so that cache can
+ // be properly updated.
+ for (String path : required_load_paths) {
+ if (!local_scene_cache.find(path)) {
+ current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_IGNORE, &err);
+ current_packed_scene->set_path(path, true);
+ local_scene_cache[path] = current_packed_scene;
+ } else {
+ current_packed_scene = local_scene_cache[path];
+ }
+ }
+ }
+
+ ERR_FAIL_COND(current_packed_scene.is_null());
+
+ // Instantiate the node.
+ Node *instantiated_node = nullptr;
+ if (current_packed_scene.is_valid()) {
+ instantiated_node = current_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ }
+
+ ERR_FAIL_COND(!instantiated_node);
+
+ bool original_node_is_displayed_folded = original_node->is_displayed_folded();
+ bool original_node_scene_instance_load_placeholder = original_node->get_scene_instance_load_placeholder();
+
+ // Update the name to match
+ instantiated_node->set_name(original_node->get_name());
+
+ // Is this replacing the edited root node?
+ String original_node_file_path = original_node->get_scene_file_path();
+
+ if (current_edited_scene == original_node) {
+ instantiated_node->set_scene_instance_state(original_node->get_scene_instance_state());
+ // Fix unsaved inherited scene
+ if (original_node_file_path.is_empty()) {
+ Ref<SceneState> state = current_packed_scene->get_state();
+ state->set_path(current_packed_scene->get_path());
+ instantiated_node->set_scene_inherited_state(state);
+ }
+ editor_data.set_edited_scene_root(instantiated_node);
+ current_edited_scene = instantiated_node;
+
+ if (original_node->is_inside_tree()) {
+ SceneTreeDock::get_singleton()->set_edited_scene(current_edited_scene);
+ original_node->get_tree()->set_edited_scene_root(instantiated_node);
+ }
+ }
+
+ // Replace the original node with the instantiated version.
+ original_node->replace_by(instantiated_node, false);
+
+ // Mark the old node for deletion.
+ original_node->queue_free();
+
+ // Restore the folded and placeholder state from the original node.
+ instantiated_node->set_display_folded(original_node_is_displayed_folded);
+ instantiated_node->set_scene_instance_load_placeholder(original_node_scene_instance_load_placeholder);
+
+ if (owner) {
+ Ref<SceneState> ss_inst = owner->get_scene_instance_state();
+ if (ss_inst.is_valid()) {
+ ss_inst->update_instance_resource(p_instance_path, current_packed_scene);
+ }
+
+ owner->set_editable_instance(instantiated_node, is_editable);
+ }
+
+ // Attempt to re-add all the additional nodes.
+ for (AdditiveNodeEntry additive_node_entry : addition_list) {
+ Node *parent_node = instantiated_node->get_node_or_null(additive_node_entry.parent);
+
+ if (!parent_node) {
+ parent_node = current_edited_scene;
+ }
+
+ parent_node->add_child(additive_node_entry.node);
+ parent_node->move_child(additive_node_entry.node, additive_node_entry.index);
+ // If the additive node's owner was the node which got replaced, update it.
+ if (additive_node_entry.owner == original_node) {
+ additive_node_entry.owner = instantiated_node;
+ }
+
+ additive_node_entry.node->set_owner(additive_node_entry.owner);
+
+ // If the parent node was lost, attempt to restore the original global transform.
+ {
+ Node2D *node_2d = Object::cast_to<Node2D>(additive_node_entry.node);
+ if (node_2d) {
+ node_2d->set_transform(additive_node_entry.transform_2d);
+ }
+
+ Node3D *node_3d = Object::cast_to<Node3D>(additive_node_entry.node);
+ if (node_3d) {
+ node_3d->set_transform(additive_node_entry.transform_3d);
+ }
+ }
+ }
+
+ // Restore the selection.
+ if (selected_node_paths.size()) {
+ for (NodePath selected_node_path : selected_node_paths) {
+ Node *selected_node = instantiated_node->get_node_or_null(selected_node_path);
+ if (selected_node) {
+ editor_selection->add_node(selected_node);
+ }
+ }
+ editor_selection->update();
+ }
+
+ // Attempt to restore the modified properties and signals for the instantitated node and all its owned children.
+ for (KeyValue<NodePath, ModificationNodeEntry> &E : modification_table) {
+ NodePath new_current_path = E.key;
+ Node *modifiable_node = instantiated_node->get_node_or_null(new_current_path);
+
+ if (modifiable_node) {
+ // Get properties for this node.
+ List<PropertyInfo> pinfo;
+ modifiable_node->get_property_list(&pinfo);
+
+ // Get names of all valid property names (TODO: make this more efficent).
+ List<String> property_names;
+ for (const PropertyInfo &E2 : pinfo) {
+ if (E2.usage & PROPERTY_USAGE_STORAGE) {
+ property_names.push_back(E2.name);
+ }
+ }
+
+ // Restore the modified properties for this node.
+ for (const KeyValue<StringName, Variant> &E2 : E.value.property_table) {
+ if (property_names.find(E2.key)) {
+ modifiable_node->set(E2.key, E2.value);
+ }
+ }
+ // Restore the connections to other nodes.
+ for (const ConnectionWithNodePath &E2 : E.value.connections_to) {
+ Connection conn = E2.connection;
+
+ // Get the node the callable is targetting.
+ Node *target_node = cast_to<Node>(conn.callable.get_object());
+
+ // If the callable object no longer exists or is marked for deletion,
+ // attempt to reaccquire the closest match by using the node path
+ // we saved earlier.
+ if (!target_node || !target_node->is_queued_for_deletion()) {
+ target_node = modifiable_node->get_node_or_null(E2.node_path);
+ }
+
+ if (target_node) {
+ // Reconstruct the callable.
+ Callable new_callable = Callable(target_node, conn.callable.get_method());
+
+ if (!modifiable_node->is_connected(conn.signal.get_name(), new_callable)) {
+ ERR_FAIL_COND(modifiable_node->connect(conn.signal.get_name(), new_callable, conn.flags) != OK);
+ }
+ }
+ }
+
+ // Restore the connections from other nodes.
+ for (const Connection &E2 : E.value.connections_from) {
+ Connection conn = E2;
+
+ bool valid = modifiable_node->has_method(conn.callable.get_method()) || Ref<Script>(modifiable_node->get_script()).is_null() || Ref<Script>(modifiable_node->get_script())->has_method(conn.callable.get_method());
+ ERR_CONTINUE_MSG(!valid, vformat("Attempt to connect signal '%s.%s' to nonexistent method '%s.%s'.", conn.signal.get_object()->get_class(), conn.signal.get_name(), conn.callable.get_object()->get_class(), conn.callable.get_method()));
+
+ // Get the object which the signal is connected from.
+ Object *source_object = conn.signal.get_object();
+
+ if (source_object) {
+ ERR_FAIL_COND(source_object->connect(conn.signal.get_name(), Callable(modifiable_node, conn.callable.get_method()), conn.flags) != OK);
+ }
+ }
+
+ // Re-add the groups.
+ for (const Node::GroupInfo &E2 : E.value.groups) {
+ modifiable_node->add_to_group(E2.name, E2.persistent);
+ }
+ }
+ }
+ }
+ // Cleanup the history of the changes.
+ editor_history.cleanup_history();
+
+ current_edited_scene->propagate_notification(NOTIFICATION_NODE_RECACHE_REQUESTED);
+ }
+ edited_scene_map.clear();
+ }
+ editor_data.set_edited_scene(original_edited_scene_idx);
+
+ _edit_current();
+}
+
int EditorNode::plugin_init_callback_count = 0;
void EditorNode::add_plugin_init_callback(EditorPluginInitializeCallback p_callback) {
@@ -6917,7 +7421,7 @@ EditorNode::EditorNode() {
_reset_play_buttons();
- ED_SHORTCUT_AND_COMMAND("editor/run_specific_scene", TTR("Run Specific Scene"), KeyModifierMask::META | KeyModifierMask::SHIFT | Key::F5);
+ ED_SHORTCUT_AND_COMMAND("editor/run_specific_scene", TTR("Run Specific Scene"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F5);
ED_SHORTCUT_OVERRIDE("editor/run_specific_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R);
play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_specific_scene"));
diff --git a/editor/editor_node.h b/editor/editor_node.h
index d7a4bd4434..bb10abb589 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -68,6 +68,7 @@ class EditorLayoutsDialog;
class EditorLog;
class EditorPluginList;
class EditorQuickOpen;
+class EditorPropertyResource;
class EditorResourcePreview;
class EditorResourceConversionPlugin;
class EditorRun;
@@ -86,6 +87,7 @@ class ImportDock;
class LinkButton;
class MenuBar;
class MenuButton;
+class Node2D;
class NodeDock;
class OptionButton;
class OrphanResourcesDialog;
@@ -293,6 +295,8 @@ private:
bool _initializing_plugins = false;
HashMap<String, EditorPlugin *> addon_name_to_plugin;
LocalVector<String> pending_addons;
+ HashMap<ObjectID, HashSet<EditorPlugin *>> active_plugins;
+ bool is_main_screen_editing = false;
PanelContainer *scene_root_parent = nullptr;
Control *theme_base = nullptr;
@@ -592,10 +596,6 @@ private:
void _inherit_request(String p_file);
void _instantiate_request(const Vector<String> &p_files);
- void _display_top_editors(bool p_display);
- void _set_top_editors(Vector<EditorPlugin *> p_editor_plugins_over);
- void _set_editing_top_editors(Object *p_current_object);
-
void _quick_opened();
void _quick_run();
void _open_command_palette();
@@ -796,9 +796,8 @@ public:
void show_about() { _menu_option_confirm(HELP_ABOUT, false); }
void push_item(Object *p_object, const String &p_property = "", bool p_inspector_only = false);
- void edit_item(Object *p_object);
- void edit_item_resource(Ref<Resource> p_resource);
- void hide_top_editors();
+ void edit_item(Object *p_object, Object *p_editing_owner);
+ void hide_unused_editors(const Object *p_editing_owner = nullptr);
void select_editor_by_name(const String &p_name);
@@ -820,6 +819,37 @@ public:
Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_clear_errors = true, bool p_force_open_imported = false, bool p_silent_change_tab = false);
Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false);
+ HashMap<StringName, Variant> get_modified_properties_for_node(Node *p_node);
+
+ struct AdditiveNodeEntry {
+ Node *node = nullptr;
+ NodePath parent = NodePath();
+ Node *owner = nullptr;
+ int index = 0;
+ // Used if the original parent node is lost
+ Transform2D transform_2d;
+ Transform3D transform_3d;
+ };
+
+ struct ConnectionWithNodePath {
+ Connection connection;
+ NodePath node_path;
+ };
+
+ struct ModificationNodeEntry {
+ HashMap<StringName, Variant> property_table;
+ List<ConnectionWithNodePath> connections_to;
+ List<Connection> connections_from;
+ List<Node::GroupInfo> groups;
+ };
+
+ void update_diff_data_for_node(
+ Node *p_edited_scene,
+ Node *p_root,
+ Node *p_node,
+ HashMap<NodePath, ModificationNodeEntry> &p_modification_table,
+ List<AdditiveNodeEntry> &p_addition_list);
+
bool is_scene_open(const String &p_path);
void set_current_scene(int p_idx);
@@ -872,6 +902,9 @@ public:
void reload_scene(const String &p_path);
+ void find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, List<Node *> &p_instance_list);
+ void reload_instances_with_path_in_edited_scenes(const String &p_path);
+
bool is_exiting() const { return exiting; }
Button *get_pause_button() { return pause_button; }
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 7f02148dfc..14cdbc364e 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -662,7 +662,7 @@ void EditorPlugin::make_visible(bool p_visible) {
}
void EditorPlugin::edit(Object *p_object) {
- if (p_object->is_class("Resource")) {
+ if (Object::cast_to<Resource>(p_object)) {
GDVIRTUAL_CALL(_edit, Ref<Resource>(Object::cast_to<Resource>(p_object)));
} else {
GDVIRTUAL_CALL(_edit, p_object);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 46f52ec4af..152e77acb7 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -268,7 +268,7 @@ void EditorPropertyTextEnum::_custom_value_accepted() {
_custom_value_submitted(new_value);
}
-void EditorPropertyTextEnum::_custom_value_cancelled() {
+void EditorPropertyTextEnum::_custom_value_canceled() {
custom_value_edit->set_text(get_edited_object()->get(get_edited_property()));
edit_custom_layout->hide();
@@ -380,7 +380,7 @@ EditorPropertyTextEnum::EditorPropertyTextEnum() {
cancel_button = memnew(Button);
cancel_button->set_flat(true);
edit_custom_layout->add_child(cancel_button);
- cancel_button->connect("pressed", callable_mp(this, &EditorPropertyTextEnum::_custom_value_cancelled));
+ cancel_button->connect("pressed", callable_mp(this, &EditorPropertyTextEnum::_custom_value_canceled));
add_focusable(option_button);
add_focusable(edit_button);
@@ -3905,40 +3905,7 @@ void EditorPropertyResource::_open_editor_pressed() {
Ref<Resource> res = get_edited_object()->get(get_edited_property());
if (res.is_valid()) {
// May clear the editor so do it deferred.
- callable_mp(EditorNode::get_singleton(), &EditorNode::edit_item_resource).bind(res).call_deferred();
- }
-}
-
-void EditorPropertyResource::_fold_other_editors(Object *p_self) {
- if (this == p_self) {
- return;
- }
-
- Ref<Resource> res = get_edited_object()->get(get_edited_property());
- if (!res.is_valid()) {
- return;
- }
-
- bool use_editor = false;
- for (int i = 0; i < EditorNode::get_editor_data().get_editor_plugin_count(); i++) {
- EditorPlugin *ep = EditorNode::get_editor_data().get_editor_plugin(i);
- if (ep->handles(res.ptr())) {
- use_editor = true;
- break;
- }
- }
- if (!use_editor) {
- return;
- }
-
- opened_editor = false;
-
- bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
- if (unfolded) {
- // Refold.
- resource_picker->set_toggle_pressed(false);
- get_edited_object()->editor_set_section_unfold(get_edited_property(), false);
- update_property();
+ callable_mp(EditorNode::get_singleton(), &EditorNode::edit_item).bind(res.ptr(), this).call_deferred();
}
}
@@ -4091,20 +4058,17 @@ void EditorPropertyResource::update_property() {
sub_inspector_vbox->add_child(sub_inspector);
resource_picker->set_toggle_pressed(true);
- bool use_editor = false;
+ Array editor_list;
for (int i = 0; i < EditorNode::get_editor_data().get_editor_plugin_count(); i++) {
EditorPlugin *ep = EditorNode::get_editor_data().get_editor_plugin(i);
if (ep->handles(res.ptr())) {
- use_editor = true;
+ editor_list.push_back(ep);
}
}
- if (use_editor) {
- // Open editor directly and hide other such editors which are currently open.
+ if (!editor_list.is_empty()) {
+ // Open editor directly.
_open_editor_pressed();
- if (is_inside_tree()) {
- get_tree()->call_deferred(SNAME("call_group"), "_editor_resource_properties", "_fold_other_editors", this);
- }
opened_editor = true;
}
@@ -4123,7 +4087,7 @@ void EditorPropertyResource::update_property() {
sub_inspector_vbox = nullptr;
if (opened_editor) {
- EditorNode::get_singleton()->hide_top_editors();
+ EditorNode::get_singleton()->hide_unused_editors();
opened_editor = false;
}
@@ -4157,6 +4121,15 @@ void EditorPropertyResource::set_use_sub_inspector(bool p_enable) {
use_sub_inspector = p_enable;
}
+void EditorPropertyResource::fold_resource() {
+ bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
+ if (unfolded) {
+ resource_picker->set_toggle_pressed(false);
+ get_edited_object()->editor_set_section_unfold(get_edited_property(), false);
+ update_property();
+ }
+}
+
void EditorPropertyResource::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
@@ -4168,14 +4141,8 @@ void EditorPropertyResource::_notification(int p_what) {
}
}
-void EditorPropertyResource::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_fold_other_editors"), &EditorPropertyResource::_fold_other_editors);
-}
-
EditorPropertyResource::EditorPropertyResource() {
use_sub_inspector = bool(EDITOR_GET("interface/inspector/open_resources_in_current_inspector"));
-
- add_to_group("_editor_resource_properties");
}
////////////// DEFAULT PLUGIN //////////////////////
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index a255af30ee..d29ec12f97 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -121,7 +121,7 @@ class EditorPropertyTextEnum : public EditorProperty {
void _edit_custom_value();
void _custom_value_submitted(String p_value);
void _custom_value_accepted();
- void _custom_value_cancelled();
+ void _custom_value_canceled();
protected:
virtual void _set_read_only(bool p_read_only) override;
@@ -834,13 +834,11 @@ class EditorPropertyResource : public EditorProperty {
void _sub_inspector_object_id_selected(int p_id);
void _open_editor_pressed();
- void _fold_other_editors(Object *p_self);
void _update_property_bg();
void _update_preferred_shader();
protected:
virtual void _set_read_only(bool p_read_only) override;
- static void _bind_methods();
void _notification(int p_what);
public:
@@ -852,6 +850,7 @@ public:
void expand_revertable() override;
void set_use_sub_inspector(bool p_enable);
+ void fold_resource();
EditorPropertyResource();
};
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index cb71a2457b..86ffbccefd 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -97,7 +97,7 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const
}
if (p_preview.is_valid()) {
- preview_rect->set_offset(SIDE_LEFT, assign_button->get_icon()->get_width() + assign_button->get_theme_stylebox(SNAME("normal"))->get_default_margin(SIDE_LEFT) + get_theme_constant(SNAME("h_separation"), SNAME("Button")));
+ preview_rect->set_offset(SIDE_LEFT, assign_button->get_icon()->get_width() + assign_button->get_theme_stylebox(SNAME("normal"))->get_content_margin(SIDE_LEFT) + get_theme_constant(SNAME("h_separation"), SNAME("Button")));
// Resource-specific stretching.
if (Ref<GradientTexture1D>(edited_resource).is_valid() || Ref<Gradient>(edited_resource).is_valid()) {
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 177266e366..54e14074d9 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -278,11 +278,11 @@ void EditorSpinSlider::_update_value_input_stylebox() {
// higher margin to match the location where the text begins.
// The margin values below were determined by empirical testing.
if (is_layout_rtl()) {
- stylebox->set_default_margin(SIDE_LEFT, 0);
- stylebox->set_default_margin(SIDE_RIGHT, (!get_label().is_empty() ? 23 : 16) * EDSCALE);
+ stylebox->set_content_margin(SIDE_LEFT, 0);
+ stylebox->set_content_margin(SIDE_RIGHT, (!get_label().is_empty() ? 23 : 16) * EDSCALE);
} else {
- stylebox->set_default_margin(SIDE_LEFT, (!get_label().is_empty() ? 23 : 16) * EDSCALE);
- stylebox->set_default_margin(SIDE_RIGHT, 0);
+ stylebox->set_content_margin(SIDE_LEFT, (!get_label().is_empty() ? 23 : 16) * EDSCALE);
+ stylebox->set_content_margin(SIDE_RIGHT, 0);
}
value_input->add_theme_style_override("normal", stylebox);
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 7a880d2ab3..745acca04b 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -197,15 +197,15 @@ void EditorColorMap::create() {
static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) {
Ref<StyleBoxTexture> style(memnew(StyleBoxTexture));
style->set_texture(p_texture);
- style->set_margin_size_individual(p_left * EDSCALE, p_top * EDSCALE, p_right * EDSCALE, p_bottom * EDSCALE);
- style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
+ style->set_texture_margin_individual(p_left * EDSCALE, p_top * EDSCALE, p_right * EDSCALE, p_bottom * EDSCALE);
+ style->set_content_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
style->set_draw_center(p_draw_center);
return style;
}
static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty));
- style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
+ style->set_content_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
return style;
}
@@ -215,7 +215,7 @@ static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left =
// Adjust level of detail based on the corners' effective sizes.
style->set_corner_detail(Math::ceil(0.8 * p_corner_width * EDSCALE));
style->set_corner_radius_all(p_corner_width * EDSCALE);
- style->set_default_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
+ style->set_content_margin_individual(p_margin_left * EDSCALE, p_margin_top * EDSCALE, p_margin_right * EDSCALE, p_margin_bottom * EDSCALE);
// Work around issue about antialiased edges being blurrier (GH-35279).
style->set_anti_aliased(false);
return style;
@@ -648,7 +648,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Vector2 widget_default_margin = Vector2(extra_spacing + 6, extra_spacing + default_margin_size + 1) * EDSCALE;
Ref<StyleBoxFlat> style_widget = style_default->duplicate();
- style_widget->set_default_margin_individual(widget_default_margin.x, widget_default_margin.y, widget_default_margin.x, widget_default_margin.y);
+ style_widget->set_content_margin_individual(widget_default_margin.x, widget_default_margin.y, widget_default_margin.x, widget_default_margin.y);
style_widget->set_bg_color(dark_color_1);
if (draw_extra_borders) {
style_widget->set_border_width_all(Math::round(EDSCALE));
@@ -684,7 +684,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Style for windows, popups, etc..
Ref<StyleBoxFlat> style_popup = style_default->duplicate();
const int popup_margin_size = default_margin_size * EDSCALE * 3;
- style_popup->set_default_margin_all(popup_margin_size);
+ style_popup->set_content_margin_all(popup_margin_size);
style_popup->set_border_color(contrast_color_1);
const Color shadow_color = Color(0, 0, 0, dark_theme ? 0.3 : 0.1);
style_popup->set_shadow_color(shadow_color);
@@ -722,12 +722,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_tab_base->set_corner_radius(CORNER_BOTTOM_RIGHT, 0);
// When using a border width greater than 0, visually line up the left of the selected tab with the underlying panel.
- style_tab_base->set_expand_margin_size(SIDE_LEFT, -border_width);
+ style_tab_base->set_expand_margin(SIDE_LEFT, -border_width);
- style_tab_base->set_default_margin(SIDE_LEFT, widget_default_margin.x + 5 * EDSCALE);
- style_tab_base->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 5 * EDSCALE);
- style_tab_base->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
- style_tab_base->set_default_margin(SIDE_TOP, widget_default_margin.y);
+ style_tab_base->set_content_margin(SIDE_LEFT, widget_default_margin.x + 5 * EDSCALE);
+ style_tab_base->set_content_margin(SIDE_RIGHT, widget_default_margin.x + 5 * EDSCALE);
+ style_tab_base->set_content_margin(SIDE_BOTTOM, widget_default_margin.y);
+ style_tab_base->set_content_margin(SIDE_TOP, widget_default_margin.y);
Ref<StyleBoxFlat> style_tab_selected = style_tab_base->duplicate();
@@ -740,13 +740,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_tab_selected->set_corner_radius_all(0);
Ref<StyleBoxFlat> style_tab_unselected = style_tab_base->duplicate();
- style_tab_unselected->set_expand_margin_size(SIDE_BOTTOM, 0);
+ style_tab_unselected->set_expand_margin(SIDE_BOTTOM, 0);
style_tab_unselected->set_bg_color(dark_color_1);
// Add some spacing between unselected tabs to make them easier to distinguish from each other
style_tab_unselected->set_border_color(Color(0, 0, 0, 0));
Ref<StyleBoxFlat> style_tab_disabled = style_tab_base->duplicate();
- style_tab_disabled->set_expand_margin_size(SIDE_BOTTOM, 0);
+ style_tab_disabled->set_expand_margin(SIDE_BOTTOM, 0);
style_tab_disabled->set_bg_color(disabled_bg_color);
style_tab_disabled->set_border_color(disabled_bg_color);
@@ -772,7 +772,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// CanvasItem Editor
Ref<StyleBoxFlat> style_canvas_editor_info = make_flat_stylebox(Color(0.0, 0.0, 0.0, 0.2));
- style_canvas_editor_info->set_expand_margin_size_all(4 * EDSCALE);
+ style_canvas_editor_info->set_expand_margin_all(4 * EDSCALE);
theme->set_stylebox("CanvasItemInfoOverlay", "EditorStyles", style_canvas_editor_info);
// 2D and 3D contextual toolbar.
@@ -787,7 +787,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Add an underline to the StyleBox, but prevent its minimum vertical size from changing.
toolbar_stylebox->set_border_color(accent_color);
toolbar_stylebox->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE));
- toolbar_stylebox->set_default_margin(SIDE_BOTTOM, 0);
+ toolbar_stylebox->set_content_margin(SIDE_BOTTOM, 0);
theme->set_stylebox("ContextualToolbar", "EditorStyles", toolbar_stylebox);
// Script Editor
@@ -808,11 +808,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> style_write_movie_button = style_widget_pressed->duplicate();
style_write_movie_button->set_bg_color(accent_color);
style_write_movie_button->set_corner_radius_all(corner_radius * EDSCALE);
- style_write_movie_button->set_default_margin(SIDE_TOP, 0);
- style_write_movie_button->set_default_margin(SIDE_BOTTOM, 0);
- style_write_movie_button->set_default_margin(SIDE_LEFT, 0);
- style_write_movie_button->set_default_margin(SIDE_RIGHT, 0);
- style_write_movie_button->set_expand_margin_size(SIDE_RIGHT, 2 * EDSCALE);
+ style_write_movie_button->set_content_margin(SIDE_TOP, 0);
+ style_write_movie_button->set_content_margin(SIDE_BOTTOM, 0);
+ style_write_movie_button->set_content_margin(SIDE_LEFT, 0);
+ style_write_movie_button->set_content_margin(SIDE_RIGHT, 0);
+ style_write_movie_button->set_expand_margin(SIDE_RIGHT, 2 * EDSCALE);
theme->set_stylebox("MovieWriterButtonPressed", "EditorStyles", style_write_movie_button);
theme->set_stylebox("normal", "MenuButton", style_menu);
@@ -855,16 +855,16 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
color_inspector_action.a = 0.5;
Ref<StyleBoxFlat> style_inspector_action = style_widget->duplicate();
style_inspector_action->set_bg_color(color_inspector_action);
- style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN);
+ style_inspector_action->set_content_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN);
theme->set_stylebox("normal", "InspectorActionButton", style_inspector_action);
style_inspector_action = style_widget_hover->duplicate();
- style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN);
+ style_inspector_action->set_content_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN);
theme->set_stylebox("hover", "InspectorActionButton", style_inspector_action);
style_inspector_action = style_widget_pressed->duplicate();
- style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN);
+ style_inspector_action->set_content_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN);
theme->set_stylebox("pressed", "InspectorActionButton", style_inspector_action);
style_inspector_action = style_widget_disabled->duplicate();
- style_inspector_action->set_default_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN);
+ style_inspector_action->set_content_margin(SIDE_RIGHT, ACTION_BUTTON_EXTRA_MARGIN);
theme->set_stylebox("disabled", "InspectorActionButton", style_inspector_action);
theme->set_constant("h_separation", "InspectorActionButton", ACTION_BUTTON_EXTRA_MARGIN);
@@ -908,11 +908,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> style_option_button_pressed = style_widget_pressed->duplicate();
Ref<StyleBoxFlat> style_option_button_disabled = style_widget_disabled->duplicate();
- style_option_button_focus->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
- style_option_button_normal->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
- style_option_button_hover->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
- style_option_button_pressed->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
- style_option_button_disabled->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
+ style_option_button_focus->set_content_margin(SIDE_RIGHT, 4 * EDSCALE);
+ style_option_button_normal->set_content_margin(SIDE_RIGHT, 4 * EDSCALE);
+ style_option_button_hover->set_content_margin(SIDE_RIGHT, 4 * EDSCALE);
+ style_option_button_pressed->set_content_margin(SIDE_RIGHT, 4 * EDSCALE);
+ style_option_button_disabled->set_content_margin(SIDE_RIGHT, 4 * EDSCALE);
theme->set_stylebox("focus", "OptionButton", style_option_button_focus);
theme->set_stylebox("normal", "OptionButton", style_widget);
@@ -978,7 +978,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Checkbox
Ref<StyleBoxFlat> sb_checkbox = style_menu->duplicate();
- sb_checkbox->set_default_margin_all(default_margin_size * EDSCALE);
+ sb_checkbox->set_content_margin_all(default_margin_size * EDSCALE);
theme->set_stylebox("normal", "CheckBox", sb_checkbox);
theme->set_stylebox("pressed", "CheckBox", sb_checkbox);
@@ -1018,7 +1018,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Use 1 pixel for the sides, since if 0 is used, the highlight of hovered items is drawn
// on top of the popup border. This causes a 'gap' in the panel border when an item is highlighted,
// and it looks weird. 1px solves this.
- style_popup_menu->set_default_margin_individual(EDSCALE, 2 * EDSCALE, EDSCALE, 2 * EDSCALE);
+ style_popup_menu->set_content_margin_individual(EDSCALE, 2 * EDSCALE, EDSCALE, 2 * EDSCALE);
// Always display a border for PopupMenus so they can be distinguished from their background.
style_popup_menu->set_border_width_all(EDSCALE);
if (draw_extra_borders) {
@@ -1078,7 +1078,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
sub_inspector_bg->set_bg_color(dark_color_1.lerp(si_base_color, 0.08));
sub_inspector_bg->set_border_width_all(2 * EDSCALE);
sub_inspector_bg->set_border_color(si_base_color * Color(0.7, 0.7, 0.7, 0.8));
- sub_inspector_bg->set_default_margin_all(4 * EDSCALE);
+ sub_inspector_bg->set_content_margin_all(4 * EDSCALE);
sub_inspector_bg->set_corner_radius(CORNER_TOP_LEFT, 0);
sub_inspector_bg->set_corner_radius(CORNER_TOP_RIGHT, 0);
@@ -1318,7 +1318,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_content_panel->set_corner_radius(CORNER_TOP_LEFT, 0);
style_content_panel->set_corner_radius(CORNER_TOP_RIGHT, 0);
// Compensate for the border.
- style_content_panel->set_default_margin_individual(margin_size_extra * EDSCALE, (2 + margin_size_extra) * EDSCALE, margin_size_extra * EDSCALE, margin_size_extra * EDSCALE);
+ style_content_panel->set_content_margin_individual(margin_size_extra * EDSCALE, (2 + margin_size_extra) * EDSCALE, margin_size_extra * EDSCALE, margin_size_extra * EDSCALE);
theme->set_stylebox("panel", "TabContainer", style_content_panel);
// Bottom panel.
@@ -1339,15 +1339,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// This stylebox is used in 3d and 2d viewports (no borders).
Ref<StyleBoxFlat> style_content_panel_vp = style_content_panel->duplicate();
- style_content_panel_vp->set_default_margin_individual(border_width * 2, default_margin_size * EDSCALE, border_width * 2, border_width * 2);
+ style_content_panel_vp->set_content_margin_individual(border_width * 2, default_margin_size * EDSCALE, border_width * 2, border_width * 2);
theme->set_stylebox("Content", "EditorStyles", style_content_panel_vp);
// This stylebox is used by preview tabs in the Theme Editor.
Ref<StyleBoxFlat> style_theme_preview_tab = style_tab_selected_odd->duplicate();
- style_theme_preview_tab->set_expand_margin_size(SIDE_BOTTOM, 5 * EDSCALE);
+ style_theme_preview_tab->set_expand_margin(SIDE_BOTTOM, 5 * EDSCALE);
theme->set_stylebox("ThemeEditorPreviewFG", "EditorStyles", style_theme_preview_tab);
Ref<StyleBoxFlat> style_theme_preview_bg_tab = style_tab_unselected->duplicate();
- style_theme_preview_bg_tab->set_expand_margin_size(SIDE_BOTTOM, 2 * EDSCALE);
+ style_theme_preview_bg_tab->set_expand_margin(SIDE_BOTTOM, 2 * EDSCALE);
theme->set_stylebox("ThemeEditorPreviewBG", "EditorStyles", style_theme_preview_bg_tab);
// Separators
@@ -1361,9 +1361,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("DebuggerPanel", "EditorStyles", style_panel_debugger);
Ref<StyleBoxFlat> style_panel_invisible_top = style_content_panel->duplicate();
- int stylebox_offset = theme->get_font(SNAME("tab_selected"), SNAME("TabContainer"))->get_height(theme->get_font_size(SNAME("tab_selected"), SNAME("TabContainer"))) + theme->get_stylebox(SNAME("tab_selected"), SNAME("TabContainer"))->get_minimum_size().height + theme->get_stylebox(SNAME("panel"), SNAME("TabContainer"))->get_default_margin(SIDE_TOP);
- style_panel_invisible_top->set_expand_margin_size(SIDE_TOP, -stylebox_offset);
- style_panel_invisible_top->set_default_margin(SIDE_TOP, 0);
+ int stylebox_offset = theme->get_font(SNAME("tab_selected"), SNAME("TabContainer"))->get_height(theme->get_font_size(SNAME("tab_selected"), SNAME("TabContainer"))) + theme->get_stylebox(SNAME("tab_selected"), SNAME("TabContainer"))->get_minimum_size().height + theme->get_stylebox(SNAME("panel"), SNAME("TabContainer"))->get_content_margin(SIDE_TOP);
+ style_panel_invisible_top->set_expand_margin(SIDE_TOP, -stylebox_offset);
+ style_panel_invisible_top->set_content_margin(SIDE_TOP, 0);
theme->set_stylebox("BottomPanelDebuggerOverride", "EditorStyles", style_panel_invisible_top);
// LineEdit
@@ -1371,7 +1371,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> style_line_edit = style_widget->duplicate();
// The original style_widget style has an extra 1 pixel offset that makes LineEdits not align with Buttons,
// so this compensates for that.
- style_line_edit->set_default_margin(SIDE_TOP, style_line_edit->get_default_margin(SIDE_TOP) - 1 * EDSCALE);
+ style_line_edit->set_content_margin(SIDE_TOP, style_line_edit->get_content_margin(SIDE_TOP) - 1 * EDSCALE);
// Don't round the bottom corner to make the line look sharper.
style_tab_selected->set_corner_radius(CORNER_BOTTOM_LEFT, 0);
@@ -1459,12 +1459,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_window_title->set_corner_radius(CORNER_TOP_LEFT, 0);
style_window_title->set_corner_radius(CORNER_TOP_RIGHT, 0);
// Prevent visible line between window title and body.
- style_window_title->set_expand_margin_size(SIDE_BOTTOM, 2 * EDSCALE);
+ style_window_title->set_expand_margin(SIDE_BOTTOM, 2 * EDSCALE);
Ref<StyleBoxFlat> style_window = style_popup->duplicate();
style_window->set_border_color(base_color);
style_window->set_border_width(SIDE_TOP, 24 * EDSCALE);
- style_window->set_expand_margin_size(SIDE_TOP, 24 * EDSCALE);
+ style_window->set_expand_margin(SIDE_TOP, 24 * EDSCALE);
theme->set_stylebox("embedded_border", "Window", style_window);
theme->set_color("title_color", "Window", font_color);
@@ -1598,7 +1598,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// is only relevant for default tooltips.
Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate();
style_tooltip->set_shadow_size(0);
- style_tooltip->set_default_margin_all(default_margin_size * EDSCALE * 0.5);
+ style_tooltip->set_content_margin_all(default_margin_size * EDSCALE * 0.5);
style_tooltip->set_bg_color(dark_color_3 * Color(0.8, 0.8, 0.8, 0.9));
style_tooltip->set_border_width_all(0);
theme->set_color("font_color", "TooltipLabel", font_hover_color);
@@ -1610,10 +1610,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<StyleBoxFlat> control_editor_popup_style = style_popup->duplicate();
control_editor_popup_style->set_shadow_size(0);
- control_editor_popup_style->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE);
- control_editor_popup_style->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE);
- control_editor_popup_style->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE);
- control_editor_popup_style->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_content_margin(SIDE_LEFT, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_content_margin(SIDE_TOP, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_content_margin(SIDE_RIGHT, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_content_margin(SIDE_BOTTOM, default_margin_size * EDSCALE);
control_editor_popup_style->set_border_width_all(0);
theme->set_stylebox("panel", "ControlEditorPopupPanel", control_editor_popup_style);
@@ -1826,8 +1826,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Dictionary editor add item.
// Expand to the left and right by 4px to compensate for the dictionary editor margins.
Ref<StyleBoxFlat> style_dictionary_add_item = make_flat_stylebox(prop_subsection_color, 0, 4, 0, 4, corner_radius);
- style_dictionary_add_item->set_expand_margin_size(SIDE_LEFT, 4 * EDSCALE);
- style_dictionary_add_item->set_expand_margin_size(SIDE_RIGHT, 4 * EDSCALE);
+ style_dictionary_add_item->set_expand_margin(SIDE_LEFT, 4 * EDSCALE);
+ style_dictionary_add_item->set_expand_margin(SIDE_RIGHT, 4 * EDSCALE);
theme->set_stylebox("DictionaryAddItem", "EditorStyles", style_dictionary_add_item);
Ref<StyleBoxEmpty> vshader_label_style = make_empty_stylebox(2, 1, 2, 1);
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index 43f2c4e74e..73b645f351 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -525,7 +525,7 @@ EditorToaster::EditorToaster() {
Ref<StyleBoxFlat> boxes[] = { info_panel_style_background, warning_panel_style_background, error_panel_style_background };
for (int i = 0; i < 3; i++) {
- boxes[i]->set_default_margin_individual(int(stylebox_radius * 2.5), 3, int(stylebox_radius * 2.5), 3);
+ boxes[i]->set_content_margin_individual(int(stylebox_radius * 2.5), 3, int(stylebox_radius * 2.5), 3);
}
// Theming (progress).
diff --git a/editor/event_listener_line_edit.cpp b/editor/event_listener_line_edit.cpp
index 274fe34c52..ea4a7133bf 100644
--- a/editor/event_listener_line_edit.cpp
+++ b/editor/event_listener_line_edit.cpp
@@ -59,16 +59,42 @@ static const char *_joy_axis_descriptions[(size_t)JoyAxis::MAX * 2] = {
String EventListenerLineEdit::get_event_text(const Ref<InputEvent> &p_event, bool p_include_device) {
ERR_FAIL_COND_V_MSG(p_event.is_null(), String(), "Provided event is not a valid instance of InputEvent");
- String text = p_event->as_text();
-
+ String text;
Ref<InputEventKey> key = p_event;
- if (key.is_valid() && key->is_command_or_control_autoremap()) {
+ if (key.is_valid()) {
+ String mods_text = key->InputEventWithModifiers::as_text();
+ mods_text = mods_text.is_empty() ? mods_text : mods_text + "+";
+ if (key->is_command_or_control_autoremap()) {
#ifdef MACOS_ENABLED
- text = text.replace("Command", "Command/Ctrl");
+ mods_text = mods_text.replace("Command", "Command/Ctrl");
#else
- text = text.replace("Ctrl", "Command/Ctrl");
+ mods_text = mods_text.replace("Ctrl", "Command/Ctrl");
#endif
+ }
+
+ if (key->get_keycode() != Key::NONE) {
+ text += mods_text + keycode_get_string(key->get_keycode());
+ }
+ if (key->get_physical_keycode() != Key::NONE) {
+ if (!text.is_empty()) {
+ text += " or ";
+ }
+ text += mods_text + keycode_get_string(key->get_physical_keycode()) + " (" + RTR("Physical") + ")";
+ }
+ if (key->get_key_label() != Key::NONE) {
+ if (!text.is_empty()) {
+ text += " or ";
+ }
+ text += mods_text + keycode_get_string(key->get_key_label()) + " (Unicode)";
+ }
+
+ if (text.is_empty()) {
+ text = "(" + RTR("Unset") + ")";
+ }
+ } else {
+ text = p_event->as_text();
}
+
Ref<InputEventMouse> mouse = p_event;
Ref<InputEventJoypadMotion> jp_motion = p_event;
Ref<InputEventJoypadButton> jp_button = p_event;
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index f41792af7f..a078c58e72 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -2648,7 +2648,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
p_popup->add_icon_shortcut(get_theme_icon(SNAME("Filesystem"), SNAME("EditorIcons")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER);
p_popup->set_item_text(p_popup->get_item_index(FILE_SHOW_IN_EXPLORER), item_text);
if (!is_directory) {
- p_popup->add_icon_item(get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), TTR("Open in External Program"), FILE_OPEN_EXTERNAL);
+ p_popup->add_icon_shortcut(get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_GET_SHORTCUT("filesystem_dock/open_in_external_program"), FILE_OPEN_EXTERNAL);
}
path = fpath;
}
@@ -2869,6 +2869,8 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
_tree_rmb_option(FILE_RENAME);
} else if (ED_IS_SHORTCUT("filesystem_dock/show_in_explorer", p_event)) {
_tree_rmb_option(FILE_SHOW_IN_EXPLORER);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/open_in_external_program", p_event)) {
+ _tree_rmb_option(FILE_OPEN_EXTERNAL);
} else if (ED_IS_SHORTCUT("editor/open_search", p_event)) {
focus_on_filter();
} else {
@@ -2939,12 +2941,19 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
}
}
-void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &r_files) const {
+bool FileSystemDock::_get_imported_files(const String &p_path, String &r_extension, Vector<String> &r_files) const {
if (!p_path.ends_with("/")) {
if (FileAccess::exists(p_path + ".import")) {
+ if (r_extension.is_empty()) {
+ r_extension = p_path.get_extension();
+ } else if (r_extension != p_path.get_extension()) {
+ r_files.clear();
+ return false; // File type mismatch, stop search.
+ }
+
r_files.push_back(p_path);
}
- return;
+ return true;
}
Ref<DirAccess> da = DirAccess::open(p_path);
@@ -2953,11 +2962,14 @@ void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &r
while (!n.is_empty()) {
if (n != "." && n != ".." && !n.ends_with(".import")) {
String npath = p_path + n + (da->current_is_dir() ? "/" : "");
- _get_imported_files(npath, r_files);
+ if (!_get_imported_files(npath, r_extension, r_files)) {
+ return false;
+ }
}
n = da->get_next();
}
da->list_dir_end();
+ return true;
}
void FileSystemDock::_update_import_dock() {
@@ -2982,10 +2994,16 @@ void FileSystemDock::_update_import_dock() {
}
}
- // Expand directory selection
+ if (!selected.is_empty() && selected[0] == "res://") {
+ // Scanning res:// is costly and unlikely to yield any useful results.
+ return;
+ }
+
+ // Expand directory selection.
Vector<String> efiles;
- for (int i = 0; i < selected.size(); i++) {
- _get_imported_files(selected[i], efiles);
+ String extension;
+ for (const String &fpath : selected) {
+ _get_imported_files(fpath, extension, efiles);
}
// Check import.
@@ -3098,6 +3116,7 @@ FileSystemDock::FileSystemDock() {
ED_SHORTCUT("filesystem_dock/rename", TTR("Rename..."), Key::F2);
ED_SHORTCUT_OVERRIDE("filesystem_dock/rename", "macos", Key::ENTER);
ED_SHORTCUT("filesystem_dock/show_in_explorer", TTR("Open in File Manager"));
+ ED_SHORTCUT("filesystem_dock/open_in_external_program", TTR("Open in External Program"));
VBoxContainer *top_vbc = memnew(VBoxContainer);
add_child(top_vbc);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 3f12b73043..42a72b7ee8 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -214,7 +214,7 @@ private:
void _file_multi_selected(int p_index, bool p_selected);
void _tree_multi_selected(Object *p_item, int p_column, bool p_selected);
- void _get_imported_files(const String &p_path, Vector<String> &r_files) const;
+ bool _get_imported_files(const String &p_path, String &r_extension, Vector<String> &r_files) const;
void _update_import_dock();
void _get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Vector<String> &r_files, Vector<String> &r_folders) const;
diff --git a/editor/icons/Keyboard.svg b/editor/icons/Keyboard.svg
index b9dfab71ed..b6d963f9d7 100644
--- a/editor/icons/Keyboard.svg
+++ b/editor/icons/Keyboard.svg
@@ -1 +1 @@
-<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".996"><path d="m4 2a1 1 0 0 0 -1 1v9.084c0 .506.448.916 1 .916h8c.552 0 1-.41 1-.916v-9.084a1 1 0 0 0 -1-1zm1.543 1.139h1.393l1.834 4.199h1.295v.437c.708.052 1.246.239 1.61.559.368.316.55.747.55 1.295 0 .552-.182.99-.55 1.314-.368.32-.906.505-1.61.553v.467h-1.294v-.473c-.708-.06-1.247-.248-1.615-.564-.364-.316-.545-.75-.545-1.297 0-.548.181-.977.545-1.29.368-.315.907-.504 1.615-.564v-.437h-1.464l-.282-.733h-1.595l-.284.733h-1.439l1.836-4.2zm.684 1.39-.409 1.057h.817zm3.84 4.338v1.526c.28-.04.483-.12.607-.24.124-.125.185-.302.185-.53 0-.224-.063-.396-.191-.516-.124-.12-.326-.2-.602-.24zm-1.296.006c-.284.04-.487.12-.61.24-.12.116-.182.288-.182.516 0 .22.065.392.193.512.132.12.331.202.6.246v-1.514z" fill="#e0e0e0"/><path d="m27 2h7v14h-7z" fill="#fff"/><path d="m1 4v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-9h-1v9a1 1 0 0 1 -1 1h-10a1 1 0 0 1 -1-1v-9z" fill="#e0e0e0"/></g></svg>
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path d="M6.584 5.135 6.17 4.059l-.412 1.076h.826zm3.203 2.976a1.032 1.032 0 0 0-.287.041.953.953 0 0 0-.09.034c-.028.012-.057.024-.084.039a.912.912 0 0 0-.152.107.988.988 0 0 0-.23.305.937.937 0 0 0-.04.097 1.017 1.017 0 0 0-.068.323 1.553 1.553 0 0 0 0 .244 1.374 1.374 0 0 0 .068.328 1.03 1.03 0 0 0 .201.336c.023.022.045.044.069.064a.96.96 0 0 0 .152.104c.027.015.056.027.084.039.03.012.06.024.09.033a.965.965 0 0 0 .19.035 1.028 1.028 0 0 0 .197 0 .974.974 0 0 0 .36-.107.876.876 0 0 0 .077-.049.872.872 0 0 0 .074-.055.882.882 0 0 0 .13-.136.978.978 0 0 0 .177-.368 1.225 1.225 0 0 0 .035-.224 1.61 1.61 0 0 0 0-.244 1.361 1.361 0 0 0-.035-.223 1.092 1.092 0 0 0-.121-.285.87.87 0 0 0-.12-.15.862.862 0 0 0-.14-.124c-.025-.017-.05-.035-.078-.05-.027-.015-.056-.027-.086-.04a.892.892 0 0 0-.373-.074z" style="fill-opacity:.99607843;fill:#e0e0e0"/><path d="M4 2c-.616-.02-1.084.59-1 1.178.003 3-.007 6 .005 9 .057.577.672.889 1.203.822 2.631-.003 5.263.006 7.894-.005a.973.973 0 0 0 .898-1.09c-.003-3.002.007-6.005-.005-9.007-.042-.592-.643-.976-1.203-.898H4Zm1.475.646H6.89l1.865 4.27H7.268l-.286-.744H5.36l-.287.744H3.61l1.866-4.27Zm4.312 4.301c1.069-.042 2.164.679 2.363 1.766.232 1.01-.34 2.144-1.326 2.502.296.465.837-.109 1.06-.007l.544.642c-.64.756-1.883.677-2.605.084-.394-.448-.866-.673-1.409-.887-1.175-.66-1.391-2.456-.43-3.39.463-.486 1.141-.716 1.803-.71Z" style="fill:#e0e0e0;fill-opacity:.996078"/><path fill="#e0e0e0" d="M1 4v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V4h-1v9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4Z" style="fill-opacity:.996"/></svg>
diff --git a/editor/icons/KeyboardError.svg b/editor/icons/KeyboardError.svg
new file mode 100644
index 0000000000..e20d133155
--- /dev/null
+++ b/editor/icons/KeyboardError.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path d="M4 2c-.616-.02-1.084.59-1 1.178.003 3-.007 6 .005 9 .057.577.672.889 1.203.822 2.631-.003 5.263.006 7.894-.005a.973.973 0 0 0 .898-1.09c-.003-3.002.007-6.005-.005-9.007-.042-.592-.643-.976-1.203-.898H4Zm4.223 1.262c1.06.005 2.29.257 2.92 1.197.532.862.275 2.057-.484 2.703-.346.382-.862.629-1.075 1.117.055.345-.33.172-.537.213H7.148c-.037-.749.503-1.335 1.026-1.796.406-.253.744-1.002.129-1.22-.626-.25-1.374.117-1.645.715l-2.08-1.039c.599-1.147 1.868-1.818 3.136-1.872.17-.013.339-.018.509-.018Zm.127 5.697c.798-.057 1.616.616 1.54 1.45-.023.81-.841 1.413-1.623 1.328-.833.022-1.6-.771-1.443-1.613.097-.721.83-1.195 1.526-1.165z" style="fill:#ff5f5f;fill-opacity:1"/><path fill="#e0e0e0" d="M1 4v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V4h-1v9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4Z" style="fill-opacity:1;fill:#ff5f5f"/></svg>
diff --git a/editor/icons/KeyboardLabel.svg b/editor/icons/KeyboardLabel.svg
new file mode 100644
index 0000000000..07a687f447
--- /dev/null
+++ b/editor/icons/KeyboardLabel.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M11.814 1.977c-.078 0-.157.008-.232.023H4c-.7-.034-1.143.765-1 1.39.008 2.95-.017 5.9.014 8.848.13.705.965.847 1.562.76 2.542-.008 5.085.02 7.627-.014.734-.1.9-.952.797-1.564-.003-2.84.006-5.68-.006-8.522-.035-.594-.628-.927-1.18-.921zM9.797 4.016l.572.58-.572.578-.57-.578.57-.58zm-.606 1.05.594.606-.594.601-.591-.601.591-.606zm1.213 0 .596.606-.596.601-.593-.601.593-.606zm.717 1.436h1.06c.053.217.093.428.122.63.028.201.043.395.043.58a2.363 2.363 0 0 1-.133.724 1.425 1.425 0 0 1-.31.515c-.249.265-.598.399-1.05.399-.331 0-.594-.08-.785-.235a1.091 1.091 0 0 1-.236-.275c-.063.1-.14.19-.236.265-.206.163-.467.245-.787.245-.252 0-.457-.057-.614-.166a2.75 2.75 0 0 1-.095.42 1.936 1.936 0 0 1-.403.722c-.2.22-.452.383-.756.49-.303.11-.654.166-1.052.166-.466 0-.865-.089-1.2-.265a1.817 1.817 0 0 1-.765-.752c-.18-.327-.27-.715-.27-1.164 0-.256.027-.525.082-.809.055-.284.126-.545.21-.781h1.001c-.062.232-.112.46-.15.684a3.87 3.87 0 0 0-.053.613c0 .37.1.643.3.82.204.177.523.264.96.264.222 0 .425-.03.61-.092a.97.97 0 0 0 .439-.299.803.803 0 0 0 .166-.521 5.463 5.463 0 0 0-.051-.725 11.61 11.61 0 0 0-.068-.482 26.51 26.51 0 0 0-.096-.606h1.135l.043.276c.047.32.123.532.228.634.105.1.24.15.402.15.165 0 .284-.04.358-.124.076-.086.115-.224.115-.412v-.524h1.027v.524c0 .203.032.351.096.447.065.095.202.142.412.142a.637.637 0 0 0 .33-.078c.089-.052.133-.15.133-.297 0-.128-.019-.295-.054-.498l-.108-.605z" style="fill:#e0e0e0;fill-opacity:.996078"/><path fill="#e0e0e0" d="M1 4v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V4h-1v9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4Z" style="fill-opacity:.996"/></svg>
diff --git a/editor/icons/KeyboardPhysical.svg b/editor/icons/KeyboardPhysical.svg
index 4364e0b4fa..7d4b7e2999 100644
--- a/editor/icons/KeyboardPhysical.svg
+++ b/editor/icons/KeyboardPhysical.svg
@@ -1 +1 @@
-<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".996"><path d="m4 2a1 1 0 0 0 -1 1v9.084c0 .506.448.916 1 .916h8c.552 0 1-.41 1-.916v-9.084a1 1 0 0 0 -1-1zm2.762 1.768h2.476l3.264 7.464h-2.604l-.502-1.3h-2.835l-.502 1.3h-2.561zm1.217 2.474-.725 1.878h1.45z" fill="#e0e0e0"/><path d="m27 2h7v14h-7z" fill="#fff"/><path d="m1 4v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-9h-1v9a1 1 0 0 1 -1 1h-10a1 1 0 0 1 -1-1v-9z" fill="#e0e0e0"/></g></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="M4 2a1 1 0 0 0-1 1v9.084c0 .506.448.916 1 .916h8c.552 0 1-.41 1-.916V3a1 1 0 0 0-1-1Zm2.762 1.768h2.476l3.264 7.464H9.898l-.502-1.3H6.561l-.502 1.3H3.498Zm1.217 2.474L7.254 8.12h1.45z" style="fill-opacity:.996"/><path fill="#e0e0e0" d="M1 4v9a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V4h-1v9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4Z" style="fill-opacity:.996"/></svg>
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 4b0ece3367..1ffede6502 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -734,7 +734,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p
/* CREATE PRIMITIVE ARRAY */
/**************************/
- // The way collada uses indices is more optimal, and friendlier with 3D modelling software,
+ // The way collada uses indices is more optimal, and friendlier with 3D modeling software,
// because it can index everything, not only vertices (similar to how the WII works).
// This is, however, more incompatible with standard video cards, so arrays must be converted.
// Must convert to GL/DX format.
diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp
index 08d4bfff4a..48e3759e57 100644
--- a/editor/input_event_configuration_dialog.cpp
+++ b/editor/input_event_configuration_dialog.cpp
@@ -38,9 +38,10 @@
#include "scene/gui/separator.h"
#include "scene/gui/tree.h"
-void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, bool p_update_input_list_selection) {
+void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, const Ref<InputEvent> &p_original_event, bool p_update_input_list_selection) {
if (p_event.is_valid()) {
event = p_event;
+ original_event = p_original_event;
// If the event is changed to something which is not the same as the listener,
// clear out the event from the listener text box to avoid confusion.
@@ -61,7 +62,7 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, b
// Update option values and visibility
bool show_mods = false;
bool show_device = false;
- bool show_phys_key = false;
+ bool show_key = false;
if (mod.is_valid()) {
show_mods = true;
@@ -74,9 +75,25 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, b
}
if (k.is_valid()) {
- show_phys_key = true;
- physical_key_checkbox->set_pressed(k->get_physical_keycode() != Key::NONE && k->get_keycode() == Key::NONE);
-
+ show_key = true;
+ if (k->get_keycode() == Key::NONE && k->get_physical_keycode() == Key::NONE && k->get_key_label() != Key::NONE) {
+ key_mode->select(KEYMODE_UNICODE);
+ } else if (k->get_keycode() != Key::NONE) {
+ key_mode->select(KEYMODE_KEYCODE);
+ } else if (k->get_physical_keycode() != Key::NONE) {
+ key_mode->select(KEYMODE_PHY_KEYCODE);
+ } else {
+ // Invalid key.
+ event = Ref<InputEvent>();
+ original_event = Ref<InputEvent>();
+ event_listener->clear_event();
+ event_as_text->set_text(TTR("No Event Configured"));
+
+ additional_options_container->hide();
+ input_list_tree->deselect_all();
+ _update_input_list();
+ return;
+ }
} else if (joyb.is_valid() || joym.is_valid() || mb.is_valid()) {
show_device = true;
_set_current_device(event->get_device());
@@ -84,11 +101,20 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, b
mod_container->set_visible(show_mods);
device_container->set_visible(show_device);
- physical_key_checkbox->set_visible(show_phys_key);
+ key_mode->set_visible(show_key);
additional_options_container->show();
+ // Update mode selector based on original key event.
+ Ref<InputEventKey> ko = p_original_event;
+ if (ko.is_valid()) {
+ key_mode->set_item_disabled(KEYMODE_KEYCODE, ko->get_keycode() == Key::NONE);
+ key_mode->set_item_disabled(KEYMODE_PHY_KEYCODE, ko->get_physical_keycode() == Key::NONE);
+ key_mode->set_item_disabled(KEYMODE_UNICODE, ko->get_key_label() == Key::NONE);
+ }
+
// Update selected item in input list.
if (p_update_input_list_selection && (k.is_valid() || joyb.is_valid() || joym.is_valid() || mb.is_valid())) {
+ in_tree_update = true;
TreeItem *category = input_list_tree->get_root()->get_first_child();
while (category) {
TreeItem *input_item = category->get_first_child();
@@ -97,6 +123,7 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, b
// input_type should always be > 0, unless the tree structure has been misconfigured.
int input_type = input_item->get_parent()->get_meta("__type", 0);
if (input_type == 0) {
+ in_tree_update = false;
return;
}
@@ -112,6 +139,7 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, b
category->set_collapsed(false);
input_item->select(0);
input_list_tree->ensure_cursor_is_visible();
+ in_tree_update = false;
return;
}
input_item = input_item->get_next();
@@ -122,10 +150,12 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, b
category->set_collapsed(true); // Event not in this category, so collapse;
category = category->get_next();
}
+ in_tree_update = false;
}
} else {
// Event is not valid, reset dialog
- event = p_event;
+ event = Ref<InputEvent>();
+ original_event = Ref<InputEvent>();
event_listener->clear_event();
event_as_text->set_text(TTR("No Event Configured"));
@@ -141,8 +171,10 @@ void InputEventConfigurationDialog::_on_listen_input_changed(const Ref<InputEven
return;
}
- // Create an editable reference
+ // Create an editable reference and a copy of full event.
Ref<InputEvent> received_event = p_event;
+ Ref<InputEvent> received_original_event = received_event->duplicate();
+
// Check what the type is and if it is allowed.
Ref<InputEventKey> k = received_event;
Ref<InputEventJoypadButton> joyb = received_event;
@@ -170,11 +202,15 @@ void InputEventConfigurationDialog::_on_listen_input_changed(const Ref<InputEven
if (k.is_valid()) {
k->set_pressed(false); // To avoid serialisation of 'pressed' property - doesn't matter for actions anyway.
- // Maintain physical keycode option state
- if (physical_key_checkbox->is_pressed()) {
+ if (key_mode->get_selected_id() == KEYMODE_KEYCODE) {
+ k->set_physical_keycode(Key::NONE);
+ k->set_key_label(Key::NONE);
+ } else if (key_mode->get_selected_id() == KEYMODE_PHY_KEYCODE) {
k->set_keycode(Key::NONE);
- } else {
+ k->set_key_label(Key::NONE);
+ } else if (key_mode->get_selected_id() == KEYMODE_UNICODE) {
k->set_physical_keycode(Key::NONE);
+ k->set_keycode(Key::NONE);
}
}
@@ -186,7 +222,7 @@ void InputEventConfigurationDialog::_on_listen_input_changed(const Ref<InputEven
// Maintain device selection.
received_event->set_device(_get_current_device());
- _set_event(received_event);
+ _set_event(received_event, received_original_event);
}
void InputEventConfigurationDialog::_on_listen_focus_changed() {
@@ -326,14 +362,14 @@ void InputEventConfigurationDialog::_mod_toggled(bool p_checked, int p_index) {
}
}
- _set_event(ie);
+ _set_event(ie, original_event);
}
void InputEventConfigurationDialog::_autoremap_command_or_control_toggled(bool p_checked) {
Ref<InputEventWithModifiers> ie = event;
if (ie.is_valid()) {
ie->set_command_or_control_autoremap(p_checked);
- _set_event(ie);
+ _set_event(ie, original_event);
}
if (p_checked) {
@@ -345,27 +381,38 @@ void InputEventConfigurationDialog::_autoremap_command_or_control_toggled(bool p
}
}
-void InputEventConfigurationDialog::_physical_keycode_toggled(bool p_checked) {
+void InputEventConfigurationDialog::_key_mode_selected(int p_mode) {
Ref<InputEventKey> k = event;
-
- if (k.is_null()) {
+ Ref<InputEventKey> ko = original_event;
+ if (k.is_null() || ko.is_null()) {
return;
}
- if (p_checked) {
- k->set_physical_keycode(k->get_keycode());
+ if (key_mode->get_selected_id() == KEYMODE_KEYCODE) {
+ k->set_keycode(ko->get_keycode());
+ k->set_physical_keycode(Key::NONE);
+ k->set_key_label(Key::NONE);
+ } else if (key_mode->get_selected_id() == KEYMODE_PHY_KEYCODE) {
k->set_keycode(Key::NONE);
- } else {
- k->set_keycode((Key)k->get_physical_keycode());
+ k->set_physical_keycode(ko->get_physical_keycode());
+ k->set_key_label(Key::NONE);
+ } else if (key_mode->get_selected_id() == KEYMODE_UNICODE) {
k->set_physical_keycode(Key::NONE);
+ k->set_keycode(Key::NONE);
+ k->set_key_label(ko->get_key_label());
}
- _set_event(k);
+ _set_event(k, original_event);
}
void InputEventConfigurationDialog::_input_list_item_selected() {
TreeItem *selected = input_list_tree->get_selected();
+ // Called form _set_event, do not update for a second time.
+ if (in_tree_update) {
+ return;
+ }
+
// Invalid tree selection - type only exists on the "category" items, which are not a valid selection.
if (selected->has_meta("__type")) {
return;
@@ -379,15 +426,11 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
Ref<InputEventKey> k;
k.instantiate();
- if (physical_key_checkbox->is_pressed()) {
- k->set_physical_keycode(keycode);
- k->set_keycode(Key::NONE);
- } else {
- k->set_physical_keycode(Key::NONE);
- k->set_keycode(keycode);
- }
+ k->set_physical_keycode(keycode);
+ k->set_keycode(keycode);
+ k->set_key_label(keycode);
- // Maintain modifier state from checkboxes
+ // Maintain modifier state from checkboxes.
k->set_alt_pressed(mod_checkboxes[MOD_ALT]->is_pressed());
k->set_shift_pressed(mod_checkboxes[MOD_SHIFT]->is_pressed());
if (autoremap_command_or_control_checkbox->is_pressed()) {
@@ -397,7 +440,23 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
k->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
}
- _set_event(k, false);
+ Ref<InputEventKey> ko = k->duplicate();
+
+ if (key_mode->get_selected_id() == KEYMODE_UNICODE) {
+ key_mode->select(KEYMODE_PHY_KEYCODE);
+ }
+
+ if (key_mode->get_selected_id() == KEYMODE_KEYCODE) {
+ k->set_physical_keycode(Key::NONE);
+ k->set_keycode(keycode);
+ k->set_key_label(Key::NONE);
+ } else if (key_mode->get_selected_id() == KEYMODE_PHY_KEYCODE) {
+ k->set_physical_keycode(keycode);
+ k->set_keycode(Key::NONE);
+ k->set_key_label(Key::NONE);
+ }
+
+ _set_event(k, ko, false);
} break;
case INPUT_MOUSE_BUTTON: {
MouseButton idx = (MouseButton)(int)selected->get_meta("__index");
@@ -417,7 +476,7 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
// Maintain selected device
mb->set_device(_get_current_device());
- _set_event(mb, false);
+ _set_event(mb, mb, false);
} break;
case INPUT_JOY_BUTTON: {
JoyButton idx = (JoyButton)(int)selected->get_meta("__index");
@@ -426,7 +485,7 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
// Maintain selected device
jb->set_device(_get_current_device());
- _set_event(jb, false);
+ _set_event(jb, jb, false);
} break;
case INPUT_JOY_MOTION: {
JoyAxis axis = (JoyAxis)(int)selected->get_meta("__axis");
@@ -440,7 +499,7 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
// Maintain selected device
jm->set_device(_get_current_device());
- _set_event(jm, false);
+ _set_event(jm, jm, false);
} break;
}
}
@@ -470,7 +529,9 @@ void InputEventConfigurationDialog::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
input_list_search->set_right_icon(input_list_search->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- physical_key_checkbox->set_icon(get_theme_icon(SNAME("KeyboardPhysical"), SNAME("EditorIcons")));
+ key_mode->set_item_icon(KEYMODE_KEYCODE, get_theme_icon(SNAME("Keyboard"), SNAME("EditorIcons")));
+ key_mode->set_item_icon(KEYMODE_PHY_KEYCODE, get_theme_icon(SNAME("KeyboardPhysical"), SNAME("EditorIcons")));
+ key_mode->set_item_icon(KEYMODE_UNICODE, get_theme_icon(SNAME("KeyboardLabel"), SNAME("EditorIcons")));
icon_cache.keyboard = get_theme_icon(SNAME("Keyboard"), SNAME("EditorIcons"));
icon_cache.mouse = get_theme_icon(SNAME("Mouse"), SNAME("EditorIcons"));
@@ -484,22 +545,22 @@ void InputEventConfigurationDialog::_notification(int p_what) {
void InputEventConfigurationDialog::popup_and_configure(const Ref<InputEvent> &p_event) {
if (p_event.is_valid()) {
- _set_event(p_event);
+ _set_event(p_event, p_event->duplicate());
} else {
// Clear Event
- _set_event(p_event);
+ _set_event(Ref<InputEvent>(), Ref<InputEvent>());
// Clear Checkbox Values
for (int i = 0; i < MOD_MAX; i++) {
mod_checkboxes[i]->set_pressed(false);
}
- // Enable the Physical Key checkbox by default to encourage its use.
+ // Enable the Physical Key by default to encourage its use.
// Physical Key should be used for most game inputs as it allows keys to work
// on non-QWERTY layouts out of the box.
// This is especially important for WASD movement layouts.
- physical_key_checkbox->set_pressed(true);
+ key_mode->select(KEYMODE_PHY_KEYCODE);
autoremap_command_or_control_checkbox->set_pressed(false);
// Select "All Devices" by default.
@@ -621,14 +682,15 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
mod_container->hide();
additional_options_container->add_child(mod_container);
- // Physical Key Checkbox
+ // Key Mode Selection
- physical_key_checkbox = memnew(CheckBox);
- physical_key_checkbox->set_text(TTR("Use Physical Keycode"));
- physical_key_checkbox->set_tooltip_text(TTR("Stores the physical position of the key on the keyboard rather than the key's value. Used for compatibility with non-latin layouts.\nThis should generally be enabled for most game shortcuts, but not in non-game applications."));
- physical_key_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_physical_keycode_toggled));
- physical_key_checkbox->hide();
- additional_options_container->add_child(physical_key_checkbox);
+ key_mode = memnew(OptionButton);
+ key_mode->add_item("Keycode (Latin equvialent)", KEYMODE_KEYCODE);
+ key_mode->add_item("Physical Keycode (poistion of US QWERTY keyboard)", KEYMODE_PHY_KEYCODE);
+ key_mode->add_item("Unicode (case-insencetive)", KEYMODE_UNICODE);
+ key_mode->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_key_mode_selected));
+ key_mode->hide();
+ additional_options_container->add_child(key_mode);
main_vbox->add_child(additional_options_container);
}
diff --git a/editor/input_event_configuration_dialog.h b/editor/input_event_configuration_dialog.h
index 67906233dd..e7ab0da4d6 100644
--- a/editor/input_event_configuration_dialog.h
+++ b/editor/input_event_configuration_dialog.h
@@ -50,7 +50,10 @@ private:
Ref<Texture2D> joypad_axis;
} icon_cache;
- Ref<InputEvent> event = Ref<InputEvent>();
+ Ref<InputEvent> event;
+ Ref<InputEvent> original_event;
+
+ bool in_tree_update = false;
// Listening for input
EventListenerLineEdit *event_listener = nullptr;
@@ -88,9 +91,15 @@ private:
CheckBox *mod_checkboxes[MOD_MAX];
CheckBox *autoremap_command_or_control_checkbox = nullptr;
- CheckBox *physical_key_checkbox = nullptr;
+ enum KeyMode {
+ KEYMODE_KEYCODE,
+ KEYMODE_PHY_KEYCODE,
+ KEYMODE_UNICODE,
+ };
+
+ OptionButton *key_mode = nullptr;
- void _set_event(const Ref<InputEvent> &p_event, bool p_update_input_list_selection = true);
+ void _set_event(const Ref<InputEvent> &p_event, const Ref<InputEvent> &p_original_event, bool p_update_input_list_selection = true);
void _on_listen_input_changed(const Ref<InputEvent> &p_event);
void _on_listen_focus_changed();
@@ -100,7 +109,7 @@ private:
void _mod_toggled(bool p_checked, int p_index);
void _autoremap_command_or_control_toggled(bool p_checked);
- void _physical_keycode_toggled(bool p_checked);
+ void _key_mode_selected(int p_mode);
void _device_selection_changed(int p_option_button_index);
void _set_current_device(int p_device);
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index b28373e308..52482ecb16 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -189,8 +189,7 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) {
int history_id = EditorUndoRedoManager::get_singleton()->get_history_for_object(current).id;
EditorUndoRedoManager::get_singleton()->clear_history(true, history_id);
- EditorNode::get_singleton()->get_editor_plugins_over()->edit(nullptr);
- EditorNode::get_singleton()->get_editor_plugins_over()->edit(current);
+ EditorNode::get_singleton()->edit_item(current, inspector);
}
} break;
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index 4f6487fa77..97398b8b69 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -92,7 +92,7 @@ void PluginConfigDialog::_on_confirmed() {
_clear_fields();
}
-void PluginConfigDialog::_on_cancelled() {
+void PluginConfigDialog::_on_canceled() {
_clear_fields();
}
@@ -162,7 +162,7 @@ void PluginConfigDialog::_notification(int p_what) {
case NOTIFICATION_READY: {
connect("confirmed", callable_mp(this, &PluginConfigDialog::_on_confirmed));
- get_cancel_button()->connect("pressed", callable_mp(this, &PluginConfigDialog::_on_cancelled));
+ get_cancel_button()->connect("pressed", callable_mp(this, &PluginConfigDialog::_on_canceled));
} break;
}
}
diff --git a/editor/plugin_config_dialog.h b/editor/plugin_config_dialog.h
index e8df308c54..50b901a39e 100644
--- a/editor/plugin_config_dialog.h
+++ b/editor/plugin_config_dialog.h
@@ -58,7 +58,7 @@ class PluginConfigDialog : public ConfirmationDialog {
void _clear_fields();
void _on_confirmed();
- void _on_cancelled();
+ void _on_canceled();
void _on_language_changed(const int p_language);
void _on_required_text_changed(const String &p_text);
String _get_subfolder();
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index a675495429..c0972d201e 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -1237,7 +1237,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
if (playback.is_valid()) {
playing = playback->is_playing();
current = playback->get_current_node();
- blend_from = playback->get_blend_from_node();
+ blend_from = playback->get_fading_from_node();
travel_path = playback->get_travel_path();
}
@@ -1695,7 +1695,7 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
tp = playback->get_travel_path();
is_playing = playback->is_playing();
current_node = playback->get_current_node();
- blend_from_node = playback->get_blend_from_node();
+ blend_from_node = playback->get_fading_from_node();
play_pos = playback->get_current_play_pos();
current_length = playback->get_current_length();
}
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index eab5eb0404..2639765283 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -107,7 +107,7 @@ void EditorAssetLibraryItem::_bind_methods() {
EditorAssetLibraryItem::EditorAssetLibraryItem() {
Ref<StyleBoxEmpty> border;
border.instantiate();
- border->set_default_margin_all(5 * EDSCALE);
+ border->set_content_margin_all(5 * EDSCALE);
add_theme_style_override("panel", border);
HBoxContainer *hb = memnew(HBoxContainer);
@@ -1549,7 +1549,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
Ref<StyleBoxEmpty> border2;
border2.instantiate();
- border2->set_default_margin_individual(15 * EDSCALE, 15 * EDSCALE, 35 * EDSCALE, 15 * EDSCALE);
+ border2->set_content_margin_individual(15 * EDSCALE, 15 * EDSCALE, 35 * EDSCALE, 15 * EDSCALE);
PanelContainer *library_vb_border = memnew(PanelContainer);
library_scroll->add_child(library_vb_border);
diff --git a/editor/plugins/bit_map_editor_plugin.cpp b/editor/plugins/bit_map_editor_plugin.cpp
index 4f82aaf071..30fc60b0e0 100644
--- a/editor/plugins/bit_map_editor_plugin.cpp
+++ b/editor/plugins/bit_map_editor_plugin.cpp
@@ -53,7 +53,7 @@ BitMapEditor::BitMapEditor() {
// Reduce extra padding on top and bottom of size label.
Ref<StyleBoxEmpty> stylebox;
stylebox.instantiate();
- stylebox->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
+ stylebox->set_content_margin(SIDE_RIGHT, 4 * EDSCALE);
size_label->add_theme_style_override("normal", stylebox);
}
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 4c14755b03..5d0555a10e 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -246,7 +246,7 @@ public:
}
};
-bool CanvasItemEditor::_is_node_locked(const Node *p_node) {
+bool CanvasItemEditor::_is_node_locked(const Node *p_node) const {
return p_node->get_meta("_edit_lock_", false);
}
@@ -770,7 +770,7 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po
return still_selected;
}
-List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retrieve_locked, bool remove_canvas_item_if_parent_in_selection) {
+List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retrieve_locked, bool remove_canvas_item_if_parent_in_selection) const {
List<CanvasItem *> selection;
for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
@@ -1226,7 +1226,6 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
bool panner_active = panner->gui_input(p_event, warped_panning ? viewport->get_global_rect() : Rect2());
if (panner->is_panning() != pan_pressed) {
pan_pressed = panner->is_panning();
- _update_cursor();
}
if (panner_active) {
@@ -2570,8 +2569,10 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
// Handles the mouse hovering
_gui_input_hover(p_event);
- // Change the cursor
- _update_cursor();
+ if (mb.is_valid()) {
+ // Update the default cursor.
+ _update_cursor();
+ }
// Grab focus
if (!viewport->has_focus() && (!get_viewport()->gui_get_focus_owner() || !get_viewport()->gui_get_focus_owner()->is_text_field())) {
@@ -2580,6 +2581,31 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
}
void CanvasItemEditor::_update_cursor() {
+ // Choose the correct default cursor.
+ CursorShape c = CURSOR_ARROW;
+ switch (tool) {
+ case TOOL_MOVE:
+ c = CURSOR_MOVE;
+ break;
+ case TOOL_EDIT_PIVOT:
+ c = CURSOR_CROSS;
+ break;
+ case TOOL_PAN:
+ c = CURSOR_DRAG;
+ break;
+ case TOOL_RULER:
+ c = CURSOR_CROSS;
+ break;
+ default:
+ break;
+ }
+ if (pan_pressed) {
+ c = CURSOR_DRAG;
+ }
+ set_default_cursor_shape(c);
+}
+
+Control::CursorShape CanvasItemEditor::get_cursor_shape(const Point2 &p_pos) const {
// Compute an eventual rotation of the cursor
const CursorShape rotation_array[4] = { CURSOR_HSIZE, CURSOR_BDIAGSIZE, CURSOR_VSIZE, CURSOR_FDIAGSIZE };
int rotation_array_index = 0;
@@ -2601,26 +2627,8 @@ void CanvasItemEditor::_update_cursor() {
}
// Choose the correct cursor
- CursorShape c = CURSOR_ARROW;
+ CursorShape c = get_default_cursor_shape();
switch (drag_type) {
- case DRAG_NONE:
- switch (tool) {
- case TOOL_MOVE:
- c = CURSOR_MOVE;
- break;
- case TOOL_EDIT_PIVOT:
- c = CURSOR_CROSS;
- break;
- case TOOL_PAN:
- c = CURSOR_DRAG;
- break;
- case TOOL_RULER:
- c = CURSOR_CROSS;
- break;
- default:
- break;
- }
- break;
case DRAG_LEFT:
case DRAG_RIGHT:
c = rotation_array[rotation_array_index];
@@ -2662,16 +2670,7 @@ void CanvasItemEditor::_update_cursor() {
if (pan_pressed) {
c = CURSOR_DRAG;
}
-
- if (c != viewport->get_default_cursor_shape()) {
- viewport->set_default_cursor_shape(c);
-
- // Force refresh cursor if it's over the viewport.
- if (viewport->get_global_rect().has_point(get_global_mouse_position())) {
- DisplayServer::CursorShape ds_cursor_shape = (DisplayServer::CursorShape)viewport->get_default_cursor_shape();
- DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape);
- }
- }
+ return c;
}
void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string, Side p_side) {
@@ -3958,8 +3957,8 @@ void CanvasItemEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
select_sb->set_texture(get_theme_icon(SNAME("EditorRect2D"), SNAME("EditorIcons")));
- select_sb->set_margin_size_all(4);
- select_sb->set_default_margin_all(4);
+ select_sb->set_texture_margin_all(4);
+ select_sb->set_content_margin_all(4);
AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
_keying_changed();
@@ -3990,6 +3989,10 @@ void CanvasItemEditor::_selection_changed() {
}
void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
+ if (!p_canvas_item) {
+ return;
+ }
+
Array selection = editor_selection->get_selected_nodes();
if (selection.size() != 1 || Object::cast_to<Node>(selection[0]) != p_canvas_item) {
_reset_drag();
@@ -5925,7 +5928,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it
EditorNode::get_singleton()->get_gui_base()->add_child(selector);
selector->set_title(TTR("Change Default Type"));
selector->connect("confirmed", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_confirmed));
- selector->connect("cancelled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
+ selector->connect("canceled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
VBoxContainer *vbc = memnew(VBoxContainer);
selector->add_child(vbc);
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index f4fcc8a3d2..1e01eac82d 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -368,7 +368,7 @@ private:
void _pan_callback(Vector2 p_scroll_vec);
void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
- bool _is_node_locked(const Node *p_node);
+ bool _is_node_locked(const Node *p_node) const;
bool _is_node_movable(const Node *p_node, bool p_popup_warning = false);
void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, bool p_allow_locked = false);
@@ -402,7 +402,7 @@ private:
void _prepare_grid_menu();
void _on_grid_menu_id_pressed(int p_id);
- List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true);
+ List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true) const;
Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list);
void _expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true);
Rect2 _get_encompassing_rect(const Node *p_node);
@@ -552,6 +552,8 @@ public:
void focus_selection();
void center_at(const Point2 &p_pos);
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
+
EditorSelection *editor_selection = nullptr;
CanvasItemEditor();
diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp
index 3676c2c222..2eb17b3f13 100644
--- a/editor/plugins/gradient_editor.cpp
+++ b/editor/plugins/gradient_editor.cpp
@@ -52,12 +52,12 @@ void GradientEditor::reverse_gradient() {
int GradientEditor::_get_point_from_pos(int x) {
int result = -1;
- int total_w = get_size().width - get_size().height - draw_spacing;
+ int total_w = get_size().width - get_size().height - draw_spacing - handle_width;
float min_distance = 1e20;
for (int i = 0; i < points.size(); i++) {
// Check if we clicked at point.
float distance = ABS(x - points[i].offset * total_w);
- float min = (handle_width / 2 * 1.7); // Make it easier to grab.
+ float min = handle_width * 0.85; // Allow the mouse to be more than half a handle width away for ease of grabbing.
if (distance <= min && distance < min_distance) {
result = i;
min_distance = distance;
@@ -198,116 +198,87 @@ void GradientEditor::gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mb = p_event;
- // Show color picker on double click.
- if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_double_click() && mb->is_pressed()) {
- grabbed = _get_point_from_pos(mb->get_position().x);
- _show_color_picker();
- accept_event();
- return;
- }
-
- // Delete point on right click.
- if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
- grabbed = _get_point_from_pos(mb->get_position().x);
- if (grabbed != -1) {
- points.remove_at(grabbed);
- grabbed = -1;
- grabbing = false;
- queue_redraw();
- emit_signal(SNAME("ramp_changed"));
- accept_event();
- }
- }
-
- // Hold alt key to duplicate selected color.
- if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed() && mb->is_alt_pressed()) {
- int x = mb->get_position().x;
- grabbed = _get_point_from_pos(x);
- if (grabbed != -1) {
- int total_w = get_size().width - get_size().height - draw_spacing;
- Gradient::Point new_point = points[grabbed];
- new_point.offset = CLAMP(x / float(total_w), 0, 1);
+ if (mb.is_valid() && mb->is_pressed()) {
+ float adjusted_mb_x = mb->get_position().x - handle_width / 2;
- points.push_back(new_point);
- points.sort();
- for (int i = 0; i < points.size(); ++i) {
- if (points[i].offset == new_point.offset) {
- grabbed = i;
- break;
- }
+ // Delete point on right click.
+ if (mb->get_button_index() == MouseButton::RIGHT) {
+ grabbed = _get_point_from_pos(adjusted_mb_x);
+ if (grabbed != -1) {
+ points.remove_at(grabbed);
+ grabbed = -1;
+ grabbing = false;
+ queue_redraw();
+ emit_signal(SNAME("ramp_changed"));
+ accept_event();
}
-
- emit_signal(SNAME("ramp_changed"));
- queue_redraw();
}
- }
- // Select.
- if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
- queue_redraw();
- int x = mb->get_position().x;
- int total_w = get_size().width - get_size().height - draw_spacing;
+ // Hold Alt key to duplicate selected color.
+ if (mb->get_button_index() == MouseButton::LEFT && mb->is_alt_pressed()) {
+ grabbed = _get_point_from_pos(adjusted_mb_x);
- //Check if color selector was clicked.
- if (x > total_w + draw_spacing) {
- _show_color_picker();
- return;
- }
-
- grabbing = true;
+ if (grabbed != -1) {
+ int total_w = get_size().width - get_size().height - draw_spacing - handle_width;
+ Gradient::Point new_point = points[grabbed];
+ new_point.offset = CLAMP(adjusted_mb_x / float(total_w), 0, 1);
+ points.push_back(new_point);
+ points.sort();
+ for (int i = 0; i < points.size(); ++i) {
+ if (points[i].offset == new_point.offset) {
+ grabbed = i;
+ break;
+ }
+ }
- grabbed = _get_point_from_pos(x);
- //grab or select
- if (grabbed != -1) {
- return;
+ emit_signal(SNAME("ramp_changed"));
+ queue_redraw();
+ }
}
- // Insert point.
- Gradient::Point new_point;
- new_point.offset = CLAMP(x / float(total_w), 0, 1);
-
- Gradient::Point prev;
- Gradient::Point next;
+ // Select.
+ if (mb->get_button_index() == MouseButton::LEFT) {
+ queue_redraw();
+ int total_w = get_size().width - get_size().height - draw_spacing - handle_width;
- int pos = -1;
- for (int i = 0; i < points.size(); i++) {
- if (points[i].offset < new_point.offset) {
- pos = i;
+ // Check if color selector was clicked or ramp was double-clicked.
+ if (adjusted_mb_x > total_w + draw_spacing) {
+ if (!mb->is_double_click()) {
+ _show_color_picker();
+ }
+ return;
+ } else if (mb->is_double_click()) {
+ grabbed = _get_point_from_pos(adjusted_mb_x);
+ _show_color_picker();
+ accept_event();
+ return;
}
- }
- if (pos == -1) {
- prev.color = Color(0, 0, 0);
- prev.offset = 0;
- if (points.size()) {
- next = points[0];
- } else {
- next.color = Color(1, 1, 1);
- next.offset = 1.0;
- }
- } else {
- if (pos == points.size() - 1) {
- next.color = Color(1, 1, 1);
- next.offset = 1.0;
- } else {
- next = points[pos + 1];
+ grabbing = true;
+ grabbed = _get_point_from_pos(adjusted_mb_x);
+
+ // Grab or select.
+ if (grabbed != -1) {
+ return;
}
- prev = points[pos];
- }
- new_point.color = prev.color.lerp(next.color, (new_point.offset - prev.offset) / (next.offset - prev.offset));
+ // Insert point.
+ Gradient::Point new_point;
+ new_point.offset = CLAMP(adjusted_mb_x / float(total_w), 0, 1);
+ new_point.color = gradient->get_color_at_offset(new_point.offset);
- points.push_back(new_point);
- points.sort();
- for (int i = 0; i < points.size(); i++) {
- if (points[i].offset == new_point.offset) {
- grabbed = i;
- break;
+ points.push_back(new_point);
+ points.sort();
+ for (int i = 0; i < points.size(); i++) {
+ if (points[i].offset == new_point.offset) {
+ grabbed = i;
+ break;
+ }
}
- }
- emit_signal(SNAME("ramp_changed"));
+ emit_signal(SNAME("ramp_changed"));
+ }
}
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) {
@@ -321,18 +292,16 @@ void GradientEditor::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && grabbing) {
- int total_w = get_size().width - get_size().height - draw_spacing;
-
- int x = mm->get_position().x;
-
- float newofs = CLAMP(x / float(total_w), 0, 1);
+ float adjusted_mm_x = mm->get_position().x - handle_width / 2;
+ int total_w = get_size().width - get_size().height - draw_spacing - handle_width;
+ float newofs = CLAMP(adjusted_mm_x / float(total_w), 0, 1);
// Snap to "round" coordinates if holding Ctrl.
// Be more precise if holding Shift as well.
if (mm->is_ctrl_pressed()) {
newofs = Math::snapped(newofs, mm->is_shift_pressed() ? 0.025 : 0.1);
} else if (mm->is_shift_pressed()) {
- // Snap to nearest point if holding just Shift
+ // Snap to nearest point if holding just Shift.
const float snap_threshold = 0.03;
float smallest_ofs = snap_threshold;
bool found = false;
@@ -421,7 +390,7 @@ void GradientEditor::_notification(int p_what) {
// Draw borders around color ramp if in focus.
if (has_focus()) {
- draw_rect(Rect2(handle_width / 2, 0, total_w, h), Color(1, 1, 1, 0.9), false);
+ draw_rect(Rect2(handle_width / 2, 0, total_w, h), Color(1, 1, 1, 0.9), false, 1);
}
// Draw point markers.
@@ -432,18 +401,18 @@ void GradientEditor::_notification(int p_what) {
draw_line(Vector2(points[i].offset * total_w + handle_width / 2, 0), Vector2(points[i].offset * total_w + handle_width / 2, h / 2), col);
Rect2 rect = Rect2(points[i].offset * total_w, h / 2, handle_width, h / 2);
draw_rect(rect, points[i].color, true);
- draw_rect(rect, col, false);
+ draw_rect(rect, col, false, 1);
if (grabbed == i) {
const Color focus_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
rect = rect.grow(-1);
if (has_focus()) {
- draw_rect(rect, focus_color, false);
+ draw_rect(rect, focus_color, false, 1);
} else {
- draw_rect(rect, focus_color.darkened(0.4), false);
+ draw_rect(rect, focus_color.darkened(0.4), false, 1);
}
rect = rect.grow(-1);
- draw_rect(rect, col, false);
+ draw_rect(rect, col, false, 1);
}
}
@@ -454,7 +423,7 @@ void GradientEditor::_notification(int p_what) {
// Draw with selection color.
draw_rect(Rect2(button_offset, 0, h, h), points[grabbed].color);
} else {
- // If no color selected draw grey color with 'X' on top.
+ // If no color selected draw gray color with 'X' on top.
draw_rect(Rect2(button_offset, 0, h, h), Color(0.5, 0.5, 0.5, 1));
draw_line(Vector2(button_offset, 0), Vector2(button_offset + h, h), Color(1, 1, 1, 0.6));
draw_line(Vector2(button_offset, h), Vector2(button_offset + h, 0), Color(1, 1, 1, 0.6));
diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp
index 1adcc2a3b4..519cfcaa94 100644
--- a/editor/plugins/lightmap_gi_editor_plugin.cpp
+++ b/editor/plugins/lightmap_gi_editor_plugin.cpp
@@ -35,12 +35,43 @@
void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
if (lightmap) {
- LightmapGI::BakeError err;
+ LightmapGI::BakeError err = LightmapGI::BAKE_ERROR_OK;
const uint64_t time_started = OS::get_singleton()->get_ticks_msec();
- if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) {
- err = lightmap->bake(lightmap, p_file, bake_func_step);
+ if (get_tree()->get_edited_scene_root()) {
+ Ref<LightmapGIData> lightmapGIData = lightmap->get_light_data();
+
+ if (lightmapGIData.is_valid()) {
+ String path = lightmapGIData->get_path();
+ if (!path.is_resource_file()) {
+ int srpos = path.find("::");
+ if (srpos != -1) {
+ String base = path.substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ err = LightmapGI::BAKE_ERROR_FOREIGN_DATA;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ err = LightmapGI::BAKE_ERROR_FOREIGN_DATA;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(path + ".import")) {
+ err = LightmapGI::BAKE_ERROR_FOREIGN_DATA;
+ }
+ }
+ }
+
+ if (err == LightmapGI::BAKE_ERROR_OK) {
+ if (get_tree()->get_edited_scene_root() == lightmap) {
+ err = lightmap->bake(lightmap, p_file, bake_func_step);
+ } else {
+ err = lightmap->bake(lightmap->get_parent(), p_file, bake_func_step);
+ }
+ }
} else {
- err = lightmap->bake(lightmap->get_parent(), p_file, bake_func_step);
+ err = LightmapGI::BAKE_ERROR_NO_SCENE_ROOT;
}
bake_func_end(time_started);
@@ -59,16 +90,21 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
file_dialog->set_current_path(scene_path);
file_dialog->popup_file_dialog();
-
} break;
- case LightmapGI::BAKE_ERROR_NO_MESHES:
+ case LightmapGI::BAKE_ERROR_NO_MESHES: {
EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake Light' flag is on."));
- break;
- case LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE:
+ } break;
+ case LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE: {
EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable."));
- break;
+ } break;
+ case LightmapGI::BAKE_ERROR_NO_SCENE_ROOT: {
+ EditorNode::get_singleton()->show_warning(TTR("No editor scene root found."));
+ } break;
+ case LightmapGI::BAKE_ERROR_FOREIGN_DATA: {
+ EditorNode::get_singleton()->show_warning(TTR("Lightmap data is not local to the scene."));
+ } break;
default: {
- }
+ } break;
}
}
}
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 05fc464226..c30f0ec62d 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -1254,7 +1254,7 @@ Polygon2DEditor::Polygon2DEditor() {
uv_edit = memnew(AcceptDialog);
add_child(uv_edit);
uv_edit->set_title(TTR("Polygon 2D UV Editor"));
- uv_edit->connect("cancelled", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide));
+ uv_edit->connect("canceled", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide));
VBoxContainer *uv_main_vb = memnew(VBoxContainer);
uv_edit->add_child(uv_main_vb);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 6bb725f7a0..b719a2ce30 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -2159,7 +2159,7 @@ ScriptTextEditor::ScriptTextEditor() {
connection_info_dialog = memnew(ConnectionInfoDialog);
- SET_DRAG_FORWARDING_GCD(code_editor, ScriptTextEditor);
+ SET_DRAG_FORWARDING_GCD(code_editor->get_text_editor(), ScriptTextEditor);
}
ScriptTextEditor::~ScriptTextEditor() {
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index bc9a33d5d6..907bc81674 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -117,6 +117,10 @@ void ShaderEditorPlugin::_move_shader_tab(int p_from, int p_to) {
}
void ShaderEditorPlugin::edit(Object *p_object) {
+ if (!p_object) {
+ return;
+ }
+
EditedShader es;
ShaderInclude *si = Object::cast_to<ShaderInclude>(p_object);
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 9bad2f2fbf..d7559bc18e 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -256,10 +256,10 @@ void TextureRegionEditor::_region_draw() {
margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT);
margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT);
} else if (obj_styleBox.is_valid()) {
- margins[0] = obj_styleBox->get_margin_size(SIDE_TOP);
- margins[1] = obj_styleBox->get_margin_size(SIDE_BOTTOM);
- margins[2] = obj_styleBox->get_margin_size(SIDE_LEFT);
- margins[3] = obj_styleBox->get_margin_size(SIDE_RIGHT);
+ margins[0] = obj_styleBox->get_texture_margin(SIDE_TOP);
+ margins[1] = obj_styleBox->get_texture_margin(SIDE_BOTTOM);
+ margins[2] = obj_styleBox->get_texture_margin(SIDE_LEFT);
+ margins[3] = obj_styleBox->get_texture_margin(SIDE_RIGHT);
}
Vector2 pos[4] = {
@@ -314,10 +314,10 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT);
margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT);
} else if (obj_styleBox.is_valid()) {
- margins[0] = obj_styleBox->get_margin_size(SIDE_TOP);
- margins[1] = obj_styleBox->get_margin_size(SIDE_BOTTOM);
- margins[2] = obj_styleBox->get_margin_size(SIDE_LEFT);
- margins[3] = obj_styleBox->get_margin_size(SIDE_RIGHT);
+ margins[0] = obj_styleBox->get_texture_margin(SIDE_TOP);
+ margins[1] = obj_styleBox->get_texture_margin(SIDE_BOTTOM);
+ margins[2] = obj_styleBox->get_texture_margin(SIDE_LEFT);
+ margins[3] = obj_styleBox->get_texture_margin(SIDE_RIGHT);
}
Vector2 pos[4] = {
@@ -431,8 +431,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
undo_redo->add_do_method(node_ninepatch, "set_patch_margin", side[edited_margin], node_ninepatch->get_patch_margin(side[edited_margin]));
undo_redo->add_undo_method(node_ninepatch, "set_patch_margin", side[edited_margin], prev_margin);
} else if (obj_styleBox.is_valid()) {
- undo_redo->add_do_method(obj_styleBox.ptr(), "set_margin_size", side[edited_margin], obj_styleBox->get_margin_size(side[edited_margin]));
- undo_redo->add_undo_method(obj_styleBox.ptr(), "set_margin_size", side[edited_margin], prev_margin);
+ undo_redo->add_do_method(obj_styleBox.ptr(), "set_texture_margin", side[edited_margin], obj_styleBox->get_texture_margin(side[edited_margin]));
+ undo_redo->add_undo_method(obj_styleBox.ptr(), "set_texture_margin", side[edited_margin], prev_margin);
obj_styleBox->emit_signal(CoreStringNames::get_singleton()->changed);
}
edited_margin = -1;
@@ -474,7 +474,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
node_ninepatch->set_patch_margin(side[edited_margin], prev_margin);
}
if (obj_styleBox.is_valid()) {
- obj_styleBox->set_margin_size(side[edited_margin], prev_margin);
+ obj_styleBox->set_texture_margin(side[edited_margin], prev_margin);
}
edited_margin = -1;
} else {
@@ -535,7 +535,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
node_ninepatch->set_patch_margin(side[edited_margin], new_margin);
}
if (obj_styleBox.is_valid()) {
- obj_styleBox->set_margin_size(side[edited_margin], new_margin);
+ obj_styleBox->set_texture_margin(side[edited_margin], new_margin);
}
} else {
Vector2 new_pos = mtx.affine_inverse().xform(mm->get_position());
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 40aac77a99..14ff59b442 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -3335,8 +3335,10 @@ void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) {
}
edited_theme = p_theme;
- edited_theme->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
- _update_type_list();
+ if (edited_theme.is_valid()) {
+ edited_theme->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
+ _update_type_list();
+ }
add_type_dialog->set_edited_theme(edited_theme);
}
@@ -3496,7 +3498,9 @@ void ThemeEditor::edit(const Ref<Theme> &p_theme) {
preview_tab->set_preview_theme(p_theme);
}
- theme_name->set_text(TTR("Theme:") + " " + theme->get_path().get_file());
+ if (theme.is_valid()) {
+ theme_name->set_text(TTR("Theme:") + " " + theme->get_path().get_file());
+ }
}
Ref<Theme> ThemeEditor::get_edited_theme() {
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 96b1ad7ee0..4c5cde926a 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -5186,7 +5186,7 @@ VisualShaderEditor::VisualShaderEditor() {
members_dialog->set_ok_button_text(TTR("Create"));
members_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualShaderEditor::_member_create));
members_dialog->get_ok_button()->set_disabled(true);
- members_dialog->connect("cancelled", callable_mp(this, &VisualShaderEditor::_member_cancel));
+ members_dialog->connect("canceled", callable_mp(this, &VisualShaderEditor::_member_cancel));
add_child(members_dialog);
// add varyings dialog
diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp
index a3ccf392e6..f9f72fee77 100644
--- a/editor/plugins/voxel_gi_editor_plugin.cpp
+++ b/editor/plugins/voxel_gi_editor_plugin.cpp
@@ -35,7 +35,9 @@
void VoxelGIEditorPlugin::_bake() {
if (voxel_gi) {
- if (voxel_gi->get_probe_data().is_null()) {
+ Ref<VoxelGIData> voxel_gi_data = voxel_gi->get_probe_data();
+
+ if (voxel_gi_data.is_null()) {
String path = get_tree()->get_edited_scene_root()->get_scene_file_path();
if (path.is_empty()) {
path = "res://" + voxel_gi->get_name() + "_data.res";
@@ -46,7 +48,32 @@ void VoxelGIEditorPlugin::_bake() {
probe_file->set_current_path(path);
probe_file->popup_file_dialog();
return;
+ } else {
+ String path = voxel_gi_data->get_path();
+ if (!path.is_resource_file()) {
+ int srpos = path.find("::");
+ if (srpos != -1) {
+ String base = path.substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ EditorNode::get_singleton()->show_warning(TTR("Voxel GI data is not local to the scene."));
+ return;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ EditorNode::get_singleton()->show_warning(TTR("Voxel GI data is part of an imported resource."));
+ return;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(path + ".import")) {
+ EditorNode::get_singleton()->show_warning(TTR("Voxel GI data is an imported resource."));
+ return;
+ }
+ }
}
+
voxel_gi->bake();
}
}
diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp
index db11f80826..37f941c7b2 100644
--- a/editor/progress_dialog.cpp
+++ b/editor/progress_dialog.cpp
@@ -195,7 +195,7 @@ void ProgressDialog::add_task(const String &p_task, const String &p_label, int p
cancel_hb->hide();
}
cancel_hb->move_to_front();
- cancelled = false;
+ canceled = false;
_popup();
if (p_can_cancel) {
cancel->grab_focus();
@@ -203,12 +203,12 @@ void ProgressDialog::add_task(const String &p_task, const String &p_label, int p
}
bool ProgressDialog::task_step(const String &p_task, const String &p_state, int p_step, bool p_force_redraw) {
- ERR_FAIL_COND_V(!tasks.has(p_task), cancelled);
+ ERR_FAIL_COND_V(!tasks.has(p_task), canceled);
if (!p_force_redraw) {
uint64_t tus = OS::get_singleton()->get_ticks_usec();
if (tus - last_progress_tick < 200000) { //200ms
- return cancelled;
+ return canceled;
}
}
@@ -228,7 +228,7 @@ bool ProgressDialog::task_step(const String &p_task, const String &p_state, int
#ifndef ANDROID_ENABLED
Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor
#endif
- return cancelled;
+ return canceled;
}
void ProgressDialog::end_task(const String &p_task) {
@@ -246,7 +246,7 @@ void ProgressDialog::end_task(const String &p_task) {
}
void ProgressDialog::_cancel_pressed() {
- cancelled = true;
+ canceled = true;
}
void ProgressDialog::_bind_methods() {
diff --git a/editor/progress_dialog.h b/editor/progress_dialog.h
index 5346f01a9e..7ac4864c9c 100644
--- a/editor/progress_dialog.h
+++ b/editor/progress_dialog.h
@@ -85,7 +85,7 @@ class ProgressDialog : public PopupPanel {
void _popup();
void _cancel_pressed();
- bool cancelled = false;
+ bool canceled = false;
protected:
void _notification(int p_what);
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 5f61d10f9d..727b2c9b4d 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -1285,6 +1285,7 @@ static const char *gdscript_signals_renames[][2] = {
// {"changed","settings_changed"}, // EditorSettings
{ "about_to_show", "about_to_popup" }, // Popup
{ "button_release", "button_released" }, // XRController3D
+ { "cancelled", "canceled" }, // AcceptDialog
{ "network_peer_connected", "peer_connected" }, // MultiplayerAPI
{ "network_peer_disconnected", "peer_disconnected" }, // MultiplayerAPI
{ "network_peer_packet", "peer_packet" }, // MultiplayerAPI
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 733f140a56..5d1a2a49c5 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1428,6 +1428,9 @@ void SceneTreeDock::_script_open_request(const Ref<Script> &p_script) {
void SceneTreeDock::_push_item(Object *p_object) {
EditorNode::get_singleton()->push_item(p_object);
+ if (p_object == nullptr) {
+ EditorNode::get_singleton()->hide_unused_editors(this);
+ }
}
void SceneTreeDock::_handle_select(Node *p_node) {
@@ -2004,13 +2007,13 @@ void SceneTreeDock::_shader_created(Ref<Shader> p_shader) {
void SceneTreeDock::_script_creation_closed() {
script_create_dialog->disconnect("script_created", callable_mp(this, &SceneTreeDock::_script_created));
script_create_dialog->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_script_creation_closed));
- script_create_dialog->disconnect("cancelled", callable_mp(this, &SceneTreeDock::_script_creation_closed));
+ script_create_dialog->disconnect("canceled", callable_mp(this, &SceneTreeDock::_script_creation_closed));
}
void SceneTreeDock::_shader_creation_closed() {
shader_create_dialog->disconnect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created));
shader_create_dialog->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_shader_creation_closed));
- shader_create_dialog->disconnect("cancelled", callable_mp(this, &SceneTreeDock::_shader_creation_closed));
+ shader_create_dialog->disconnect("canceled", callable_mp(this, &SceneTreeDock::_shader_creation_closed));
}
void SceneTreeDock::_toggle_editable_children_from_selection() {
@@ -2061,7 +2064,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
return;
}
- EditorNode::get_singleton()->get_editor_plugins_over()->make_visible(false);
+ EditorNode::get_singleton()->hide_unused_editors(this);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(p_cut ? TTR("Cut Node(s)") : TTR("Remove Node(s)"), UndoRedo::MERGE_DISABLE, remove_list.front()->get());
@@ -3090,7 +3093,7 @@ void SceneTreeDock::attach_script_to_selected(bool p_extend) {
script_create_dialog->connect("script_created", callable_mp(this, &SceneTreeDock::_script_created));
script_create_dialog->connect("confirmed", callable_mp(this, &SceneTreeDock::_script_creation_closed));
- script_create_dialog->connect("cancelled", callable_mp(this, &SceneTreeDock::_script_creation_closed));
+ script_create_dialog->connect("canceled", callable_mp(this, &SceneTreeDock::_script_creation_closed));
script_create_dialog->set_inheritance_base_type("Node");
script_create_dialog->config(inherits, path);
script_create_dialog->popup_centered();
@@ -3132,7 +3135,7 @@ void SceneTreeDock::attach_shader_to_selected(int p_preferred_mode) {
shader_create_dialog->connect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created));
shader_create_dialog->connect("confirmed", callable_mp(this, &SceneTreeDock::_shader_creation_closed));
- shader_create_dialog->connect("cancelled", callable_mp(this, &SceneTreeDock::_shader_creation_closed));
+ shader_create_dialog->connect("canceled", callable_mp(this, &SceneTreeDock::_shader_creation_closed));
shader_create_dialog->config(path, true, true, -1, p_preferred_mode);
shader_create_dialog->popup_centered();
}
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index e0d748c478..e795cc919c 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -677,7 +677,7 @@ bool SceneTreeEditor::_item_matches_all_terms(TreeItem *p_item, PackedStringArra
for (int i = 0; i < p_terms.size(); i++) {
String term = p_terms[i];
- // Recognise special filter.
+ // Recognize special filter.
if (term.contains(":") && !term.get_slicec(':', 0).is_empty()) {
String parameter = term.get_slicec(':', 0);
String argument = term.get_slicec(':', 1);
diff --git a/main/main.cpp b/main/main.cpp
index 69c5af25ca..cfde124b90 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -185,6 +185,7 @@ static bool init_maximized = false;
static bool init_windowed = false;
static bool init_always_on_top = false;
static bool init_use_custom_pos = false;
+static bool init_use_custom_screen = false;
static Vector2 init_custom_pos;
// Debug
@@ -964,6 +965,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (I->next()) {
init_screen = I->next()->get().to_int();
+ init_use_custom_screen = true;
N = I->next()->next();
} else {
@@ -1669,7 +1671,23 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
window_flags |= DisplayServer::WINDOW_FLAG_NO_FOCUS_BIT;
}
window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int());
- init_screen = GLOBAL_GET("display/window/size/initial_screen").operator int();
+ int initial_position_type = GLOBAL_GET("display/window/size/initial_position_type").operator int();
+ if (initial_position_type == 0) {
+ if (!init_use_custom_pos) {
+ init_custom_pos = GLOBAL_GET("display/window/size/initial_position").operator Vector2i();
+ init_use_custom_pos = true;
+ }
+ } else if (initial_position_type == 1) {
+ if (!init_use_custom_screen) {
+ init_screen = DisplayServer::SCREEN_PRIMARY;
+ init_use_custom_screen = true;
+ }
+ } else if (initial_position_type == 2) {
+ if (!init_use_custom_screen) {
+ init_screen = GLOBAL_GET("display/window/size/initial_screen").operator int();
+ init_use_custom_screen = true;
+ }
+ }
}
GLOBAL_DEF("internationalization/locale/include_text_server_data", false);
@@ -2147,7 +2165,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
if (id) {
agile_input_event_flushing = GLOBAL_DEF("input_devices/buffering/agile_event_flushing", false);
- if (bool(GLOBAL_DEF("input_devices/pointing/emulate_touch_from_mouse", false)) &&
+ if (bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_touch_from_mouse", false)) &&
!(editor || project_manager)) {
if (!DisplayServer::get_singleton()->is_touchscreen_available()) {
//only if no touchscreen ui hint, set emulation
@@ -2155,7 +2173,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
}
}
- id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF("input_devices/pointing/emulate_mouse_from_touch", true)));
+ id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true)));
}
MAIN_PRINT("Main: Load Translations and Remaps");
diff --git a/misc/scripts/codespell.sh b/misc/scripts/codespell.sh
index c00d897666..34885016b6 100755
--- a/misc/scripts/codespell.sh
+++ b/misc/scripts/codespell.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-SKIP_LIST="./.git,./bin,./thirdparty,*.gen.*,*.po,*.pot,package-lock.json,./core/string/locales.h,./DONORS.md,./misc/dist/linux/org.godotengine.Godot.desktop,./misc/scripts/codespell.sh"
+SKIP_LIST="./.*,./bin,.platform/web/node_modules,./platform/android/java/lib/src/com,./thirdparty,*.gen.*,*.po,*.pot,*.rc,package-lock.json,./core/string/locales.h,./AUTHORS.md,./COPYRIGHT.txt,./DONORS.md,./misc/dist/linux/org.godotengine.Godot.desktop,./misc/scripts/codespell.sh"
IGNORE_LIST="alo,ba,childs,complies,curvelinear,doubleclick,expct,fave,findn,gird,gud,inout,lod,nd,numer,ois,readded,ro,sav,statics,te,varius,varn,wan"
-codespell -w -q 3 -S "${SKIP_LIST}" -L "${IGNORE_LIST}"
+codespell -w -q 3 -S "${SKIP_LIST}" -L "${IGNORE_LIST}" --builtin "clear,rare,en-GB_to_en-US"
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 6c80fb7665..e19dda090e 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -401,6 +401,16 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->_instruction_args_size = instr_args_max;
function->_ptrcall_args_size = ptrcall_max;
+#ifdef DEBUG_ENABLED
+ function->operator_names = operator_names;
+ function->setter_names = setter_names;
+ function->getter_names = getter_names;
+ function->builtin_methods_names = builtin_methods_names;
+ function->constructors_names = constructors_names;
+ function->utilities_names = utilities_names;
+ function->gds_utilities_names = gds_utilities_names;
+#endif
+
ended = true;
return function;
}
@@ -551,6 +561,9 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va
append(Address());
append(p_target);
append(op_func);
+#ifdef DEBUG_ENABLED
+ add_debug_name(operator_names, get_operation_pos(op_func), Variant::get_operator_name(p_operator));
+#endif
return;
}
@@ -580,6 +593,9 @@ void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, V
append(p_right_operand);
append(p_target);
append(op_func);
+#ifdef DEBUG_ENABLED
+ add_debug_name(operator_names, get_operation_pos(op_func), Variant::get_operator_name(p_operator));
+#endif
return;
}
@@ -765,6 +781,9 @@ void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const S
append(p_target);
append(p_source);
append(setter);
+#ifdef DEBUG_ENABLED
+ add_debug_name(setter_names, get_setter_pos(setter), p_name);
+#endif
return;
}
append_opcode(GDScriptFunction::OPCODE_SET_NAMED);
@@ -780,6 +799,9 @@ void GDScriptByteCodeGenerator::write_get_named(const Address &p_target, const S
append(p_source);
append(p_target);
append(getter);
+#ifdef DEBUG_ENABLED
+ add_debug_name(getter_names, get_getter_pos(getter), p_name);
+#endif
return;
}
append_opcode(GDScriptFunction::OPCODE_GET_NAMED);
@@ -972,14 +994,18 @@ void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const
append(p_function_name);
}
-void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) {
+void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {
append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_GDSCRIPT_UTILITY, 1 + p_arguments.size());
+ GDScriptUtilityFunctions::FunctionPtr gds_function = GDScriptUtilityFunctions::get_function(p_function);
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
append(get_call_target(p_target));
append(p_arguments.size());
- append(p_function);
+ append(gds_function);
+#ifdef DEBUG_ENABLED
+ add_debug_name(gds_utilities_names, get_gds_utility_pos(gds_function), p_function);
+#endif
}
void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {
@@ -1012,6 +1038,9 @@ void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, cons
append(target);
append(p_arguments.size());
append(Variant::get_validated_utility_function(p_function));
+#ifdef DEBUG_ENABLED
+ add_debug_name(utilities_names, get_utility_pos(Variant::get_validated_utility_function(p_function)), p_function);
+#endif
} else {
append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_UTILITY, 1 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
@@ -1074,6 +1103,9 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target,
append(target);
append(p_arguments.size());
append(Variant::get_validated_builtin_method(p_type, p_method));
+#ifdef DEBUG_ENABLED
+ add_debug_name(builtin_methods_names, get_builtin_method_pos(Variant::get_validated_builtin_method(p_type, p_method)), p_method);
+#endif
}
void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) {
@@ -1263,6 +1295,9 @@ void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant
append(get_call_target(p_target));
append(p_arguments.size());
append(Variant::get_validated_constructor(p_type, valid_constructor));
+#ifdef DEBUG_ENABLED
+ add_debug_name(constructors_names, get_constructor_pos(Variant::get_validated_constructor(p_type, valid_constructor)), Variant::get_type_name(p_type));
+#endif
return;
}
}
@@ -1543,28 +1578,6 @@ void GDScriptByteCodeGenerator::write_endwhile() {
current_breaks_to_patch.pop_back();
}
-void GDScriptByteCodeGenerator::start_match() {
- match_continues_to_patch.push_back(List<int>());
-}
-
-void GDScriptByteCodeGenerator::start_match_branch() {
- // Patch continue statements.
- for (const int &E : match_continues_to_patch.back()->get()) {
- patch_jump(E);
- }
- match_continues_to_patch.pop_back();
- // Start a new list for next branch.
- match_continues_to_patch.push_back(List<int>());
-}
-
-void GDScriptByteCodeGenerator::end_match() {
- // Patch continue statements.
- for (const int &E : match_continues_to_patch.back()->get()) {
- patch_jump(E);
- }
- match_continues_to_patch.pop_back();
-}
-
void GDScriptByteCodeGenerator::write_break() {
append_opcode(GDScriptFunction::OPCODE_JUMP);
current_breaks_to_patch.back()->get().push_back(opcodes.size());
@@ -1576,12 +1589,6 @@ void GDScriptByteCodeGenerator::write_continue() {
append(continue_addrs.back()->get());
}
-void GDScriptByteCodeGenerator::write_continue_match() {
- append_opcode(GDScriptFunction::OPCODE_JUMP);
- match_continues_to_patch.back()->get().push_back(opcodes.size());
- append(0);
-}
-
void GDScriptByteCodeGenerator::write_breakpoint() {
append_opcode(GDScriptFunction::OPCODE_BREAKPOINT);
}
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index 171c505116..8aa02b86c4 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -95,6 +95,24 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
RBMap<MethodBind *, int> method_bind_map;
RBMap<GDScriptFunction *, int> lambdas_map;
+#if DEBUG_ENABLED
+ // Keep method and property names for pointer and validated operations.
+ // Used when disassembling the bytecode.
+ Vector<String> operator_names;
+ Vector<String> setter_names;
+ Vector<String> getter_names;
+ Vector<String> builtin_methods_names;
+ Vector<String> constructors_names;
+ Vector<String> utilities_names;
+ Vector<String> gds_utilities_names;
+ void add_debug_name(Vector<String> &vector, int index, const String &name) {
+ if (index >= vector.size()) {
+ vector.resize(index + 1);
+ }
+ vector.write[index] = name;
+ }
+#endif
+
// Lists since these can be nested.
List<int> if_jmp_addrs;
List<int> for_jmp_addrs;
@@ -113,7 +131,6 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
List<int> ternary_jump_skip_pos;
List<List<int>> current_breaks_to_patch;
- List<List<int>> match_continues_to_patch;
void add_stack_identifier(const StringName &p_id, int p_stackpos) {
if (locals.size() > max_locals) {
@@ -468,8 +485,8 @@ public:
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) override;
- virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) override;
void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, bool p_is_static, const Vector<Address> &p_arguments);
+ virtual void write_call_gdscript_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) override;
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) override;
@@ -496,12 +513,8 @@ public:
virtual void start_while_condition() override;
virtual void write_while(const Address &p_condition) override;
virtual void write_endwhile() override;
- virtual void start_match() override;
- virtual void start_match_branch() override;
- virtual void end_match() override;
virtual void write_break() override;
virtual void write_continue() override;
- virtual void write_continue_match() override;
virtual void write_breakpoint() override;
virtual void write_newline(int p_line) override;
virtual void write_return(const Address &p_return_value) override;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index e885938eba..6d42d152b9 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -121,7 +121,7 @@ public:
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) = 0;
- virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_gdscript_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) = 0;
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
@@ -148,12 +148,8 @@ public:
virtual void start_while_condition() = 0; // Used to allow a jump to the expression evaluation.
virtual void write_while(const Address &p_condition) = 0;
virtual void write_endwhile() = 0;
- virtual void start_match() = 0;
- virtual void start_match_branch() = 0;
- virtual void end_match() = 0;
virtual void write_break() = 0;
virtual void write_continue() = 0;
- virtual void write_continue_match() = 0;
virtual void write_breakpoint() = 0;
virtual void write_newline(int p_line) = 0;
virtual void write_return(const Address &p_return_value) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index d63a1b4536..c78dd1528f 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -546,7 +546,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->write_call_utility(result, call->function_name, arguments);
} else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptUtilityFunctions::function_exists(call->function_name)) {
// GDScript utility function.
- gen->write_call_gdscript_utility(result, GDScriptUtilityFunctions::get_function(call->function_name), arguments);
+ gen->write_call_gdscript_utility(result, call->function_name, arguments);
} else {
// Regular function.
const GDScriptParser::ExpressionNode *callee = call->callee;
@@ -1410,7 +1410,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
Vector<GDScriptCodeGenerator::Address> len_args;
len_args.push_back(p_value_addr);
- codegen.generator->write_call_gdscript_utility(value_length_addr, GDScriptUtilityFunctions::get_function("len"), len_args);
+ codegen.generator->write_call_gdscript_utility(value_length_addr, "len", len_args);
// Test length compatibility.
temp_type.builtin_type = Variant::BOOL;
@@ -1508,7 +1508,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
Vector<GDScriptCodeGenerator::Address> func_args;
func_args.push_back(p_value_addr);
- codegen.generator->write_call_gdscript_utility(value_length_addr, GDScriptUtilityFunctions::get_function("len"), func_args);
+ codegen.generator->write_call_gdscript_utility(value_length_addr, "len", func_args);
// Test length compatibility.
temp_type.builtin_type = Variant::BOOL;
@@ -1679,7 +1679,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
case GDScriptParser::Node::MATCH: {
const GDScriptParser::MatchNode *match = static_cast<const GDScriptParser::MatchNode *>(s);
- gen->start_match();
codegen.start_block();
// Evaluate the match expression.
@@ -1718,7 +1717,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
const GDScriptParser::MatchBranchNode *branch = match->branches[j];
- gen->start_match_branch(); // Need so lower level code can patch 'continue' jumps.
codegen.start_block(); // Create an extra block around for binds.
// Add locals in block before patterns, so temporaries don't use the stack address for binds.
@@ -1756,8 +1754,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
for (int j = 0; j < match->branches.size(); j++) {
gen->write_endif();
}
-
- gen->end_match();
} break;
case GDScriptParser::Node::IF: {
const GDScriptParser::IfNode *if_n = static_cast<const GDScriptParser::IfNode *>(s);
@@ -1845,12 +1841,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
gen->write_break();
} break;
case GDScriptParser::Node::CONTINUE: {
- const GDScriptParser::ContinueNode *cont = static_cast<const GDScriptParser::ContinueNode *>(s);
- if (cont->is_for_match) {
- gen->write_continue_match();
- } else {
- gen->write_continue();
- }
+ gen->write_continue();
} break;
case GDScriptParser::Node::RETURN: {
const GDScriptParser::ReturnNode *return_n = static_cast<const GDScriptParser::ReturnNode *>(s);
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 4edabdcb40..b5c8a6f478 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -128,7 +128,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += DADDR(3);
text += " = ";
text += DADDR(1);
- text += " <operator function> ";
+ text += " ";
+ text += operator_names[_code_ptr[ip + 4]];
+ text += " ";
text += DADDR(2);
incr += 5;
@@ -230,7 +232,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "set_named validated ";
text += DADDR(1);
text += "[\"";
- text += "<unknown name>";
+ text += setter_names[_code_ptr[ip + 3]];
text += "\"] = ";
text += DADDR(2);
@@ -253,7 +255,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += " = ";
text += DADDR(1);
text += "[\"";
- text += "<unknown name>";
+ text += getter_names[_code_ptr[ip + 3]];
text += "\"]";
incr += 4;
@@ -398,7 +400,8 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += DADDR(1 + argc);
text += " = ";
- text += "<unknown type>(";
+ text += constructors_names[_code_ptr[ip + 3 + argc]];
+ text += "(";
for (int i = 0; i < argc; i++) {
if (i > 0) {
text += ", ";
@@ -687,7 +690,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += DADDR(2 + argc) + " = ";
text += DADDR(1) + ".";
- text += "<unknown method>";
+ text += builtin_methods_names[_code_ptr[ip + 4 + argc]];
text += "(";
@@ -725,12 +728,12 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
case OPCODE_CALL_UTILITY_VALIDATED: {
int instr_var_args = _code_ptr[++ip];
- text += "call-utility ";
+ text += "call-utility validated ";
int argc = _code_ptr[ip + 1 + instr_var_args];
text += DADDR(1 + argc) + " = ";
- text += "<unknown function>";
+ text += utilities_names[_code_ptr[ip + 3 + argc]];
text += "(";
for (int i = 0; i < argc; i++) {
@@ -746,12 +749,12 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
case OPCODE_CALL_GDSCRIPT_UTILITY: {
int instr_var_args = _code_ptr[++ip];
- text += "call-gscript-utility ";
+ text += "call-gdscript-utility ";
int argc = _code_ptr[ip + 1 + instr_var_args];
text += DADDR(1 + argc) + " = ";
- text += "<unknown function>";
+ text += gds_utilities_names[_code_ptr[ip + 3 + argc]];
text += "(";
for (int i = 0; i < argc; i++) {
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 76214f3482..37416a734d 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -505,6 +505,16 @@ private:
Vector<Variant> default_arg_values;
#endif
+#ifdef DEBUG_ENABLED
+ Vector<String> operator_names;
+ Vector<String> setter_names;
+ Vector<String> getter_names;
+ Vector<String> builtin_methods_names;
+ Vector<String> constructors_names;
+ Vector<String> utilities_names;
+ Vector<String> gds_utilities_names;
+#endif
+
List<StackDebug> stack_debug;
Variant _get_default_variant_for_data_type(const GDScriptDataType &p_data_type);
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index f5d3306376..6dc63c502c 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -41,6 +41,7 @@
#include "core/os/os.h"
#include "core/string/string_builder.h"
#include "gdscript_warning.h"
+#include "servers/text_server.h"
#endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED
@@ -186,24 +187,6 @@ void GDScriptParser::push_error(const String &p_message, const Node *p_origin) {
}
#ifdef DEBUG_ENABLED
-void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_code, const String &p_symbol1, const String &p_symbol2, const String &p_symbol3, const String &p_symbol4) {
- ERR_FAIL_COND(p_source == nullptr);
- Vector<String> symbols;
- if (!p_symbol1.is_empty()) {
- symbols.push_back(p_symbol1);
- }
- if (!p_symbol2.is_empty()) {
- symbols.push_back(p_symbol2);
- }
- if (!p_symbol3.is_empty()) {
- symbols.push_back(p_symbol3);
- }
- if (!p_symbol4.is_empty()) {
- symbols.push_back(p_symbol4);
- }
- push_warning(p_source, p_code, symbols);
-}
-
void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Vector<String> &p_symbols) {
ERR_FAIL_COND(p_source == nullptr);
if (is_ignoring_warnings) {
@@ -1806,11 +1789,10 @@ GDScriptParser::BreakNode *GDScriptParser::parse_break() {
GDScriptParser::ContinueNode *GDScriptParser::parse_continue() {
if (!can_continue) {
- push_error(R"(Cannot use "continue" outside of a loop or pattern matching block.)");
+ push_error(R"(Cannot use "continue" outside of a loop.)");
}
current_suite->has_continue = true;
ContinueNode *cont = alloc_node<ContinueNode>();
- cont->is_for_match = is_continue_match;
complete_extents(cont);
end_statement(R"("continue")");
return cont;
@@ -1836,12 +1818,10 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() {
// Save break/continue state.
bool could_break = can_break;
bool could_continue = can_continue;
- bool was_continue_match = is_continue_match;
// Allow break/continue.
can_break = true;
can_continue = true;
- is_continue_match = false;
SuiteNode *suite = alloc_node<SuiteNode>();
if (n_for->variable) {
@@ -1859,7 +1839,6 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() {
// Reset break/continue state.
can_break = could_break;
can_continue = could_continue;
- is_continue_match = was_continue_match;
return n_for;
}
@@ -1996,13 +1975,6 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
return nullptr;
}
- // Save continue state.
- bool could_continue = can_continue;
- bool was_continue_match = is_continue_match;
- // Allow continue for match.
- can_continue = true;
- is_continue_match = true;
-
SuiteNode *suite = alloc_node<SuiteNode>();
if (branch->patterns.size() > 0) {
for (const KeyValue<StringName, IdentifierNode *> &E : branch->patterns[0]->binds) {
@@ -2015,10 +1987,6 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
branch->block = parse_suite("match pattern block", suite);
complete_extents(branch);
- // Restore continue state.
- can_continue = could_continue;
- is_continue_match = was_continue_match;
-
return branch;
}
@@ -2177,12 +2145,10 @@ GDScriptParser::WhileNode *GDScriptParser::parse_while() {
// Save break/continue state.
bool could_break = can_break;
bool could_continue = can_continue;
- bool was_continue_match = is_continue_match;
// Allow break/continue.
can_break = true;
can_continue = true;
- is_continue_match = false;
n_while->loop = parse_suite(R"("while" block)");
n_while->loop->is_loop = true;
@@ -2191,7 +2157,6 @@ GDScriptParser::WhileNode *GDScriptParser::parse_while() {
// Reset break/continue state.
can_break = could_break;
can_continue = could_continue;
- is_continue_match = was_continue_match;
return n_while;
}
@@ -2251,7 +2216,14 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_expression(bool p_can_assi
}
GDScriptParser::IdentifierNode *GDScriptParser::parse_identifier() {
- return static_cast<IdentifierNode *>(parse_identifier(nullptr, false));
+ IdentifierNode *identifier = static_cast<IdentifierNode *>(parse_identifier(nullptr, false));
+#ifdef DEBUG_ENABLED
+ // Check for spoofing here (if available in TextServer) since this isn't called inside expressions. This is only relevant for declarations.
+ if (identifier && TS->has_feature(TextServer::FEATURE_UNICODE_SECURITY) && TS->spoof_check(identifier->name.operator String())) {
+ push_warning(identifier, GDScriptWarning::CONFUSABLE_IDENTIFIER, identifier->name.operator String());
+ }
+#endif
+ return identifier;
}
GDScriptParser::ExpressionNode *GDScriptParser::parse_identifier(ExpressionNode *p_previous_operand, bool p_can_assign) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 0903f62061..5da709e8cd 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -758,7 +758,6 @@ public:
};
struct ContinueNode : public Node {
- bool is_for_match = false;
ContinueNode() {
type = CONTINUE;
}
@@ -1254,7 +1253,6 @@ private:
bool panic_mode = false;
bool can_break = false;
bool can_continue = false;
- bool is_continue_match = false; // Whether a `continue` will act on a `match`.
List<bool> multiline_stack;
ClassNode *head = nullptr;
@@ -1361,8 +1359,11 @@ private:
void clear();
void push_error(const String &p_message, const Node *p_origin = nullptr);
#ifdef DEBUG_ENABLED
- void push_warning(const Node *p_source, GDScriptWarning::Code p_code, const String &p_symbol1 = String(), const String &p_symbol2 = String(), const String &p_symbol3 = String(), const String &p_symbol4 = String());
void push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Vector<String> &p_symbols);
+ template <typename... Symbols>
+ void push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Symbols &...p_symbols) {
+ push_warning(p_source, p_code, Vector<String>{ p_symbols... });
+ }
#endif
void make_completion_context(CompletionType p_type, Node *p_node, int p_argument = -1, bool p_force = false);
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index e17a804003..d7f1114fd3 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -31,10 +31,14 @@
#include "gdscript_tokenizer.h"
#include "core/error/error_macros.h"
+#include "core/string/char_utils.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
#endif
+#ifdef DEBUG_ENABLED
+#include "servers/text_server.h"
+#endif
static const char *token_names[] = {
"Empty", // EMPTY,
@@ -435,10 +439,12 @@ GDScriptTokenizer::Token GDScriptTokenizer::check_vcs_marker(char32_t p_test, To
}
GDScriptTokenizer::Token GDScriptTokenizer::annotation() {
- if (!is_ascii_identifier_char(_peek())) {
+ if (is_unicode_identifier_start(_peek())) {
+ _advance(); // Consume start character.
+ } else {
push_error("Expected annotation identifier after \"@\".");
}
- while (is_ascii_identifier_char(_peek())) {
+ while (is_unicode_identifier_continue(_peek())) {
// Consume all identifier characters.
_advance();
}
@@ -447,7 +453,6 @@ GDScriptTokenizer::Token GDScriptTokenizer::annotation() {
return annotation;
}
-GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() {
#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
KEYWORD_GROUP('a') \
KEYWORD("as", Token::AS) \
@@ -512,8 +517,21 @@ GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() {
#define MIN_KEYWORD_LENGTH 2
#define MAX_KEYWORD_LENGTH 10
- // Consume all alphanumeric characters.
- while (is_ascii_identifier_char(_peek())) {
+#ifdef DEBUG_ENABLED
+void GDScriptTokenizer::make_keyword_list() {
+#define KEYWORD_LINE(keyword, token_type) keyword,
+#define KEYWORD_GROUP_IGNORE(group)
+ keyword_list = {
+ KEYWORDS(KEYWORD_GROUP_IGNORE, KEYWORD_LINE)
+ };
+#undef KEYWORD_LINE
+#undef KEYWORD_GROUP_IGNORE
+}
+#endif // DEBUG_ENABLED
+
+GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() {
+ // Consume all identifier characters.
+ while (is_unicode_identifier_continue(_peek())) {
_advance();
}
@@ -565,15 +583,28 @@ GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() {
}
// Not a keyword, so must be an identifier.
- return make_identifier(name);
+ Token id = make_identifier(name);
+
+#ifdef DEBUG_ENABLED
+ // Additional checks for identifiers but only in debug and if it's available in TextServer.
+ if (TS->has_feature(TextServer::FEATURE_UNICODE_SECURITY)) {
+ int64_t confusable = TS->is_confusable(name, keyword_list);
+ if (confusable >= 0) {
+ push_error(vformat(R"(Identifier "%s" is visually similar to the GDScript keyword "%s" and thus not allowed.)", name, keyword_list[confusable]));
+ }
+ }
+#endif // DEBUG_ENABLED
+
+ return id;
-#undef KEYWORDS
-#undef MIN_KEYWORD_LENGTH
-#undef MAX_KEYWORD_LENGTH
#undef KEYWORD_GROUP_CASE
#undef KEYWORD
}
+#undef MAX_KEYWORD_LENGTH
+#undef MIN_KEYWORD_LENGTH
+#undef KEYWORDS
+
void GDScriptTokenizer::newline(bool p_make_token) {
// Don't overwrite previous newline, nor create if we want a line continuation.
if (p_make_token && !pending_newline && !line_continuation) {
@@ -720,7 +751,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
error.rightmost_column = column + 1;
push_error(error);
has_error = true;
- } else if (is_ascii_identifier_char(_peek())) {
+ } else if (is_unicode_identifier_start(_peek()) || is_unicode_identifier_continue(_peek())) {
// Letter at the end of the number.
push_error("Invalid numeric notation.");
}
@@ -1311,7 +1342,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
if (is_digit(c)) {
return number();
- } else if (is_ascii_identifier_char(c)) {
+ } else if (is_unicode_identifier_start(c)) {
return potential_identifier();
}
@@ -1504,7 +1535,11 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
}
default:
- return make_error(vformat(R"(Unknown character "%s".)", String(&c, 1)));
+ if (is_whitespace(c)) {
+ return make_error(vformat(R"(Invalid white space character "\\u%X".)", static_cast<int32_t>(c)));
+ } else {
+ return make_error(vformat(R"(Unknown character "%s".)", String(&c, 1)));
+ }
}
}
@@ -1514,4 +1549,7 @@ GDScriptTokenizer::GDScriptTokenizer() {
tab_size = EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size");
}
#endif // TOOLS_ENABLED
+#ifdef DEBUG_ENABLED
+ make_keyword_list();
+#endif // DEBUG_ENABLED
}
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 9588922122..608840d3f1 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -224,6 +224,9 @@ private:
char32_t indent_char = '\0';
int position = 0;
int length = 0;
+#ifdef DEBUG_ENABLED
+ Vector<String> keyword_list;
+#endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED
HashMap<int, CommentData> comments;
@@ -239,6 +242,10 @@ private:
void _skip_whitespace();
void check_indent();
+#ifdef DEBUG_ENABLED
+ void make_keyword_list();
+#endif // DEBUG_ENABLED
+
Token make_error(const String &p_message);
void push_error(const String &p_message);
void push_error(const Token &p_error);
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 184cecb316..a6cbb7f6ae 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -155,6 +155,10 @@ String GDScriptWarning::get_message() const {
CHECK_SYMBOLS(2);
return vformat(R"(The function '%s()' is a static function but was called from an instance. Instead, it should be directly called from the type: '%s.%s()'.)", symbols[0], symbols[1], symbols[0]);
}
+ case CONFUSABLE_IDENTIFIER: {
+ CHECK_SYMBOLS(1);
+ return vformat(R"(The identifier "%s" has misleading characters and might be confused with something else.)", symbols[0]);
+ }
case WARNING_MAX:
break; // Can't happen, but silences warning
}
@@ -219,6 +223,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"SHADOWED_GLOBAL_IDENTIFIER",
"INT_ASSIGNED_TO_ENUM",
"STATIC_CALLED_ON_INSTANCE",
+ "CONFUSABLE_IDENTIFIER",
};
static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index e3aee45f33..b485f02b9c 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -78,6 +78,7 @@ public:
SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable.
INT_ASSIGNED_TO_ENUM, // An integer value was assigned to an enum-typed variable without casting.
STATIC_CALLED_ON_INSTANCE, // A static method was called on an instance of a class instead of on the class itself.
+ CONFUSABLE_IDENTIFIER, // The identifier contains misleading characters that can be confused. E.g. "usеr" (has Cyrillic "е" instead of Latin "e").
WARNING_MAX,
};
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.out b/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.out
index b018091c18..32e230fc80 100644
--- a/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.out
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/lambda_unused_arg.out
@@ -2,4 +2,4 @@ GDTEST_OK
>> WARNING
>> Line: 2
>> UNUSED_PARAMETER
->>
+>> The parameter 'unused' is never used in the function ''. If this is intended, prefix it with an underscore: '_unused'
diff --git a/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.gd b/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.gd
new file mode 100644
index 0000000000..4b1f284070
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.gd
@@ -0,0 +1,3 @@
+func test():
+ var аs # Using Cyrillic "а".
+ print(аs)
diff --git a/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.out b/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.out
new file mode 100644
index 0000000000..337dec2f4d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/identifier_similar_to_keyword.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Identifier "аs" is visually similar to the GDScript keyword "as" and thus not allowed.
diff --git a/modules/gdscript/tests/scripts/parser/features/match.gd b/modules/gdscript/tests/scripts/parser/features/match.gd
index 4d05490aa5..59b5ba2426 100644
--- a/modules/gdscript/tests/scripts/parser/features/match.gd
+++ b/modules/gdscript/tests/scripts/parser/features/match.gd
@@ -3,8 +3,6 @@ func test():
match i:
"Hello":
print("hello")
- # This will fall through to the default case below.
- continue
"Good bye":
print("bye")
_:
diff --git a/modules/gdscript/tests/scripts/parser/features/match.out b/modules/gdscript/tests/scripts/parser/features/match.out
index 732885c7a2..a2cb94399c 100644
--- a/modules/gdscript/tests/scripts/parser/features/match.out
+++ b/modules/gdscript/tests/scripts/parser/features/match.out
@@ -1,4 +1,3 @@
GDTEST_OK
hello
-default
This will match
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_match.gd b/modules/gdscript/tests/scripts/parser/features/nested_match.gd
index aaddcc7e83..491d917a8e 100644
--- a/modules/gdscript/tests/scripts/parser/features/nested_match.gd
+++ b/modules/gdscript/tests/scripts/parser/features/nested_match.gd
@@ -8,11 +8,10 @@ func test():
1234:
print("2")
match number:
- 1234:
- print("3")
- continue
+ 4321:
+ print("Should not be printed")
_:
- print("Should also be printed")
+ print("3")
match number:
1234:
print("4")
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_match.out b/modules/gdscript/tests/scripts/parser/features/nested_match.out
index 651d76cc59..c2d2e29a06 100644
--- a/modules/gdscript/tests/scripts/parser/features/nested_match.out
+++ b/modules/gdscript/tests/scripts/parser/features/nested_match.out
@@ -2,7 +2,6 @@ GDTEST_OK
1
2
3
-Should also be printed
4
5
6
diff --git a/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd b/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd
new file mode 100644
index 0000000000..523959a016
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.gd
@@ -0,0 +1,35 @@
+const π = PI
+var ㄥ = π
+
+func test():
+ var փորձարկում = "test"
+ prints("փորձարկում", փորձարկում)
+ var امتحان = "test"
+ prints("امتحان", امتحان)
+ var পরীক্ষা = "test"
+ prints("পরীক্ষা", পরীক্ষা)
+ var тест = "test"
+ prints("тест", тест)
+ var जाँच = "test"
+ prints("जाँच", जाँच)
+ var 기준 = "test"
+ prints("기준", 기준)
+ var 测试 = "test"
+ prints("测试", 测试)
+ var テスト = "test"
+ prints("テスト", テスト)
+ var 試験 = "test"
+ prints("試験", 試験)
+ var പരീക്ഷ = "test"
+ prints("പരീക്ഷ", പരീക്ഷ)
+ var ทดสอบ = "test"
+ prints("ทดสอบ", ทดสอบ)
+ var δοκιμή = "test"
+ prints("δοκιμή", δοκιμή)
+
+ const d = 1.1
+ _process(d)
+ print(is_equal_approx(ㄥ, PI + (d * PI)))
+
+func _process(Δ: float) -> void:
+ ㄥ += Δ * π
diff --git a/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.out b/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.out
new file mode 100644
index 0000000000..c071380a8f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/unicode_identifiers.out
@@ -0,0 +1,14 @@
+GDTEST_OK
+փորձարկում test
+امتحان test
+পরীক্ষা test
+тест test
+जाँच test
+기준 test
+测试 test
+テスト test
+試験 test
+പരീക്ഷ test
+ทดสอบ test
+δοκιμή test
+true
diff --git a/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.gd b/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.gd
new file mode 100644
index 0000000000..e2caac8ffd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.gd
@@ -0,0 +1,5 @@
+func test():
+ var port = 0 # Only latin characters.
+ var pοrt = 1 # The "ο" is Greek omicron.
+
+ prints(port, pοrt)
diff --git a/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.out b/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.out
new file mode 100644
index 0000000000..c483396443
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/confusable_identifier.out
@@ -0,0 +1,6 @@
+GDTEST_OK
+>> WARNING
+>> Line: 3
+>> CONFUSABLE_IDENTIFIER
+>> The identifier "pοrt" has misleading characters and might be confused with something else.
+0 1
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 5634c51c61..b243ba933d 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -6072,6 +6072,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_
const int track_idx = animation->get_track_count();
animation->add_track(Animation::TYPE_BLEND_SHAPE);
animation->track_set_path(track_idx, blend_path);
+ animation->track_set_imported(track_idx, true); //helps merging later
// Only LINEAR and STEP (NEAREST) can be supported out of the box by Godot's Animation,
// the other modes have to be baked.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index 2effdecf40..6a7863112a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -797,7 +797,7 @@ namespace Godot
{
if (saturation == 0)
{
- // Achromatic (grey)
+ // Achromatic (gray)
return new Color(value, value, value, alpha);
}
diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp
index 66e12a338a..9e542828ee 100644
--- a/modules/multiplayer/editor/replication_editor.cpp
+++ b/modules/multiplayer/editor/replication_editor.cpp
@@ -172,7 +172,7 @@ ReplicationEditor::ReplicationEditor() {
set_custom_minimum_size(Size2(0, 200) * EDSCALE);
delete_dialog = memnew(ConfirmationDialog);
- delete_dialog->connect("cancelled", callable_mp(this, &ReplicationEditor::_dialog_closed).bind(false));
+ delete_dialog->connect("canceled", callable_mp(this, &ReplicationEditor::_dialog_closed).bind(false));
delete_dialog->connect("confirmed", callable_mp(this, &ReplicationEditor::_dialog_closed).bind(true));
add_child(delete_dialog);
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp
index 233ff76c7d..3466cb10df 100644
--- a/modules/multiplayer/scene_replication_interface.cpp
+++ b/modules/multiplayer/scene_replication_interface.cpp
@@ -125,7 +125,7 @@ void SceneReplicationInterface::on_reset() {
}
void SceneReplicationInterface::on_network_process() {
- // Prevent endless stalling in case of unforseen spawn errors.
+ // Prevent endless stalling in case of unforeseen spawn errors.
if (spawn_queue.size()) {
ERR_PRINT("An error happened during last spawn, this usually means the 'ready' signal was not emitted by the spawned node.");
for (const ObjectID &oid : spawn_queue) {
diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
index 54f7abda8d..557d45b386 100644
--- a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
+++ b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
@@ -60,12 +60,40 @@ void NavigationMeshEditor::_bake_pressed() {
button_bake->set_pressed(false);
ERR_FAIL_COND(!node);
- if (!node->get_navigation_mesh().is_valid()) {
+ Ref<NavigationMesh> navmesh = node->get_navigation_mesh();
+ if (!navmesh.is_valid()) {
err_dialog->set_text(TTR("A NavigationMesh resource must be set or created for this node to work."));
err_dialog->popup_centered();
return;
}
+ String path = navmesh->get_path();
+ if (!path.is_resource_file()) {
+ int srpos = path.find("::");
+ if (srpos != -1) {
+ String base = path.substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ err_dialog->set_text(TTR("Cannot generate navigation mesh because it does not belong to the edited scene. Make it unique first."));
+ err_dialog->popup_centered();
+ return;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ err_dialog->set_text(TTR("Cannot generate navigation mesh because it belongs to a resource which was imported."));
+ err_dialog->popup_centered();
+ return;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(path + ".import")) {
+ err_dialog->set_text(TTR("Cannot generate navigation mesh because the resource was imported from another type."));
+ err_dialog->popup_centered();
+ return;
+ }
+ }
+
NavigationMeshGenerator::get_singleton()->clear(node->get_navigation_mesh());
NavigationMeshGenerator::get_singleton()->bake(node->get_navigation_mesh(), node);
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 7090588c6e..fe255c1ce8 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -225,7 +225,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
avp.entry = new_entry;
}
} else {
- // Add the neighbour polygon to the reachable ones.
+ // Add the neighbor polygon to the reachable ones.
gd::NavigationPoly new_navigation_poly = gd::NavigationPoly(connection.polygon);
new_navigation_poly.self_id = navigation_polys.size();
new_navigation_poly.back_navigation_poly_id = least_cost_id;
@@ -236,7 +236,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
new_navigation_poly.entry = new_entry;
navigation_polys.push_back(new_navigation_poly);
- // Add the neighbour polygon to the polygons to visit.
+ // Add the neighbor polygon to the polygons to visit.
to_visit.push_back(navigation_polys.size() - 1);
}
}
diff --git a/modules/openxr/doc_classes/OpenXRAction.xml b/modules/openxr/doc_classes/OpenXRAction.xml
index a3a45ebb4c..d53648723a 100644
--- a/modules/openxr/doc_classes/OpenXRAction.xml
+++ b/modules/openxr/doc_classes/OpenXRAction.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
This resource defines an OpenXR action. Actions can be used both for inputs (buttons/joystick/trigger/etc) and outputs (haptics).
- OpenXR performs automatic conversion between action type and input type whenever possible. An analogue trigger bound to a boolean action will thus return [code]false[/code] if the trigger is depressed and [code]true[/code] if pressed fully.
+ OpenXR performs automatic conversion between action type and input type whenever possible. An analog trigger bound to a boolean action will thus return [code]false[/code] if the trigger is depressed and [code]true[/code] if pressed fully.
Actions are not directly bound to specific devices, instead OpenXR recognizes a limited number of top level paths that identify devices by usage. We can restrict which devices an action can be bound to by these top level paths. For instance an action that should only be used for hand held controllers can have the top level paths "/user/hand/left" and "/user/hand/right" associated with them. See the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-reserved]reserved path section in the OpenXR specification[/url] for more info on the top level paths.
Note that the name of the resource is used to register the action with.
</description>
@@ -27,7 +27,7 @@
This action provides a boolean value.
</constant>
<constant name="OPENXR_ACTION_FLOAT" value="1" enum="ActionType">
- This action provides a float value between [code]0.0[/code] and [code]1.0[/code] for any analogue input such as triggers.
+ This action provides a float value between [code]0.0[/code] and [code]1.0[/code] for any analog input such as triggers.
</constant>
<constant name="OPENXR_ACTION_VECTOR2" value="2" enum="ActionType">
This action provides a vector2 value and can be bound to embedded trackpads and joysticks
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 6b8f140923..0a25cd68b7 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -751,7 +751,7 @@ bool OpenXRAPI::create_swapchains() {
Also Godot only creates a swapchain for the main output.
OpenXR will require us to create swapchains as the render target for additional viewports if we want to use the layer system
- to optimise text rendering and background rendering as OpenXR may choose to re-use the results for reprojection while we're
+ to optimize text rendering and background rendering as OpenXR may choose to re-use the results for reprojection while we're
already rendering the next frame.
Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create,
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 52a1af5a09..e1787c6da0 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -53,7 +53,7 @@
#include "util.h"
-// Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initialising structs which ensures zeroing out unspecified members.
+// Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initializing structs which ensures zeroing out unspecified members.
// Godot is currently restricted to C++17 which doesn't allow this notation. Make sure critical fields are set.
// forward declarations, we don't want to include these fully
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index 1c4d53c43a..306a2f1bbd 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -70,7 +70,7 @@ static void _editor_init() {
// Only add our OpenXR action map editor if OpenXR is enabled for our project
if (openxr_interaction_profile_meta_data == nullptr) {
- // If we didn't initialize our actionmap meta data at startup, we initialise it now.
+ // If we didn't initialize our actionmap meta data at startup, we initialize it now.
openxr_interaction_profile_meta_data = memnew(OpenXRInteractionProfileMetaData);
ERR_FAIL_NULL(openxr_interaction_profile_meta_data);
}
@@ -85,7 +85,7 @@ static void _editor_init() {
void initialize_openxr_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
if (OpenXRAPI::openxr_is_enabled(false)) {
- // Always register our extension wrappers even if we don't initialise OpenXR.
+ // Always register our extension wrappers even if we don't initialize OpenXR.
// Some of these wrappers will add functionality to our editor.
#ifdef ANDROID_ENABLED
OpenXRAPI::register_extension_wrapper(memnew(OpenXRAndroidExtension));
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 79ca4a7024..ddafae5e58 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -4136,8 +4136,9 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S
if (p_sd->bidi_override[ov].x >= p_start + p_length || p_sd->bidi_override[ov].y <= p_start) {
continue;
}
- int start = _convert_pos_inv(p_sd, MAX(0, p_start - p_sd->bidi_override[ov].x));
- int end = _convert_pos_inv(p_sd, MIN(p_start + p_length, p_sd->bidi_override[ov].y) - p_sd->bidi_override[ov].x);
+ int ov_start = _convert_pos_inv(p_sd, p_sd->bidi_override[ov].x);
+ int start = MAX(0, _convert_pos_inv(p_sd, p_start) - ov_start);
+ int end = MIN(_convert_pos_inv(p_sd, p_start + p_length), _convert_pos_inv(p_sd, p_sd->bidi_override[ov].y)) - ov_start;
ERR_FAIL_COND_V_MSG((start < 0 || end - start > p_new_sd->utf16.length()), false, "Invalid BiDi override range.");
@@ -4159,8 +4160,8 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S
int32_t _bidi_run_length = 0;
ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length);
- int32_t bidi_run_start = _convert_pos(p_sd, p_sd->bidi_override[ov].x + start + _bidi_run_start);
- int32_t bidi_run_end = _convert_pos(p_sd, p_sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length);
+ int32_t bidi_run_start = _convert_pos(p_sd, ov_start + start + _bidi_run_start);
+ int32_t bidi_run_end = _convert_pos(p_sd, ov_start + start + _bidi_run_start + _bidi_run_length);
for (int j = 0; j < sd_size; j++) {
if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) {
@@ -5587,7 +5588,7 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
}
UErrorCode err = U_ZERO_ERROR;
- UBiDi *bidi_iter = ubidi_openSized(end, 0, &err);
+ UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
switch (static_cast<TextServer::Direction>(sd->bidi_override[ov].z)) {
@@ -5605,7 +5606,7 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
if (direction != UBIDI_NEUTRAL) {
ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
} else {
- ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_DEFAULT_LTR, nullptr, &err);
+ ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err);
}
} break;
}
@@ -5637,8 +5638,8 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
}
}
- int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x - sd->start + _bidi_run_start);
- int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x - sd->start + _bidi_run_start + _bidi_run_length);
+ int32_t bidi_run_start = _convert_pos(sd, start + _bidi_run_start);
+ int32_t bidi_run_end = _convert_pos(sd, start + _bidi_run_start + _bidi_run_length);
// Shape runs.
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index e3f93086dc..277195a054 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -56,7 +56,7 @@ void AndroidInputHandler::_set_key_modifier_state(Ref<InputEventWithModifiers> e
ev->set_ctrl_pressed(control_mem);
}
-void AndroidInputHandler::process_key_event(int p_keycode, int p_physical_keycode, int p_unicode, bool p_pressed) {
+void AndroidInputHandler::process_key_event(int p_physical_keycode, int p_unicode, int p_key_label, bool p_pressed) {
static char32_t prev_wc = 0;
char32_t unicode = p_unicode;
if ((p_unicode & 0xfffffc00) == 0xd800) {
@@ -80,10 +80,7 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_physical_keycod
ev.instantiate();
Key physical_keycode = godot_code_from_android_code(p_physical_keycode);
- Key keycode = physical_keycode;
- if (p_keycode != 0) {
- keycode = godot_code_from_unicode(p_keycode);
- }
+ Key keycode = fix_keycode(unicode, physical_keycode);
switch (physical_keycode) {
case Key::SHIFT: {
@@ -104,7 +101,8 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_physical_keycod
ev->set_keycode(keycode);
ev->set_physical_keycode(physical_keycode);
- ev->set_unicode(unicode);
+ ev->set_key_label(fix_key_label(p_key_label, keycode));
+ ev->set_unicode(fix_unicode(unicode));
ev->set_pressed(p_pressed);
_set_key_modifier_state(ev);
diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h
index 34259efd81..6e53dcfc89 100644
--- a/platform/android/android_input_handler.h
+++ b/platform/android/android_input_handler.h
@@ -97,7 +97,7 @@ public:
void process_magnify(Point2 p_pos, float p_factor);
void process_pan(Point2 p_pos, Vector2 p_delta);
void process_joy_event(JoypadEvent p_event);
- void process_key_event(int p_keycode, int p_physical_keycode, int p_unicode, bool p_pressed);
+ void process_key_event(int p_physical_keycode, int p_unicode, int p_key_label, bool p_pressed);
};
#endif // ANDROID_INPUT_HANDLER_H
diff --git a/platform/android/android_keys_utils.cpp b/platform/android/android_keys_utils.cpp
index 0dc2d19cdd..f50437e82a 100644
--- a/platform/android/android_keys_utils.cpp
+++ b/platform/android/android_keys_utils.cpp
@@ -38,41 +38,3 @@ Key godot_code_from_android_code(unsigned int p_code) {
}
return Key::UNKNOWN;
}
-
-Key godot_code_from_unicode(unsigned int p_code) {
- unsigned int code = p_code;
- if (code > 0xFF) {
- return Key::UNKNOWN;
- }
- // Known control codes.
- if (code == '\b') { // 0x08
- return Key::BACKSPACE;
- }
- if (code == '\t') { // 0x09
- return Key::TAB;
- }
- if (code == '\n') { // 0x0A
- return Key::ENTER;
- }
- if (code == 0x1B) {
- return Key::ESCAPE;
- }
- if (code == 0x1F) {
- return Key::KEY_DELETE;
- }
- // Unknown control codes.
- if (code <= 0x1F || (code >= 0x80 && code <= 0x9F)) {
- return Key::UNKNOWN;
- }
- // Convert to uppercase.
- if (code >= 'a' && code <= 'z') { // 0x61 - 0x7A
- code -= ('a' - 'A');
- }
- if (code >= u'à' && code <= u'ö') { // 0xE0 - 0xF6
- code -= (u'à' - u'À'); // 0xE0 - 0xC0
- }
- if (code >= u'ø' && code <= u'þ') { // 0xF8 - 0xFF
- code -= (u'ø' - u'Ø'); // 0xF8 - 0xD8
- }
- return Key(code);
-}
diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h
index 33e7929278..3a587dd680 100644
--- a/platform/android/android_keys_utils.h
+++ b/platform/android/android_keys_utils.h
@@ -165,13 +165,14 @@ static AndroidGodotCodePair android_godot_code_pairs[] = {
{ AKEYCODE_NUMPAD_DOT, Key::KP_PERIOD }, // (158) Numeric keypad '.' key (for decimals or digit grouping).
{ AKEYCODE_NUMPAD_ENTER, Key::KP_ENTER }, // (160) Numeric keypad Enter key.
{ AKEYCODE_VOLUME_MUTE, Key::VOLUMEMUTE }, // (164) Volume Mute key.
+ { AKEYCODE_EISU, Key::JIS_EISU }, // (212) JIS EISU key.
{ AKEYCODE_YEN, Key::YEN }, // (216) Japanese Yen key.
+ { AKEYCODE_KANA, Key::JIS_KANA }, // (218) JIS KANA key.
{ AKEYCODE_HELP, Key::HELP }, // (259) Help key.
{ AKEYCODE_REFRESH, Key::REFRESH }, // (285) Refresh key.
{ AKEYCODE_MAX, Key::UNKNOWN }
};
Key godot_code_from_android_code(unsigned int p_code);
-Key godot_code_from_unicode(unsigned int p_code);
#endif // ANDROID_KEYS_UTILS_H
diff --git a/platform/android/java/lib/res/values/strings.xml b/platform/android/java/lib/res/values/strings.xml
index f5a4ab1071..7efac4ce71 100644
--- a/platform/android/java/lib/res/values/strings.xml
+++ b/platform/android/java/lib/res/values/strings.xml
@@ -48,7 +48,7 @@
<string name="state_failed_unlicensed">Download failed because you may not have purchased this app</string>
<string name="state_failed_fetching_url">Download failed because the resources could not be found</string>
<string name="state_failed_sdcard_full">Download failed because the external storage is full</string>
- <string name="state_failed_cancelled">Download cancelled</string>
+ <string name="state_failed_cancelled">Download canceled</string>
<string name="state_failed">Download failed</string>
<string name="kilobytes_per_second">%1$s KB/s</string>
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index 31b512d2dd..75a01dc787 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -148,7 +148,7 @@ public class GodotLib {
/**
* Forward regular key events.
*/
- public static native void key(int p_keycode, int p_physical_keycode, int p_unicode, boolean p_pressed);
+ public static native void key(int p_physical_keycode, int p_unicode, int p_key_label, boolean p_pressed);
/**
* Forward game device's key events.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index f2bd3e28e6..cedbbfb7c3 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -129,12 +129,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
} else {
// getKeyCode(): The physical key that was pressed.
- // Godot's keycodes match the ASCII codes, so for single byte unicode characters,
- // we can use the unmodified unicode character to determine Godot's keycode.
- final int keycode = event.getUnicodeChar(0);
final int physical_keycode = event.getKeyCode();
final int unicode = event.getUnicodeChar();
- GodotLib.key(keycode, physical_keycode, unicode, false);
+ final int key_label = event.getDisplayLabel();
+ GodotLib.key(physical_keycode, unicode, key_label, false);
};
return true;
@@ -166,10 +164,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
GodotLib.joybutton(godotJoyId, button, true);
}
} else {
- final int keycode = event.getUnicodeChar(0);
final int physical_keycode = event.getKeyCode();
final int unicode = event.getUnicodeChar();
- GodotLib.key(keycode, physical_keycode, unicode, true);
+ final int key_label = event.getDisplayLabel();
+ GodotLib.key(physical_keycode, unicode, key_label, true);
}
return true;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
index fdfe20f32b..7b628e25ed 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
@@ -93,8 +93,8 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
@Override
public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) {
for (int i = 0; i < count; ++i) {
- GodotLib.key(0, KeyEvent.KEYCODE_DEL, 0, true);
- GodotLib.key(0, KeyEvent.KEYCODE_DEL, 0, false);
+ GodotLib.key(KeyEvent.KEYCODE_DEL, 0, 0, true);
+ GodotLib.key(KeyEvent.KEYCODE_DEL, 0, 0, false);
if (mHasSelection) {
mHasSelection = false;
@@ -110,13 +110,13 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
newChars[i - start] = pCharSequence.charAt(i);
}
for (int i = 0; i < count; ++i) {
- int key = newChars[i];
- if ((key == '\n') && !(mEdit.getKeyboardType() == GodotEditText.VirtualKeyboardType.KEYBOARD_TYPE_MULTILINE)) {
+ final int character = newChars[i];
+ if ((character == '\n') && !(mEdit.getKeyboardType() == GodotEditText.VirtualKeyboardType.KEYBOARD_TYPE_MULTILINE)) {
// Return keys are handled through action events
continue;
}
- GodotLib.key(key, 0, key, true);
- GodotLib.key(key, 0, key, false);
+ GodotLib.key(0, character, 0, true);
+ GodotLib.key(0, character, 0, false);
}
}
@@ -126,17 +126,17 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
final String characters = pKeyEvent.getCharacters();
for (int i = 0; i < characters.length(); i++) {
- final int ch = characters.codePointAt(i);
- GodotLib.key(ch, 0, ch, true);
- GodotLib.key(ch, 0, ch, false);
+ final int character = characters.codePointAt(i);
+ GodotLib.key(0, character, 0, true);
+ GodotLib.key(0, character, 0, false);
}
}
if (pActionID == EditorInfo.IME_ACTION_DONE) {
// Enter key has been pressed
mRenderView.queueOnRenderThread(() -> {
- GodotLib.key(0, KeyEvent.KEYCODE_ENTER, 0, true);
- GodotLib.key(0, KeyEvent.KEYCODE_ENTER, 0, false);
+ GodotLib.key(KeyEvent.KEYCODE_ENTER, 0, 0, true);
+ GodotLib.key(KeyEvent.KEYCODE_ENTER, 0, 0, false);
});
mRenderView.getView().requestFocus();
return true;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java b/platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java
index 2cc37b627a..3ee3478fcb 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.java
@@ -120,7 +120,7 @@ public final class ProcessPhoenix extends Activity {
/**
* Checks if the current process is a temporary Phoenix Process.
- * This can be used to avoid initialisation of unused resources or to prevent running code that
+ * This can be used to avoid initialization of unused resources or to prevent running code that
* is not multi-process ready.
*
* @return true if the current process is a temporary Phoenix Process
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index e6cdd7932a..1ee1cccb82 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -382,11 +382,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_physical_keycode, jint p_unicode, jint p_key_label, jboolean p_pressed) {
if (step.get() <= 0) {
return;
}
- input_handler->process_key_event(p_keycode, p_physical_keycode, p_unicode, p_pressed);
+ input_handler->process_key_event(p_physical_keycode, p_unicode, p_key_label, p_pressed);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) {
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 3f07a8cfe1..0020ddffd2 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -49,7 +49,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JN
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jboolean p_double_tap);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_physical_keycode, jint p_unicode, jint p_key_label, jboolean p_pressed);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y);
diff --git a/platform/ios/SCsub b/platform/ios/SCsub
index bf12ab6dd7..f3925c146f 100644
--- a/platform/ios/SCsub
+++ b/platform/ios/SCsub
@@ -20,6 +20,7 @@ ios_lib = [
"godot_view_gesture_recognizer.mm",
"device_metrics.m",
"keyboard_input_view.mm",
+ "key_mapping_ios.mm",
]
env_ios = env.Clone()
diff --git a/platform/ios/detect.py b/platform/ios/detect.py
index 38e62134b5..71612cf1fa 100644
--- a/platform/ios/detect.py
+++ b/platform/ios/detect.py
@@ -99,8 +99,8 @@ def configure(env: "Environment"):
if env["ios_simulator"]:
detect_darwin_sdk_path("iossimulator", env)
- env.Append(ASFLAGS=["-mios-simulator-version-min=13.0"])
- env.Append(CCFLAGS=["-mios-simulator-version-min=13.0"])
+ env.Append(ASFLAGS=["-mios-simulator-version-min=11.0"])
+ env.Append(CCFLAGS=["-mios-simulator-version-min=11.0"])
env.extra_suffix = ".simulator" + env.extra_suffix
else:
detect_darwin_sdk_path("ios", env)
@@ -153,3 +153,11 @@ def configure(env: "Environment"):
if env["vulkan"]:
env.Append(CPPDEFINES=["VULKAN_ENABLED"])
+
+ if env["opengl3"]:
+ env.Append(CPPDEFINES=["GLES3_ENABLED"])
+ env.Prepend(
+ CPPPATH=[
+ "$IOS_SDK_PATH/System/Library/Frameworks/OpenGLES.framework/Headers",
+ ]
+ )
diff --git a/platform/ios/display_layer.h b/platform/ios/display_layer.h
index 10f42264df..e719a42cd9 100644
--- a/platform/ios/display_layer.h
+++ b/platform/ios/display_layer.h
@@ -33,7 +33,8 @@
@protocol DisplayLayer <NSObject>
-- (void)renderDisplayLayer;
+- (void)startRenderDisplayLayer;
+- (void)stopRenderDisplayLayer;
- (void)initializeDisplayLayer;
- (void)layoutDisplayLayer;
diff --git a/platform/ios/display_layer.mm b/platform/ios/display_layer.mm
index 24614fea56..3129ebb276 100644
--- a/platform/ios/display_layer.mm
+++ b/platform/ios/display_layer.mm
@@ -60,7 +60,10 @@
- (void)layoutDisplayLayer {
}
-- (void)renderDisplayLayer {
+- (void)startRenderDisplayLayer {
+}
+
+- (void)stopRenderDisplayLayer {
}
@end
@@ -76,8 +79,6 @@
}
- (void)initializeDisplayLayer {
- // Get our backing layer
-
// Configure it so that it is opaque, does not retain the contents of the backbuffer when displayed, and uses RGBA8888 color.
self.opaque = YES;
self.drawableProperties = [NSDictionary
@@ -87,8 +88,6 @@
kEAGLDrawablePropertyColorFormat,
nil];
- // FIXME: Add Vulkan support via MoltenVK. Add fallback code back?
-
// Create GL ES 3 context
if (GLOBAL_GET("rendering/renderer/rendering_method") == "gl_compatibility") {
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
@@ -115,8 +114,22 @@
[self createFramebuffer];
}
-- (void)renderDisplayLayer {
+- (void)startRenderDisplayLayer {
[EAGLContext setCurrentContext:context];
+
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
+}
+
+- (void)stopRenderDisplayLayer {
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
+ [context presentRenderbuffer:GL_RENDERBUFFER_OES];
+
+#ifdef DEBUG_ENABLED
+ GLenum err = glGetError();
+ if (err) {
+ NSLog(@"DrawView: %x error", err);
+ }
+#endif
}
- (void)dealloc {
@@ -154,11 +167,15 @@
return NO;
}
+ GLES3::TextureStorage::system_fbo = viewFramebuffer;
+
return YES;
}
// Clean up any buffers we have allocated.
- (void)destroyFramebuffer {
+ GLES3::TextureStorage::system_fbo = 0;
+
glDeleteFramebuffersOES(1, &viewFramebuffer);
viewFramebuffer = 0;
glDeleteRenderbuffersOES(1, &viewRenderbuffer);
diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h
index dd1157f668..6eaa7c8edc 100644
--- a/platform/ios/display_server_ios.h
+++ b/platform/ios/display_server_ios.h
@@ -47,6 +47,10 @@
#endif
#endif
+#if defined(GLES3_ENABLED)
+#include "drivers/gles3/rasterizer_gles3.h"
+#endif // GLES3_ENABLED
+
#import <Foundation/Foundation.h>
#import <QuartzCore/CAMetalLayer.h>
@@ -109,11 +113,12 @@ public:
void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click);
void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, float p_pressure, Vector2 p_tilt);
- void touches_cancelled(int p_idx);
+ void touches_canceled(int p_idx);
// MARK: Keyboard
- void key(Key p_key, char32_t p_char, bool p_pressed);
+ void key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed);
+ bool is_keyboard_active() const;
// MARK: Motion
@@ -216,6 +221,7 @@ public:
virtual bool screen_is_kept_on() const override;
void resize_window(CGSize size);
+ virtual void swap_buffers() override {}
};
#endif // DISPLAY_SERVER_IOS_H
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index 86ea602a98..469bc9be17 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -36,6 +36,7 @@
#import "device_metrics.h"
#import "godot_view.h"
#include "ios.h"
+#import "key_mapping_ios.h"
#import "keyboard_input_view.h"
#include "os_ios.h"
#include "tts_ios.h"
@@ -50,33 +51,14 @@ DisplayServerIOS *DisplayServerIOS::get_singleton() {
}
DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
+ KeyMappingIOS::initialize();
+
rendering_driver = p_rendering_driver;
// Init TTS
tts = [[TTS_IOS alloc] init];
-#if defined(GLES3_ENABLED)
- if (rendering_driver == "opengl3") {
- bool gl_initialization_error = false;
-
- if (RasterizerGLES3::is_viable() == OK) {
- RasterizerGLES3::register_config();
- RasterizerGLES3::make_current();
- } else {
- gl_initialization_error = true;
- }
-
- if (gl_initialization_error) {
- OS::get_singleton()->alert(
- "Your device seems not to support the required OpenGL ES 3.0 version.\n\n",
- "Unable to initialize OpenGL video driver");
- }
- }
-#endif
-
#if defined(VULKAN_ENABLED)
- rendering_driver = "vulkan";
-
context_vulkan = nullptr;
rendering_device_vulkan = nullptr;
@@ -91,13 +73,14 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
CALayer *layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"vulkan"];
if (!layer) {
- ERR_FAIL_MSG("Failed to create iOS rendering layer.");
+ ERR_FAIL_MSG("Failed to create iOS Vulkan rendering layer.");
}
Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale();
if (context_vulkan->window_create(MAIN_WINDOW_ID, p_vsync_mode, layer, size.width, size.height) != OK) {
memdelete(context_vulkan);
context_vulkan = nullptr;
+ r_error = ERR_UNAVAILABLE;
ERR_FAIL_MSG("Failed to create Vulkan window.");
}
@@ -108,6 +91,18 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
}
#endif
+#if defined(GLES3_ENABLED)
+ if (rendering_driver == "opengl3") {
+ CALayer *layer = [AppDelegate.viewController.godotView initializeRenderingForDriver:@"opengl3"];
+
+ if (!layer) {
+ ERR_FAIL_MSG("Failed to create iOS OpenGLES rendering layer.");
+ }
+
+ RasterizerGLES3::make_current();
+ }
+#endif
+
bool keep_screen_on = bool(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
screen_set_keep_on(keep_screen_on);
@@ -233,20 +228,35 @@ void DisplayServerIOS::perform_event(const Ref<InputEvent> &p_event) {
Input::get_singleton()->parse_input_event(p_event);
}
-void DisplayServerIOS::touches_cancelled(int p_idx) {
+void DisplayServerIOS::touches_canceled(int p_idx) {
touch_press(p_idx, -1, -1, false, false);
}
// MARK: Keyboard
-void DisplayServerIOS::key(Key p_key, char32_t p_char, bool p_pressed) {
+void DisplayServerIOS::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed) {
Ref<InputEventKey> ev;
ev.instantiate();
ev->set_echo(false);
ev->set_pressed(p_pressed);
- ev->set_keycode(p_key);
- ev->set_physical_keycode(p_key);
- ev->set_unicode(p_char);
+ ev->set_keycode(fix_keycode(p_char, p_key));
+ if (@available(iOS 13.4, *)) {
+ if (p_key != Key::SHIFT) {
+ ev->set_shift_pressed(p_modifier & UIKeyModifierShift);
+ }
+ if (p_key != Key::CTRL) {
+ ev->set_ctrl_pressed(p_modifier & UIKeyModifierControl);
+ }
+ if (p_key != Key::ALT) {
+ ev->set_alt_pressed(p_modifier & UIKeyModifierAlternate);
+ }
+ if (p_key != Key::META) {
+ ev->set_meta_pressed(p_modifier & UIKeyModifierCommand);
+ }
+ }
+ ev->set_key_label(p_unshifted);
+ ev->set_physical_keycode(p_physical);
+ ev->set_unicode(fix_unicode(p_char));
perform_event(ev);
}
@@ -624,6 +634,10 @@ void DisplayServerIOS::virtual_keyboard_show(const String &p_existing_text, cons
cursorEnd:_convert_utf32_offset_to_utf16(p_existing_text, p_cursor_end)];
}
+bool DisplayServerIOS::is_keyboard_active() const {
+ return [AppDelegate.viewController.keyboardView isFirstResponder];
+}
+
void DisplayServerIOS::virtual_keyboard_hide() {
[AppDelegate.viewController.keyboardView resignFirstResponder];
}
@@ -670,15 +684,18 @@ void DisplayServerIOS::resize_window(CGSize viewSize) {
void DisplayServerIOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ if (context_vulkan) {
+ context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ }
#endif
}
DisplayServer::VSyncMode DisplayServerIOS::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- return context_vulkan->get_vsync_mode(p_window);
-#else
- return DisplayServer::VSYNC_ENABLED;
+ if (context_vulkan) {
+ return context_vulkan->get_vsync_mode(p_window);
+ }
#endif
+ return DisplayServer::VSYNC_ENABLED;
}
diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm
index 1c8c578bd2..4b10f95ab8 100644
--- a/platform/ios/godot_view.mm
+++ b/platform/ios/godot_view.mm
@@ -74,16 +74,20 @@ static const float earth_gravity = 9.80665;
CALayer<DisplayLayer> *layer;
if ([driverName isEqualToString:@"vulkan"]) {
+#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
+ if (@available(iOS 13, *)) {
+ layer = [GodotMetalLayer layer];
+ } else {
+ return nil;
+ }
+#else
layer = [GodotMetalLayer layer];
+#endif
} else if ([driverName isEqualToString:@"opengl3"]) {
if (@available(iOS 13, *)) {
NSLog(@"OpenGL ES is deprecated on iOS 13");
}
-#if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
- return nil;
-#else
layer = [GodotOpenGLLayer layer];
-#endif
} else {
return nil;
}
@@ -238,7 +242,7 @@ static const float earth_gravity = 9.80665;
[self.displayLink setPaused:NO];
}
- [self.renderingLayer renderDisplayLayer];
+ [self.renderingLayer startRenderDisplayLayer];
if (!self.renderer) {
return;
@@ -258,6 +262,8 @@ static const float earth_gravity = 9.80665;
[self handleMotion];
[self.renderer renderOnView:self];
+
+ [self.renderingLayer stopRenderDisplayLayer];
}
- (BOOL)canRender {
@@ -391,7 +397,7 @@ static const float earth_gravity = 9.80665;
UITouch *touch = [tlist objectAtIndex:i];
int tid = [self getTouchIDForTouch:touch];
ERR_FAIL_COND(tid == -1);
- DisplayServerIOS::get_singleton()->touches_cancelled(tid);
+ DisplayServerIOS::get_singleton()->touches_canceled(tid);
}
}
[self clearTouches];
diff --git a/platform/ios/key_mapping_ios.h b/platform/ios/key_mapping_ios.h
new file mode 100644
index 0000000000..6cc61175bb
--- /dev/null
+++ b/platform/ios/key_mapping_ios.h
@@ -0,0 +1,46 @@
+/**************************************************************************/
+/* key_mapping_ios.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef KEY_MAPPING_IOS_H
+#define KEY_MAPPING_IOS_H
+
+#include "core/os/keyboard.h"
+
+#import <UIKit/UIKit.h>
+
+class KeyMappingIOS {
+ KeyMappingIOS() {}
+
+public:
+ static void initialize();
+ static Key remap_key(CFIndex p_keycode);
+};
+
+#endif // KEY_MAPPING_IOS_H
diff --git a/platform/ios/key_mapping_ios.mm b/platform/ios/key_mapping_ios.mm
new file mode 100644
index 0000000000..c378186778
--- /dev/null
+++ b/platform/ios/key_mapping_ios.mm
@@ -0,0 +1,186 @@
+/**************************************************************************/
+/* key_mapping_ios.mm */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "key_mapping_ios.h"
+
+#include "core/templates/hash_map.h"
+
+struct HashMapHasherKeys {
+ static _FORCE_INLINE_ uint32_t hash(const Key p_key) { return hash_fmix32(static_cast<uint32_t>(p_key)); }
+ static _FORCE_INLINE_ uint32_t hash(const CFIndex p_key) { return hash_fmix32(p_key); }
+};
+
+HashMap<CFIndex, Key, HashMapHasherKeys> keyusage_map;
+
+void KeyMappingIOS::initialize() {
+ if (@available(iOS 13.4, *)) {
+ keyusage_map[UIKeyboardHIDUsageKeyboardA] = Key::A;
+ keyusage_map[UIKeyboardHIDUsageKeyboardB] = Key::B;
+ keyusage_map[UIKeyboardHIDUsageKeyboardC] = Key::C;
+ keyusage_map[UIKeyboardHIDUsageKeyboardD] = Key::D;
+ keyusage_map[UIKeyboardHIDUsageKeyboardE] = Key::E;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF] = Key::F;
+ keyusage_map[UIKeyboardHIDUsageKeyboardG] = Key::G;
+ keyusage_map[UIKeyboardHIDUsageKeyboardH] = Key::H;
+ keyusage_map[UIKeyboardHIDUsageKeyboardI] = Key::I;
+ keyusage_map[UIKeyboardHIDUsageKeyboardJ] = Key::J;
+ keyusage_map[UIKeyboardHIDUsageKeyboardK] = Key::K;
+ keyusage_map[UIKeyboardHIDUsageKeyboardL] = Key::L;
+ keyusage_map[UIKeyboardHIDUsageKeyboardM] = Key::M;
+ keyusage_map[UIKeyboardHIDUsageKeyboardN] = Key::N;
+ keyusage_map[UIKeyboardHIDUsageKeyboardO] = Key::O;
+ keyusage_map[UIKeyboardHIDUsageKeyboardP] = Key::P;
+ keyusage_map[UIKeyboardHIDUsageKeyboardQ] = Key::Q;
+ keyusage_map[UIKeyboardHIDUsageKeyboardR] = Key::R;
+ keyusage_map[UIKeyboardHIDUsageKeyboardS] = Key::S;
+ keyusage_map[UIKeyboardHIDUsageKeyboardT] = Key::T;
+ keyusage_map[UIKeyboardHIDUsageKeyboardU] = Key::U;
+ keyusage_map[UIKeyboardHIDUsageKeyboardV] = Key::V;
+ keyusage_map[UIKeyboardHIDUsageKeyboardW] = Key::W;
+ keyusage_map[UIKeyboardHIDUsageKeyboardX] = Key::X;
+ keyusage_map[UIKeyboardHIDUsageKeyboardY] = Key::Y;
+ keyusage_map[UIKeyboardHIDUsageKeyboardZ] = Key::Z;
+ keyusage_map[UIKeyboardHIDUsageKeyboard0] = Key::KEY_0;
+ keyusage_map[UIKeyboardHIDUsageKeyboard1] = Key::KEY_1;
+ keyusage_map[UIKeyboardHIDUsageKeyboard2] = Key::KEY_2;
+ keyusage_map[UIKeyboardHIDUsageKeyboard3] = Key::KEY_3;
+ keyusage_map[UIKeyboardHIDUsageKeyboard4] = Key::KEY_4;
+ keyusage_map[UIKeyboardHIDUsageKeyboard5] = Key::KEY_5;
+ keyusage_map[UIKeyboardHIDUsageKeyboard6] = Key::KEY_6;
+ keyusage_map[UIKeyboardHIDUsageKeyboard7] = Key::KEY_7;
+ keyusage_map[UIKeyboardHIDUsageKeyboard8] = Key::KEY_8;
+ keyusage_map[UIKeyboardHIDUsageKeyboard9] = Key::KEY_9;
+ keyusage_map[UIKeyboardHIDUsageKeyboardBackslash] = Key::BACKSLASH;
+ keyusage_map[UIKeyboardHIDUsageKeyboardCloseBracket] = Key::BRACKETRIGHT;
+ keyusage_map[UIKeyboardHIDUsageKeyboardComma] = Key::COMMA;
+ keyusage_map[UIKeyboardHIDUsageKeyboardEqualSign] = Key::EQUAL;
+ keyusage_map[UIKeyboardHIDUsageKeyboardHyphen] = Key::MINUS;
+ keyusage_map[UIKeyboardHIDUsageKeyboardNonUSBackslash] = Key::SECTION;
+ keyusage_map[UIKeyboardHIDUsageKeyboardNonUSPound] = Key::ASCIITILDE;
+ keyusage_map[UIKeyboardHIDUsageKeyboardOpenBracket] = Key::BRACKETLEFT;
+ keyusage_map[UIKeyboardHIDUsageKeyboardPeriod] = Key::PERIOD;
+ keyusage_map[UIKeyboardHIDUsageKeyboardQuote] = Key::QUOTEDBL;
+ keyusage_map[UIKeyboardHIDUsageKeyboardSemicolon] = Key::SEMICOLON;
+ keyusage_map[UIKeyboardHIDUsageKeyboardSeparator] = Key::SECTION;
+ keyusage_map[UIKeyboardHIDUsageKeyboardSlash] = Key::SLASH;
+ keyusage_map[UIKeyboardHIDUsageKeyboardSpacebar] = Key::SPACE;
+ keyusage_map[UIKeyboardHIDUsageKeyboardCapsLock] = Key::CAPSLOCK;
+ keyusage_map[UIKeyboardHIDUsageKeyboardLeftAlt] = Key::ALT;
+ keyusage_map[UIKeyboardHIDUsageKeyboardLeftControl] = Key::CTRL;
+ keyusage_map[UIKeyboardHIDUsageKeyboardLeftShift] = Key::SHIFT;
+ keyusage_map[UIKeyboardHIDUsageKeyboardRightAlt] = Key::ALT;
+ keyusage_map[UIKeyboardHIDUsageKeyboardRightControl] = Key::CTRL;
+ keyusage_map[UIKeyboardHIDUsageKeyboardRightShift] = Key::SHIFT;
+ keyusage_map[UIKeyboardHIDUsageKeyboardScrollLock] = Key::SCROLLLOCK;
+ keyusage_map[UIKeyboardHIDUsageKeyboardLeftArrow] = Key::LEFT;
+ keyusage_map[UIKeyboardHIDUsageKeyboardRightArrow] = Key::RIGHT;
+ keyusage_map[UIKeyboardHIDUsageKeyboardUpArrow] = Key::UP;
+ keyusage_map[UIKeyboardHIDUsageKeyboardDownArrow] = Key::DOWN;
+ keyusage_map[UIKeyboardHIDUsageKeyboardPageUp] = Key::PAGEUP;
+ keyusage_map[UIKeyboardHIDUsageKeyboardPageDown] = Key::PAGEDOWN;
+ keyusage_map[UIKeyboardHIDUsageKeyboardHome] = Key::HOME;
+ keyusage_map[UIKeyboardHIDUsageKeyboardEnd] = Key::END;
+ keyusage_map[UIKeyboardHIDUsageKeyboardDeleteForward] = Key::KEY_DELETE;
+ keyusage_map[UIKeyboardHIDUsageKeyboardDeleteOrBackspace] = Key::BACKSPACE;
+ keyusage_map[UIKeyboardHIDUsageKeyboardEscape] = Key::ESCAPE;
+ keyusage_map[UIKeyboardHIDUsageKeyboardInsert] = Key::INSERT;
+ keyusage_map[UIKeyboardHIDUsageKeyboardReturn] = Key::ENTER;
+ keyusage_map[UIKeyboardHIDUsageKeyboardTab] = Key::TAB;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF1] = Key::F1;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF2] = Key::F2;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF3] = Key::F3;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF4] = Key::F4;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF5] = Key::F5;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF6] = Key::F6;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF7] = Key::F7;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF8] = Key::F8;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF9] = Key::F9;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF10] = Key::F10;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF11] = Key::F11;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF12] = Key::F12;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF13] = Key::F13;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF14] = Key::F14;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF15] = Key::F15;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF16] = Key::F16;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF17] = Key::F17;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF18] = Key::F18;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF19] = Key::F19;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF20] = Key::F20;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF21] = Key::F21;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF22] = Key::F22;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF23] = Key::F23;
+ keyusage_map[UIKeyboardHIDUsageKeyboardF24] = Key::F24;
+ keyusage_map[UIKeyboardHIDUsageKeypad0] = Key::KP_0;
+ keyusage_map[UIKeyboardHIDUsageKeypad1] = Key::KP_1;
+ keyusage_map[UIKeyboardHIDUsageKeypad2] = Key::KP_2;
+ keyusage_map[UIKeyboardHIDUsageKeypad3] = Key::KP_3;
+ keyusage_map[UIKeyboardHIDUsageKeypad4] = Key::KP_4;
+ keyusage_map[UIKeyboardHIDUsageKeypad5] = Key::KP_5;
+ keyusage_map[UIKeyboardHIDUsageKeypad6] = Key::KP_6;
+ keyusage_map[UIKeyboardHIDUsageKeypad7] = Key::KP_7;
+ keyusage_map[UIKeyboardHIDUsageKeypad8] = Key::KP_8;
+ keyusage_map[UIKeyboardHIDUsageKeypad9] = Key::KP_9;
+ keyusage_map[UIKeyboardHIDUsageKeypadAsterisk] = Key::KP_MULTIPLY;
+ keyusage_map[UIKeyboardHIDUsageKeyboardGraveAccentAndTilde] = Key::BAR;
+ keyusage_map[UIKeyboardHIDUsageKeypadEnter] = Key::KP_ENTER;
+ keyusage_map[UIKeyboardHIDUsageKeypadHyphen] = Key::KP_SUBTRACT;
+ keyusage_map[UIKeyboardHIDUsageKeypadNumLock] = Key::NUMLOCK;
+ keyusage_map[UIKeyboardHIDUsageKeypadPeriod] = Key::KP_PERIOD;
+ keyusage_map[UIKeyboardHIDUsageKeypadPlus] = Key::KP_ADD;
+ keyusage_map[UIKeyboardHIDUsageKeypadSlash] = Key::KP_DIVIDE;
+ keyusage_map[UIKeyboardHIDUsageKeyboardPause] = Key::PAUSE;
+ keyusage_map[UIKeyboardHIDUsageKeyboardStop] = Key::STOP;
+ keyusage_map[UIKeyboardHIDUsageKeyboardMute] = Key::VOLUMEMUTE;
+ keyusage_map[UIKeyboardHIDUsageKeyboardVolumeUp] = Key::VOLUMEUP;
+ keyusage_map[UIKeyboardHIDUsageKeyboardVolumeDown] = Key::VOLUMEDOWN;
+ keyusage_map[UIKeyboardHIDUsageKeyboardFind] = Key::SEARCH;
+ keyusage_map[UIKeyboardHIDUsageKeyboardHelp] = Key::HELP;
+ keyusage_map[UIKeyboardHIDUsageKeyboardLeftGUI] = Key::META;
+ keyusage_map[UIKeyboardHIDUsageKeyboardRightGUI] = Key::META;
+ keyusage_map[UIKeyboardHIDUsageKeyboardMenu] = Key::MENU;
+ keyusage_map[UIKeyboardHIDUsageKeyboardPrintScreen] = Key::PRINT;
+ keyusage_map[UIKeyboardHIDUsageKeyboardReturnOrEnter] = Key::ENTER;
+ keyusage_map[UIKeyboardHIDUsageKeyboardSysReqOrAttention] = Key::SYSREQ;
+ keyusage_map[0x01AE] = Key::KEYBOARD; // On-screen keyboard key on smart connector keyboard.
+ keyusage_map[0x029D] = Key::GLOBE; // "Globe" key on smart connector / Mac keyboard.
+ keyusage_map[UIKeyboardHIDUsageKeyboardLANG1] = Key::JIS_EISU;
+ keyusage_map[UIKeyboardHIDUsageKeyboardLANG2] = Key::JIS_KANA;
+ }
+}
+
+Key KeyMappingIOS::remap_key(CFIndex p_keycode) {
+ if (@available(iOS 13.4, *)) {
+ const Key *key = keyusage_map.getptr(p_keycode);
+ if (key) {
+ return *key;
+ }
+ }
+ return Key::NONE;
+}
diff --git a/platform/ios/keyboard_input_view.mm b/platform/ios/keyboard_input_view.mm
index f40db48ee3..2764403d68 100644
--- a/platform/ios/keyboard_input_view.mm
+++ b/platform/ios/keyboard_input_view.mm
@@ -115,8 +115,8 @@
- (void)deleteText:(NSInteger)charactersToDelete {
for (int i = 0; i < charactersToDelete; i++) {
- DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, true);
- DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, false);
+ DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, true);
+ DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, false);
}
}
@@ -134,20 +134,10 @@
key = Key::ENTER;
} else if (character == 0x2006) {
key = Key::SPACE;
- } else if (character == U'¥') {
- key = Key::YEN;
- } else if (character == U'§') {
- key = Key::SECTION;
- } else if (character >= 0x20 && character <= 0x7E) { // ASCII.
- if (character > 0x60 && character < 0x7B) { // Lowercase ASCII.
- key = (Key)(character - 32);
- } else {
- key = (Key)character;
- }
}
- DisplayServerIOS::get_singleton()->key(key, character, true);
- DisplayServerIOS::get_singleton()->key(key, character, false);
+ DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, true);
+ DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, false);
}
}
diff --git a/platform/ios/view_controller.mm b/platform/ios/view_controller.mm
index b787ed6709..a5aba201d7 100644
--- a/platform/ios/view_controller.mm
+++ b/platform/ios/view_controller.mm
@@ -33,6 +33,7 @@
#include "display_server_ios.h"
#import "godot_view.h"
#import "godot_view_renderer.h"
+#import "key_mapping_ios.h"
#import "keyboard_input_view.h"
#include "os_ios.h"
@@ -54,6 +55,64 @@
return (GodotView *)self.view;
}
+- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
+ [super pressesBegan:presses withEvent:event];
+
+ if (!DisplayServerIOS::get_singleton() || DisplayServerIOS::get_singleton()->is_keyboard_active()) {
+ return;
+ }
+ if (@available(iOS 13.4, *)) {
+ for (UIPress *press in presses) {
+ String u32lbl = String::utf8([press.key.charactersIgnoringModifiers UTF8String]);
+ String u32text = String::utf8([press.key.characters UTF8String]);
+ Key key = KeyMappingIOS::remap_key(press.key.keyCode);
+
+ if (press.key.keyCode == 0 && u32text.is_empty() && u32lbl.is_empty()) {
+ continue;
+ }
+
+ char32_t us = 0;
+ if (!u32lbl.is_empty() && !u32lbl.begins_with("UIKey")) {
+ us = u32lbl[0];
+ }
+
+ if (!u32text.is_empty() && !u32text.begins_with("UIKey")) {
+ for (int i = 0; i < u32text.length(); i++) {
+ const char32_t c = u32text[i];
+ DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), c, fix_key_label(us, key), key, press.key.modifierFlags, true);
+ }
+ } else {
+ DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, true);
+ }
+ }
+ }
+}
+
+- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
+ [super pressesEnded:presses withEvent:event];
+
+ if (!DisplayServerIOS::get_singleton() || DisplayServerIOS::get_singleton()->is_keyboard_active()) {
+ return;
+ }
+ if (@available(iOS 13.4, *)) {
+ for (UIPress *press in presses) {
+ String u32lbl = String::utf8([press.key.charactersIgnoringModifiers UTF8String]);
+ Key key = KeyMappingIOS::remap_key(press.key.keyCode);
+
+ if (press.key.keyCode == 0 && u32lbl.is_empty()) {
+ continue;
+ }
+
+ char32_t us = 0;
+ if (!u32lbl.is_empty() && !u32lbl.begins_with("UIKey")) {
+ us = u32lbl[0];
+ }
+
+ DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, false);
+ }
+ }
+}
+
- (void)loadView {
GodotView *view = [[GodotView alloc] init];
GodotViewRenderer *renderer = [[GodotViewRenderer alloc] init];
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 1830a7b39b..e2d29a14d3 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -192,6 +192,7 @@ def configure(env: "Environment"):
env.ParseConfig("pkg-config xrandr --cflags")
env.ParseConfig("pkg-config xrender --cflags")
env.ParseConfig("pkg-config xi --cflags")
+ env.ParseConfig("pkg-config xkbcommon --cflags")
if env["touch"]:
env.Append(CPPDEFINES=["TOUCH_ENABLED"])
@@ -271,7 +272,7 @@ def configure(env: "Environment"):
env.Append(LIBS=["miniupnpc"])
# On Linux wchar_t should be 32-bits
- # 16-bit library shouldn't be required due to compiler optimisations
+ # 16-bit library shouldn't be required due to compiler optimizations
if not env["builtin_pcre2"]:
env.ParseConfig("pkg-config libpcre2-32 --cflags --libs")
diff --git a/platform/linuxbsd/x11/SCsub b/platform/linuxbsd/x11/SCsub
index 8b2e2aabe4..d869ce9ecc 100644
--- a/platform/linuxbsd/x11/SCsub
+++ b/platform/linuxbsd/x11/SCsub
@@ -9,6 +9,7 @@ source_files = [
"dynwrappers/xcursor-so_wrap.c",
"dynwrappers/xinerama-so_wrap.c",
"dynwrappers/xinput2-so_wrap.c",
+ "dynwrappers/xkbcommon-so_wrap.c",
"dynwrappers/xrandr-so_wrap.c",
"dynwrappers/xrender-so_wrap.c",
"dynwrappers/xext-so_wrap.c",
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index d4f82cc81e..9971fe8c79 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -1324,6 +1324,8 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
}
#endif
+ XDestroyWindow(x11_display, wd.x11_xim_window);
+
XUnmapWindow(x11_display, wd.x11_window);
XDestroyWindow(x11_display, wd.x11_window);
if (wd.xic) {
@@ -2490,24 +2492,39 @@ void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_win
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
- wd.im_active = p_active;
-
if (!wd.xic) {
return;
}
+ if (!wd.focused) {
+ return;
+ }
// Block events polling while changing input focus
// because it triggers some event polling internally.
if (p_active) {
- {
- MutexLock mutex_lock(events_mutex);
- XSetICFocus(wd.xic);
+ MutexLock mutex_lock(events_mutex);
+
+ wd.ime_active = true;
+
+ XMapWindow(x11_display, wd.x11_xim_window);
+
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd.x11_xim_window, &xwa);
+ if (xwa.map_state == IsViewable) {
+ XSetInputFocus(x11_display, wd.x11_xim_window, RevertToPointerRoot, CurrentTime);
}
- window_set_ime_position(wd.im_position, p_window);
+ XSetICFocus(wd.xic);
} else {
MutexLock mutex_lock(events_mutex);
XUnsetICFocus(wd.xic);
+ XUnmapWindow(x11_display, wd.x11_xim_window);
+ wd.ime_active = false;
+
+ im_text = String();
+ im_selection = Vector2i();
}
+ OS_Unix::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
}
void DisplayServerX11::window_set_ime_position(const Point2i &p_pos, WindowID p_window) {
@@ -2516,25 +2533,29 @@ void DisplayServerX11::window_set_ime_position(const Point2i &p_pos, WindowID p_
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
- wd.im_position = p_pos;
-
if (!wd.xic) {
return;
}
+ if (!wd.focused) {
+ return;
+ }
- ::XPoint spot;
- spot.x = short(p_pos.x);
- spot.y = short(p_pos.y);
- XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, nullptr);
-
- {
- // Block events polling during this call
- // because it triggers some event polling internally.
- MutexLock mutex_lock(events_mutex);
- XSetICValues(wd.xic, XNPreeditAttributes, preedit_attr, nullptr);
+ if (wd.ime_active) {
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd.x11_xim_window, &xwa);
+ if (xwa.map_state == IsViewable) {
+ XMoveWindow(x11_display, wd.x11_xim_window, p_pos.x, p_pos.y);
+ }
}
+}
+
+Point2i DisplayServerX11::ime_get_selection() const {
+ return im_selection;
+}
- XFree(preedit_attr);
+String DisplayServerX11::ime_get_text() const {
+ return im_text;
}
void DisplayServerX11::cursor_set_shape(CursorShape p_shape) {
@@ -2872,6 +2893,16 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
// X11 functions don't know what const is
XKeyEvent *xkeyevent = p_event;
+ if (wd.ime_in_progress) {
+ return;
+ }
+ if (wd.ime_suppress_next_keyup) {
+ wd.ime_suppress_next_keyup = false;
+ if (xkeyevent->type != KeyPress) {
+ return;
+ }
+ }
+
// This code was pretty difficult to write.
// The docs stink and every toolkit seems to
// do it in a different way.
@@ -2895,12 +2926,18 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
KeySym keysym_unicode = 0; // keysym used to find unicode
// XLookupString returns keysyms usable as nice keycodes.
- char str[256 + 1];
+ char str[256] = {};
XKeyEvent xkeyevent_no_mod = *xkeyevent;
xkeyevent_no_mod.state &= ~ShiftMask;
xkeyevent_no_mod.state &= ~ControlMask;
- XLookupString(xkeyevent, str, 256, &keysym_unicode, nullptr);
- XLookupString(&xkeyevent_no_mod, nullptr, 0, &keysym_keycode, nullptr);
+ XLookupString(xkeyevent, str, 255, &keysym_unicode, nullptr);
+
+ String keysym;
+ if (xkb_keysym_to_utf32 && xkb_keysym_to_upper) {
+ KeySym keysym_unicode_nm = 0; // keysym used to find unicode
+ XLookupString(&xkeyevent_no_mod, nullptr, 0, &keysym_unicode_nm, nullptr);
+ keysym = String::chr(xkb_keysym_to_utf32(xkb_keysym_to_upper(keysym_unicode_nm)));
+ }
// Meanwhile, XLookupString returns keysyms useful for unicode.
@@ -2950,13 +2987,18 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
_get_key_modifier_state(xkeyevent->state, k);
k->set_window_id(p_window);
- k->set_unicode(tmp[i]);
-
k->set_pressed(keypress);
k->set_keycode(keycode);
-
- k->set_physical_keycode((Key)physical_keycode);
+ k->set_physical_keycode(physical_keycode);
+ if (!keysym.is_empty()) {
+ k->set_key_label(fix_key_label(keysym[0], keycode));
+ } else {
+ k->set_key_label(keycode);
+ }
+ if (keypress) {
+ k->set_unicode(fix_unicode(tmp[i]));
+ }
k->set_echo(false);
@@ -2999,7 +3041,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
// KeyMappingX11 also translates keysym to unicode.
// It does a binary search on a table to translate
// most properly.
- unsigned int unicode = keysym_unicode > 0 ? KeyMappingX11::get_unicode_from_keysym(keysym_unicode) : 0;
+ char32_t unicode = keysym_unicode > 0 ? KeyMappingX11::get_unicode_from_keysym(keysym_unicode) : 0;
/* Phase 4, determine if event must be filtered */
@@ -3085,7 +3127,14 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
k->set_keycode(keycode);
k->set_physical_keycode((Key)physical_keycode);
- k->set_unicode(unicode);
+ if (!keysym.is_empty()) {
+ k->set_key_label(fix_key_label(keysym[0], keycode));
+ } else {
+ k->set_key_label(keycode);
+ }
+ if (keypress) {
+ k->set_unicode(fix_unicode(unicode));
+ }
k->set_echo(p_echo);
if (k->get_keycode() == Key::BACKTAB) {
@@ -3237,6 +3286,80 @@ void DisplayServerX11::_handle_selection_request_event(XSelectionRequestEvent *p
XFlush(x11_display);
}
+int DisplayServerX11::_xim_preedit_start_callback(::XIM xim, ::XPointer client_data,
+ ::XPointer call_data) {
+ DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
+ WindowID window_id = ds->_get_focused_window_or_popup();
+ WindowData &wd = ds->windows[window_id];
+ if (wd.ime_active) {
+ wd.ime_in_progress = true;
+ }
+
+ return -1; // Allow preedit strings of any length (no limit).
+}
+
+void DisplayServerX11::_xim_preedit_done_callback(::XIM xim, ::XPointer client_data,
+ ::XPointer call_data) {
+ DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
+ WindowID window_id = ds->_get_focused_window_or_popup();
+ WindowData &wd = ds->windows[window_id];
+ if (wd.ime_active) {
+ wd.ime_in_progress = false;
+ wd.ime_suppress_next_keyup = true;
+ }
+}
+
+void DisplayServerX11::_xim_preedit_draw_callback(::XIM xim, ::XPointer client_data,
+ ::XIMPreeditDrawCallbackStruct *call_data) {
+ DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
+ WindowID window_id = ds->_get_focused_window_or_popup();
+ WindowData &wd = ds->windows[window_id];
+
+ XIMText *xim_text = call_data->text;
+ if (xim_text != nullptr) {
+ String changed_text;
+ if (xim_text->encoding_is_wchar) {
+ changed_text = String(xim_text->string.wide_char);
+ } else {
+ changed_text.parse_utf8(xim_text->string.multi_byte);
+ }
+
+ if (call_data->chg_length < 0) {
+ ds->im_text = ds->im_text.substr(0, call_data->chg_first) + changed_text;
+ } else {
+ ds->im_text = ds->im_text.substr(0, call_data->chg_first) + changed_text + ds->im_text.substr(call_data->chg_length);
+ }
+
+ // Find the start and end of the selection.
+ int start = 0, count = 0;
+ for (int i = 0; i < xim_text->length; i++) {
+ if (xim_text->feedback[i] & XIMReverse) {
+ if (count == 0) {
+ start = i;
+ count = 1;
+ } else {
+ count++;
+ }
+ }
+ }
+ if (count > 0) {
+ ds->im_selection = Point2i(start + call_data->chg_first, count);
+ } else {
+ ds->im_selection = Point2i(call_data->caret, 0);
+ }
+ } else {
+ ds->im_text = String();
+ ds->im_selection = Point2i();
+ }
+ if (wd.ime_active) {
+ OS_Unix::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
+ }
+}
+
+void DisplayServerX11::_xim_preedit_caret_callback(::XIM xim, ::XPointer client_data,
+ ::XIMPreeditCaretCallbackStruct *call_data) {
+}
+
void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data,
::XPointer call_data) {
WARN_PRINT("Input method stopped");
@@ -3286,10 +3409,6 @@ void DisplayServerX11::_window_changed(XEvent *event) {
if (new_rect == Rect2i(wd.position, wd.size)) {
return;
}
- if (wd.xic) {
- // Not portable.
- window_set_ime_position(Point2(0, 1));
- }
wd.position = new_rect.position;
wd.size = new_rect.size;
@@ -3637,6 +3756,7 @@ void DisplayServerX11::process_events() {
continue;
}
+ bool ime_window_event = false;
WindowID window_id = MAIN_WINDOW_ID;
// Assign the event to the relevant window
@@ -3645,6 +3765,11 @@ void DisplayServerX11::process_events() {
window_id = E.key;
break;
}
+ if (event.xany.window == E.value.x11_xim_window) {
+ window_id = E.key;
+ ime_window_event = true;
+ break;
+ }
}
if (XGetEventData(x11_display, &event.xcookie)) {
@@ -3659,6 +3784,9 @@ void DisplayServerX11::process_events() {
_refresh_device_info();
} break;
case XI_RawMotion: {
+ if (ime_window_event) {
+ break;
+ }
XIRawEvent *raw_event = (XIRawEvent *)event_data;
int device_id = raw_event->sourceid;
@@ -3761,6 +3889,9 @@ void DisplayServerX11::process_events() {
#ifdef TOUCH_ENABLED
case XI_TouchBegin:
case XI_TouchEnd: {
+ if (ime_window_event) {
+ break;
+ }
bool is_begin = event_data->evtype == XI_TouchBegin;
Ref<InputEventScreenTouch> st;
@@ -3791,6 +3922,9 @@ void DisplayServerX11::process_events() {
} break;
case XI_TouchUpdate: {
+ if (ime_window_event) {
+ break;
+ }
HashMap<int, Vector2>::Iterator curr_pos_elem = xi.state.find(index);
if (!curr_pos_elem) { // Defensive
break;
@@ -3817,6 +3951,9 @@ void DisplayServerX11::process_events() {
switch (event.type) {
case MapNotify: {
DEBUG_LOG_X11("[%u] MapNotify window=%lu (%u) \n", frame, event.xmap.window, window_id);
+ if (ime_window_event) {
+ break;
+ }
const WindowData &wd = windows[window_id];
@@ -3837,6 +3974,9 @@ void DisplayServerX11::process_events() {
case Expose: {
DEBUG_LOG_X11("[%u] Expose window=%lu (%u), count='%u' \n", frame, event.xexpose.window, window_id, event.xexpose.count);
+ if (ime_window_event) {
+ break;
+ }
windows[window_id].fullscreen = _window_fullscreen_check(window_id);
@@ -3845,18 +3985,27 @@ void DisplayServerX11::process_events() {
case NoExpose: {
DEBUG_LOG_X11("[%u] NoExpose drawable=%lu (%u) \n", frame, event.xnoexpose.drawable, window_id);
+ if (ime_window_event) {
+ break;
+ }
windows[window_id].minimized = true;
} break;
case VisibilityNotify: {
DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
+ if (ime_window_event) {
+ break;
+ }
windows[window_id].minimized = _window_minimize_check(window_id);
} break;
case LeaveNotify: {
DEBUG_LOG_X11("[%u] LeaveNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
+ if (ime_window_event) {
+ break;
+ }
if (!mouse_mode_grab) {
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
@@ -3866,6 +4015,9 @@ void DisplayServerX11::process_events() {
case EnterNotify: {
DEBUG_LOG_X11("[%u] EnterNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
+ if (ime_window_event) {
+ break;
+ }
if (!mouse_mode_grab) {
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
@@ -3874,18 +4026,14 @@ void DisplayServerX11::process_events() {
case FocusIn: {
DEBUG_LOG_X11("[%u] FocusIn window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode);
+ if (ime_window_event) {
+ break;
+ }
WindowData &wd = windows[window_id];
last_focused_window = window_id;
wd.focused = true;
- if (wd.xic) {
- // Block events polling while changing input focus
- // because it triggers some event polling internally.
- MutexLock mutex_lock(events_mutex);
- XSetICFocus(wd.xic);
- }
-
// Keep track of focus order for overlapping windows.
static unsigned int focus_order = 0;
wd.focus_order = ++focus_order;
@@ -3925,17 +4073,20 @@ void DisplayServerX11::process_events() {
case FocusOut: {
DEBUG_LOG_X11("[%u] FocusOut window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode);
-
WindowData &wd = windows[window_id];
-
- wd.focused = false;
-
- if (wd.xic) {
- // Block events polling while changing input focus
- // because it triggers some event polling internally.
+ if (wd.ime_active && event.xfocus.detail == NotifyInferior) {
+ break;
+ }
+ if (wd.ime_active) {
MutexLock mutex_lock(events_mutex);
XUnsetICFocus(wd.xic);
+ XUnmapWindow(x11_display, wd.x11_xim_window);
+ wd.ime_active = false;
+ im_text = String();
+ im_selection = Vector2i();
+ OS_Unix::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
}
+ wd.focused = false;
Input::get_singleton()->release_pressed_events();
_send_window_event(wd, WINDOW_EVENT_FOCUS_OUT);
@@ -3971,6 +4122,9 @@ void DisplayServerX11::process_events() {
case ConfigureNotify: {
DEBUG_LOG_X11("[%u] ConfigureNotify window=%lu (%u), event=%lu, above=%lu, override_redirect=%u \n", frame, event.xconfigure.window, window_id, event.xconfigure.event, event.xconfigure.above, event.xconfigure.override_redirect);
+ if (event.xconfigure.window == windows[window_id].x11_xim_window) {
+ break;
+ }
const WindowData &wd = windows[window_id];
@@ -3990,6 +4144,9 @@ void DisplayServerX11::process_events() {
case ButtonPress:
case ButtonRelease: {
+ if (ime_window_event) {
+ break;
+ }
/* exit in case of a mouse button press */
last_timestamp = event.xbutton.time;
if (mouse_mode == MOUSE_MODE_CAPTURED) {
@@ -4088,6 +4245,9 @@ void DisplayServerX11::process_events() {
} break;
case MotionNotify: {
+ if (ime_window_event) {
+ break;
+ }
// The X11 API requires filtering one-by-one through the motion
// notify events, in order to figure out which event is the one
// generated by warping the mouse pointer.
@@ -4248,7 +4408,9 @@ void DisplayServerX11::process_events() {
} break;
case SelectionNotify:
-
+ if (ime_window_event) {
+ break;
+ }
if (event.xselection.target == requested) {
Property p = _read_property(x11_display, windows[window_id].x11_window, XInternAtom(x11_display, "PRIMARY", 0));
@@ -4283,7 +4445,9 @@ void DisplayServerX11::process_events() {
break;
case ClientMessage:
-
+ if (ime_window_event) {
+ break;
+ }
if ((unsigned int)event.xclient.data.l[0] == (unsigned int)wm_delete) {
_send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
}
@@ -4692,6 +4856,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
{
wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), win_rect.position.x, win_rect.position.y, win_rect.size.width > 0 ? win_rect.size.width : 1, win_rect.size.height > 0 ? win_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes);
+ wd.x11_xim_window = XCreateWindow(x11_display, wd.x11_window, 0, 0, 1, 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes);
// Enable receiving notification when the window is initialized (MapNotify)
// so the focus can be set at the right time.
@@ -4763,7 +4928,50 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
// because it triggers some event polling internally.
MutexLock mutex_lock(events_mutex);
- wd.xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, wd.x11_window, XNFocusWindow, wd.x11_window, (char *)nullptr);
+ // Force on-the-spot for the over-the-spot style.
+ if ((xim_style & XIMPreeditPosition) != 0) {
+ xim_style &= ~XIMPreeditPosition;
+ xim_style |= XIMPreeditCallbacks;
+ }
+ if ((xim_style & XIMPreeditCallbacks) != 0) {
+ ::XIMCallback preedit_start_callback;
+ preedit_start_callback.client_data = (::XPointer)(this);
+ preedit_start_callback.callback = (::XIMProc)(void *)(_xim_preedit_start_callback);
+
+ ::XIMCallback preedit_done_callback;
+ preedit_done_callback.client_data = (::XPointer)(this);
+ preedit_done_callback.callback = (::XIMProc)(_xim_preedit_done_callback);
+
+ ::XIMCallback preedit_draw_callback;
+ preedit_draw_callback.client_data = (::XPointer)(this);
+ preedit_draw_callback.callback = (::XIMProc)(_xim_preedit_draw_callback);
+
+ ::XIMCallback preedit_caret_callback;
+ preedit_caret_callback.client_data = (::XPointer)(this);
+ preedit_caret_callback.callback = (::XIMProc)(_xim_preedit_caret_callback);
+
+ ::XVaNestedList preedit_attributes = XVaCreateNestedList(0,
+ XNPreeditStartCallback, &preedit_start_callback,
+ XNPreeditDoneCallback, &preedit_done_callback,
+ XNPreeditDrawCallback, &preedit_draw_callback,
+ XNPreeditCaretCallback, &preedit_caret_callback,
+ (char *)nullptr);
+
+ wd.xic = XCreateIC(xim,
+ XNInputStyle, xim_style,
+ XNClientWindow, wd.x11_xim_window,
+ XNFocusWindow, wd.x11_xim_window,
+ XNPreeditAttributes, preedit_attributes,
+ (char *)nullptr);
+ XFree(preedit_attributes);
+ } else {
+ wd.xic = XCreateIC(xim,
+ XNInputStyle, xim_style,
+ XNClientWindow, wd.x11_xim_window,
+ XNFocusWindow, wd.x11_xim_window,
+ (char *)nullptr);
+ }
+
if (XGetICValues(wd.xic, XNFilterEvents, &im_event_mask, nullptr) != nullptr) {
WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value");
XDestroyIC(wd.xic);
@@ -4854,7 +5062,66 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
return id;
}
+static bool _is_xim_style_supported(const ::XIMStyle &p_style) {
+ const ::XIMStyle supported_preedit = XIMPreeditCallbacks | XIMPreeditPosition | XIMPreeditNothing | XIMPreeditNone;
+ const ::XIMStyle supported_status = XIMStatusNothing | XIMStatusNone;
+
+ // Check preedit style is supported
+ if ((p_style & supported_preedit) == 0) {
+ return false;
+ }
+
+ // Check status style is supported
+ if ((p_style & supported_status) == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+static ::XIMStyle _get_best_xim_style(const ::XIMStyle &p_style_a, const ::XIMStyle &p_style_b) {
+ if (p_style_a == 0) {
+ return p_style_b;
+ }
+ if (p_style_b == 0) {
+ return p_style_a;
+ }
+
+ const ::XIMStyle preedit = XIMPreeditArea | XIMPreeditCallbacks | XIMPreeditPosition | XIMPreeditNothing | XIMPreeditNone;
+ const ::XIMStyle status = XIMStatusArea | XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone;
+
+ ::XIMStyle a = p_style_a & preedit;
+ ::XIMStyle b = p_style_b & preedit;
+ if (a != b) {
+ // Compare preedit styles.
+ if ((a | b) & XIMPreeditCallbacks) {
+ return a == XIMPreeditCallbacks ? p_style_a : p_style_b;
+ } else if ((a | b) & XIMPreeditPosition) {
+ return a == XIMPreeditPosition ? p_style_a : p_style_b;
+ } else if ((a | b) & XIMPreeditArea) {
+ return a == XIMPreeditArea ? p_style_a : p_style_b;
+ } else if ((a | b) & XIMPreeditNothing) {
+ return a == XIMPreeditNothing ? p_style_a : p_style_b;
+ }
+ } else {
+ // Preedit styles are the same, compare status styles.
+ a = p_style_a & status;
+ b = p_style_b & status;
+
+ if ((a | b) & XIMStatusCallbacks) {
+ return a == XIMStatusCallbacks ? p_style_a : p_style_b;
+ } else if ((a | b) & XIMStatusArea) {
+ return a == XIMStatusArea ? p_style_a : p_style_b;
+ } else if ((a | b) & XIMStatusNothing) {
+ return a == XIMStatusNothing ? p_style_a : p_style_b;
+ }
+ }
+ return p_style_a;
+}
+
DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
+ KeyMappingX11::initialize();
+
#ifdef DEBUG_ENABLED
int dylibloader_verbose = 1;
#else
@@ -4870,6 +5137,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
ERR_FAIL_MSG("Can't load XCursor dynamically.");
}
+ initialize_xkbcommon(dylibloader_verbose); // Optional, used for key_label.
+
if (initialize_xext(dylibloader_verbose) != 0) {
r_error = ERR_UNAVAILABLE;
ERR_FAIL_MSG("Can't load Xext dynamically.");
@@ -5001,11 +5270,13 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
if (xim_styles) {
xim_style = 0L;
for (int i = 0; i < xim_styles->count_styles; i++) {
- if (xim_styles->supported_styles[i] ==
- (XIMPreeditNothing | XIMStatusNothing)) {
- xim_style = xim_styles->supported_styles[i];
- break;
+ const ::XIMStyle &style = xim_styles->supported_styles[i];
+
+ if (!_is_xim_style_supported(style)) {
+ continue;
}
+
+ xim_style = _get_best_xim_style(xim_style, style);
}
XFree(xim_styles);
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 437766d953..290e3d6a5e 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -75,6 +75,7 @@
#include "dynwrappers/xext-so_wrap.h"
#include "dynwrappers/xinerama-so_wrap.h"
#include "dynwrappers/xinput2-so_wrap.h"
+#include "dynwrappers/xkbcommon-so_wrap.h"
#include "dynwrappers/xrandr-so_wrap.h"
#include "dynwrappers/xrender-so_wrap.h"
@@ -135,14 +136,16 @@ class DisplayServerX11 : public DisplayServer {
struct WindowData {
Window x11_window;
+ Window x11_xim_window;
::XIC xic;
+ bool ime_active = false;
+ bool ime_in_progress = false;
+ bool ime_suppress_next_keyup = false;
Size2i min_size;
Size2i max_size;
Point2i position;
Size2i size;
- Point2i im_position;
- bool im_active = false;
Callable rect_changed_callback;
Callable event_callback;
Callable input_event_callback;
@@ -178,6 +181,9 @@ class DisplayServerX11 : public DisplayServer {
unsigned int focus_order = 0;
};
+ Point2i im_selection;
+ String im_text;
+
HashMap<WindowID, WindowData> windows;
unsigned int last_mouse_monitor_mask = 0;
@@ -200,6 +206,15 @@ class DisplayServerX11 : public DisplayServer {
::Time last_keyrelease_time = 0;
::XIM xim;
::XIMStyle xim_style;
+
+ static int _xim_preedit_start_callback(::XIM xim, ::XPointer client_data,
+ ::XPointer call_data);
+ static void _xim_preedit_done_callback(::XIM xim, ::XPointer client_data,
+ ::XPointer call_data);
+ static void _xim_preedit_draw_callback(::XIM xim, ::XPointer client_data,
+ ::XIMPreeditDrawCallbackStruct *call_data);
+ static void _xim_preedit_caret_callback(::XIM xim, ::XPointer client_data,
+ ::XIMPreeditCaretCallbackStruct *call_data);
static void _xim_destroy_callback(::XIM im, ::XPointer client_data,
::XPointer call_data);
@@ -433,6 +448,9 @@ public:
virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual Point2i ime_get_selection() const override;
+ virtual String ime_get_text() const override;
+
virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
diff --git a/platform/linuxbsd/x11/dynwrappers/xkbcommon-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xkbcommon-so_wrap.c
new file mode 100644
index 0000000000..e0de1de5ad
--- /dev/null
+++ b/platform/linuxbsd/x11/dynwrappers/xkbcommon-so_wrap.c
@@ -0,0 +1,859 @@
+// This file is generated. Do not edit!
+// see https://github.com/hpvb/dynload-wrapper for details
+// generated by ./generate-wrapper.py 0.3 on 2023-01-23 14:25:23
+// flags: ./generate-wrapper.py --include /usr/include/xkbcommon/xkbcommon.h --sys-include <xkbcommon/xkbcommon.h> --soname libxkbcommon.so.0 --init-name xkbcommon --output-header xkbcommon-so_wrap.h --output-implementation xkbcommon-so_wrap.c
+//
+#include <stdint.h>
+
+#define xkb_keysym_get_name xkb_keysym_get_name_dylibloader_orig_xkbcommon
+#define xkb_keysym_from_name xkb_keysym_from_name_dylibloader_orig_xkbcommon
+#define xkb_keysym_to_utf8 xkb_keysym_to_utf8_dylibloader_orig_xkbcommon
+#define xkb_keysym_to_utf32 xkb_keysym_to_utf32_dylibloader_orig_xkbcommon
+#define xkb_utf32_to_keysym xkb_utf32_to_keysym_dylibloader_orig_xkbcommon
+#define xkb_keysym_to_upper xkb_keysym_to_upper_dylibloader_orig_xkbcommon
+#define xkb_keysym_to_lower xkb_keysym_to_lower_dylibloader_orig_xkbcommon
+#define xkb_context_new xkb_context_new_dylibloader_orig_xkbcommon
+#define xkb_context_ref xkb_context_ref_dylibloader_orig_xkbcommon
+#define xkb_context_unref xkb_context_unref_dylibloader_orig_xkbcommon
+#define xkb_context_set_user_data xkb_context_set_user_data_dylibloader_orig_xkbcommon
+#define xkb_context_get_user_data xkb_context_get_user_data_dylibloader_orig_xkbcommon
+#define xkb_context_include_path_append xkb_context_include_path_append_dylibloader_orig_xkbcommon
+#define xkb_context_include_path_append_default xkb_context_include_path_append_default_dylibloader_orig_xkbcommon
+#define xkb_context_include_path_reset_defaults xkb_context_include_path_reset_defaults_dylibloader_orig_xkbcommon
+#define xkb_context_include_path_clear xkb_context_include_path_clear_dylibloader_orig_xkbcommon
+#define xkb_context_num_include_paths xkb_context_num_include_paths_dylibloader_orig_xkbcommon
+#define xkb_context_include_path_get xkb_context_include_path_get_dylibloader_orig_xkbcommon
+#define xkb_context_set_log_level xkb_context_set_log_level_dylibloader_orig_xkbcommon
+#define xkb_context_get_log_level xkb_context_get_log_level_dylibloader_orig_xkbcommon
+#define xkb_context_set_log_verbosity xkb_context_set_log_verbosity_dylibloader_orig_xkbcommon
+#define xkb_context_get_log_verbosity xkb_context_get_log_verbosity_dylibloader_orig_xkbcommon
+#define xkb_context_set_log_fn xkb_context_set_log_fn_dylibloader_orig_xkbcommon
+#define xkb_keymap_new_from_names xkb_keymap_new_from_names_dylibloader_orig_xkbcommon
+#define xkb_keymap_new_from_file xkb_keymap_new_from_file_dylibloader_orig_xkbcommon
+#define xkb_keymap_new_from_string xkb_keymap_new_from_string_dylibloader_orig_xkbcommon
+#define xkb_keymap_new_from_buffer xkb_keymap_new_from_buffer_dylibloader_orig_xkbcommon
+#define xkb_keymap_ref xkb_keymap_ref_dylibloader_orig_xkbcommon
+#define xkb_keymap_unref xkb_keymap_unref_dylibloader_orig_xkbcommon
+#define xkb_keymap_get_as_string xkb_keymap_get_as_string_dylibloader_orig_xkbcommon
+#define xkb_keymap_min_keycode xkb_keymap_min_keycode_dylibloader_orig_xkbcommon
+#define xkb_keymap_max_keycode xkb_keymap_max_keycode_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_for_each xkb_keymap_key_for_each_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_get_name xkb_keymap_key_get_name_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_by_name xkb_keymap_key_by_name_dylibloader_orig_xkbcommon
+#define xkb_keymap_num_mods xkb_keymap_num_mods_dylibloader_orig_xkbcommon
+#define xkb_keymap_mod_get_name xkb_keymap_mod_get_name_dylibloader_orig_xkbcommon
+#define xkb_keymap_mod_get_index xkb_keymap_mod_get_index_dylibloader_orig_xkbcommon
+#define xkb_keymap_num_layouts xkb_keymap_num_layouts_dylibloader_orig_xkbcommon
+#define xkb_keymap_layout_get_name xkb_keymap_layout_get_name_dylibloader_orig_xkbcommon
+#define xkb_keymap_layout_get_index xkb_keymap_layout_get_index_dylibloader_orig_xkbcommon
+#define xkb_keymap_num_leds xkb_keymap_num_leds_dylibloader_orig_xkbcommon
+#define xkb_keymap_led_get_name xkb_keymap_led_get_name_dylibloader_orig_xkbcommon
+#define xkb_keymap_led_get_index xkb_keymap_led_get_index_dylibloader_orig_xkbcommon
+#define xkb_keymap_num_layouts_for_key xkb_keymap_num_layouts_for_key_dylibloader_orig_xkbcommon
+#define xkb_keymap_num_levels_for_key xkb_keymap_num_levels_for_key_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_get_mods_for_level xkb_keymap_key_get_mods_for_level_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_get_syms_by_level xkb_keymap_key_get_syms_by_level_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_repeats xkb_keymap_key_repeats_dylibloader_orig_xkbcommon
+#define xkb_state_new xkb_state_new_dylibloader_orig_xkbcommon
+#define xkb_state_ref xkb_state_ref_dylibloader_orig_xkbcommon
+#define xkb_state_unref xkb_state_unref_dylibloader_orig_xkbcommon
+#define xkb_state_get_keymap xkb_state_get_keymap_dylibloader_orig_xkbcommon
+#define xkb_state_update_key xkb_state_update_key_dylibloader_orig_xkbcommon
+#define xkb_state_update_mask xkb_state_update_mask_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_syms xkb_state_key_get_syms_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_utf8 xkb_state_key_get_utf8_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_utf32 xkb_state_key_get_utf32_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_one_sym xkb_state_key_get_one_sym_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_layout xkb_state_key_get_layout_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_level xkb_state_key_get_level_dylibloader_orig_xkbcommon
+#define xkb_state_serialize_mods xkb_state_serialize_mods_dylibloader_orig_xkbcommon
+#define xkb_state_serialize_layout xkb_state_serialize_layout_dylibloader_orig_xkbcommon
+#define xkb_state_mod_name_is_active xkb_state_mod_name_is_active_dylibloader_orig_xkbcommon
+#define xkb_state_mod_names_are_active xkb_state_mod_names_are_active_dylibloader_orig_xkbcommon
+#define xkb_state_mod_index_is_active xkb_state_mod_index_is_active_dylibloader_orig_xkbcommon
+#define xkb_state_mod_indices_are_active xkb_state_mod_indices_are_active_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_consumed_mods2 xkb_state_key_get_consumed_mods2_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_consumed_mods xkb_state_key_get_consumed_mods_dylibloader_orig_xkbcommon
+#define xkb_state_mod_index_is_consumed2 xkb_state_mod_index_is_consumed2_dylibloader_orig_xkbcommon
+#define xkb_state_mod_index_is_consumed xkb_state_mod_index_is_consumed_dylibloader_orig_xkbcommon
+#define xkb_state_mod_mask_remove_consumed xkb_state_mod_mask_remove_consumed_dylibloader_orig_xkbcommon
+#define xkb_state_layout_name_is_active xkb_state_layout_name_is_active_dylibloader_orig_xkbcommon
+#define xkb_state_layout_index_is_active xkb_state_layout_index_is_active_dylibloader_orig_xkbcommon
+#define xkb_state_led_name_is_active xkb_state_led_name_is_active_dylibloader_orig_xkbcommon
+#define xkb_state_led_index_is_active xkb_state_led_index_is_active_dylibloader_orig_xkbcommon
+#include <xkbcommon/xkbcommon.h>
+#undef xkb_keysym_get_name
+#undef xkb_keysym_from_name
+#undef xkb_keysym_to_utf8
+#undef xkb_keysym_to_utf32
+#undef xkb_utf32_to_keysym
+#undef xkb_keysym_to_upper
+#undef xkb_keysym_to_lower
+#undef xkb_context_new
+#undef xkb_context_ref
+#undef xkb_context_unref
+#undef xkb_context_set_user_data
+#undef xkb_context_get_user_data
+#undef xkb_context_include_path_append
+#undef xkb_context_include_path_append_default
+#undef xkb_context_include_path_reset_defaults
+#undef xkb_context_include_path_clear
+#undef xkb_context_num_include_paths
+#undef xkb_context_include_path_get
+#undef xkb_context_set_log_level
+#undef xkb_context_get_log_level
+#undef xkb_context_set_log_verbosity
+#undef xkb_context_get_log_verbosity
+#undef xkb_context_set_log_fn
+#undef xkb_keymap_new_from_names
+#undef xkb_keymap_new_from_file
+#undef xkb_keymap_new_from_string
+#undef xkb_keymap_new_from_buffer
+#undef xkb_keymap_ref
+#undef xkb_keymap_unref
+#undef xkb_keymap_get_as_string
+#undef xkb_keymap_min_keycode
+#undef xkb_keymap_max_keycode
+#undef xkb_keymap_key_for_each
+#undef xkb_keymap_key_get_name
+#undef xkb_keymap_key_by_name
+#undef xkb_keymap_num_mods
+#undef xkb_keymap_mod_get_name
+#undef xkb_keymap_mod_get_index
+#undef xkb_keymap_num_layouts
+#undef xkb_keymap_layout_get_name
+#undef xkb_keymap_layout_get_index
+#undef xkb_keymap_num_leds
+#undef xkb_keymap_led_get_name
+#undef xkb_keymap_led_get_index
+#undef xkb_keymap_num_layouts_for_key
+#undef xkb_keymap_num_levels_for_key
+#undef xkb_keymap_key_get_mods_for_level
+#undef xkb_keymap_key_get_syms_by_level
+#undef xkb_keymap_key_repeats
+#undef xkb_state_new
+#undef xkb_state_ref
+#undef xkb_state_unref
+#undef xkb_state_get_keymap
+#undef xkb_state_update_key
+#undef xkb_state_update_mask
+#undef xkb_state_key_get_syms
+#undef xkb_state_key_get_utf8
+#undef xkb_state_key_get_utf32
+#undef xkb_state_key_get_one_sym
+#undef xkb_state_key_get_layout
+#undef xkb_state_key_get_level
+#undef xkb_state_serialize_mods
+#undef xkb_state_serialize_layout
+#undef xkb_state_mod_name_is_active
+#undef xkb_state_mod_names_are_active
+#undef xkb_state_mod_index_is_active
+#undef xkb_state_mod_indices_are_active
+#undef xkb_state_key_get_consumed_mods2
+#undef xkb_state_key_get_consumed_mods
+#undef xkb_state_mod_index_is_consumed2
+#undef xkb_state_mod_index_is_consumed
+#undef xkb_state_mod_mask_remove_consumed
+#undef xkb_state_layout_name_is_active
+#undef xkb_state_layout_index_is_active
+#undef xkb_state_led_name_is_active
+#undef xkb_state_led_index_is_active
+#include <dlfcn.h>
+#include <stdio.h>
+int (*xkb_keysym_get_name_dylibloader_wrapper_xkbcommon)( xkb_keysym_t, char*, size_t);
+xkb_keysym_t (*xkb_keysym_from_name_dylibloader_wrapper_xkbcommon)(const char*,enum xkb_keysym_flags);
+int (*xkb_keysym_to_utf8_dylibloader_wrapper_xkbcommon)( xkb_keysym_t, char*, size_t);
+uint32_t (*xkb_keysym_to_utf32_dylibloader_wrapper_xkbcommon)( xkb_keysym_t);
+xkb_keysym_t (*xkb_utf32_to_keysym_dylibloader_wrapper_xkbcommon)( uint32_t);
+xkb_keysym_t (*xkb_keysym_to_upper_dylibloader_wrapper_xkbcommon)( xkb_keysym_t);
+xkb_keysym_t (*xkb_keysym_to_lower_dylibloader_wrapper_xkbcommon)( xkb_keysym_t);
+struct xkb_context* (*xkb_context_new_dylibloader_wrapper_xkbcommon)(enum xkb_context_flags);
+struct xkb_context* (*xkb_context_ref_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+void (*xkb_context_unref_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+void (*xkb_context_set_user_data_dylibloader_wrapper_xkbcommon)(struct xkb_context*, void*);
+void* (*xkb_context_get_user_data_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+int (*xkb_context_include_path_append_dylibloader_wrapper_xkbcommon)(struct xkb_context*,const char*);
+int (*xkb_context_include_path_append_default_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+int (*xkb_context_include_path_reset_defaults_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+void (*xkb_context_include_path_clear_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+unsigned int (*xkb_context_num_include_paths_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+const char* (*xkb_context_include_path_get_dylibloader_wrapper_xkbcommon)(struct xkb_context*, unsigned int);
+void (*xkb_context_set_log_level_dylibloader_wrapper_xkbcommon)(struct xkb_context*,enum xkb_log_level);
+enum xkb_log_level (*xkb_context_get_log_level_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+void (*xkb_context_set_log_verbosity_dylibloader_wrapper_xkbcommon)(struct xkb_context*, int);
+int (*xkb_context_get_log_verbosity_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+void (*xkb_context_set_log_fn_dylibloader_wrapper_xkbcommon)(struct xkb_context*, void*);
+struct xkb_keymap* (*xkb_keymap_new_from_names_dylibloader_wrapper_xkbcommon)(struct xkb_context*,struct xkb_rule_names*,enum xkb_keymap_compile_flags);
+struct xkb_keymap* (*xkb_keymap_new_from_file_dylibloader_wrapper_xkbcommon)(struct xkb_context*, FILE*,enum xkb_keymap_format,enum xkb_keymap_compile_flags);
+struct xkb_keymap* (*xkb_keymap_new_from_string_dylibloader_wrapper_xkbcommon)(struct xkb_context*,const char*,enum xkb_keymap_format,enum xkb_keymap_compile_flags);
+struct xkb_keymap* (*xkb_keymap_new_from_buffer_dylibloader_wrapper_xkbcommon)(struct xkb_context*,const char*, size_t,enum xkb_keymap_format,enum xkb_keymap_compile_flags);
+struct xkb_keymap* (*xkb_keymap_ref_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+void (*xkb_keymap_unref_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+char* (*xkb_keymap_get_as_string_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*,enum xkb_keymap_format);
+xkb_keycode_t (*xkb_keymap_min_keycode_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+xkb_keycode_t (*xkb_keymap_max_keycode_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+void (*xkb_keymap_key_for_each_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keymap_key_iter_t, void*);
+const char* (*xkb_keymap_key_get_name_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t);
+xkb_keycode_t (*xkb_keymap_key_by_name_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*,const char*);
+xkb_mod_index_t (*xkb_keymap_num_mods_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+const char* (*xkb_keymap_mod_get_name_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_mod_index_t);
+xkb_mod_index_t (*xkb_keymap_mod_get_index_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*,const char*);
+xkb_layout_index_t (*xkb_keymap_num_layouts_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+const char* (*xkb_keymap_layout_get_name_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_layout_index_t);
+xkb_layout_index_t (*xkb_keymap_layout_get_index_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*,const char*);
+xkb_led_index_t (*xkb_keymap_num_leds_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+const char* (*xkb_keymap_led_get_name_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_led_index_t);
+xkb_led_index_t (*xkb_keymap_led_get_index_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*,const char*);
+xkb_layout_index_t (*xkb_keymap_num_layouts_for_key_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t);
+xkb_level_index_t (*xkb_keymap_num_levels_for_key_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t);
+size_t (*xkb_keymap_key_get_mods_for_level_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t, xkb_mod_mask_t*, size_t);
+int (*xkb_keymap_key_get_syms_by_level_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t,const xkb_keysym_t**);
+int (*xkb_keymap_key_repeats_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t);
+struct xkb_state* (*xkb_state_new_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+struct xkb_state* (*xkb_state_ref_dylibloader_wrapper_xkbcommon)(struct xkb_state*);
+void (*xkb_state_unref_dylibloader_wrapper_xkbcommon)(struct xkb_state*);
+struct xkb_keymap* (*xkb_state_get_keymap_dylibloader_wrapper_xkbcommon)(struct xkb_state*);
+enum xkb_state_component (*xkb_state_update_key_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t,enum xkb_key_direction);
+enum xkb_state_component (*xkb_state_update_mask_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t);
+int (*xkb_state_key_get_syms_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t,const xkb_keysym_t**);
+int (*xkb_state_key_get_utf8_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t, char*, size_t);
+uint32_t (*xkb_state_key_get_utf32_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t);
+xkb_keysym_t (*xkb_state_key_get_one_sym_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t);
+xkb_layout_index_t (*xkb_state_key_get_layout_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t);
+xkb_level_index_t (*xkb_state_key_get_level_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t, xkb_layout_index_t);
+xkb_mod_mask_t (*xkb_state_serialize_mods_dylibloader_wrapper_xkbcommon)(struct xkb_state*,enum xkb_state_component);
+xkb_layout_index_t (*xkb_state_serialize_layout_dylibloader_wrapper_xkbcommon)(struct xkb_state*,enum xkb_state_component);
+int (*xkb_state_mod_name_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*,const char*,enum xkb_state_component);
+int (*xkb_state_mod_names_are_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*,enum xkb_state_component,enum xkb_state_match,...);
+int (*xkb_state_mod_index_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_mod_index_t,enum xkb_state_component);
+int (*xkb_state_mod_indices_are_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*,enum xkb_state_component,enum xkb_state_match,...);
+xkb_mod_mask_t (*xkb_state_key_get_consumed_mods2_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t,enum xkb_consumed_mode);
+xkb_mod_mask_t (*xkb_state_key_get_consumed_mods_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t);
+int (*xkb_state_mod_index_is_consumed2_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t, xkb_mod_index_t,enum xkb_consumed_mode);
+int (*xkb_state_mod_index_is_consumed_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t, xkb_mod_index_t);
+xkb_mod_mask_t (*xkb_state_mod_mask_remove_consumed_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t, xkb_mod_mask_t);
+int (*xkb_state_layout_name_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*,const char*,enum xkb_state_component);
+int (*xkb_state_layout_index_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_layout_index_t,enum xkb_state_component);
+int (*xkb_state_led_name_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*,const char*);
+int (*xkb_state_led_index_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_led_index_t);
+int initialize_xkbcommon(int verbose) {
+ void *handle;
+ char *error;
+ handle = dlopen("libxkbcommon.so.0", RTLD_LAZY);
+ if (!handle) {
+ if (verbose) {
+ fprintf(stderr, "%s\n", dlerror());
+ }
+ return(1);
+ }
+ dlerror();
+// xkb_keysym_get_name
+ *(void **) (&xkb_keysym_get_name_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keysym_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keysym_from_name
+ *(void **) (&xkb_keysym_from_name_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keysym_from_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keysym_to_utf8
+ *(void **) (&xkb_keysym_to_utf8_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keysym_to_utf8");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keysym_to_utf32
+ *(void **) (&xkb_keysym_to_utf32_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keysym_to_utf32");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_utf32_to_keysym
+ *(void **) (&xkb_utf32_to_keysym_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_utf32_to_keysym");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keysym_to_upper
+ *(void **) (&xkb_keysym_to_upper_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keysym_to_upper");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keysym_to_lower
+ *(void **) (&xkb_keysym_to_lower_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keysym_to_lower");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_new
+ *(void **) (&xkb_context_new_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_ref
+ *(void **) (&xkb_context_ref_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_unref
+ *(void **) (&xkb_context_unref_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_set_user_data
+ *(void **) (&xkb_context_set_user_data_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_set_user_data");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_get_user_data
+ *(void **) (&xkb_context_get_user_data_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_get_user_data");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_include_path_append
+ *(void **) (&xkb_context_include_path_append_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_include_path_append");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_include_path_append_default
+ *(void **) (&xkb_context_include_path_append_default_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_include_path_append_default");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_include_path_reset_defaults
+ *(void **) (&xkb_context_include_path_reset_defaults_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_include_path_reset_defaults");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_include_path_clear
+ *(void **) (&xkb_context_include_path_clear_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_include_path_clear");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_num_include_paths
+ *(void **) (&xkb_context_num_include_paths_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_num_include_paths");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_include_path_get
+ *(void **) (&xkb_context_include_path_get_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_include_path_get");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_set_log_level
+ *(void **) (&xkb_context_set_log_level_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_set_log_level");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_get_log_level
+ *(void **) (&xkb_context_get_log_level_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_get_log_level");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_set_log_verbosity
+ *(void **) (&xkb_context_set_log_verbosity_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_set_log_verbosity");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_get_log_verbosity
+ *(void **) (&xkb_context_get_log_verbosity_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_get_log_verbosity");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_context_set_log_fn
+ *(void **) (&xkb_context_set_log_fn_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_context_set_log_fn");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_new_from_names
+ *(void **) (&xkb_keymap_new_from_names_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_new_from_names");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_new_from_file
+ *(void **) (&xkb_keymap_new_from_file_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_new_from_file");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_new_from_string
+ *(void **) (&xkb_keymap_new_from_string_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_new_from_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_new_from_buffer
+ *(void **) (&xkb_keymap_new_from_buffer_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_new_from_buffer");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_ref
+ *(void **) (&xkb_keymap_ref_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_unref
+ *(void **) (&xkb_keymap_unref_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_get_as_string
+ *(void **) (&xkb_keymap_get_as_string_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_get_as_string");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_min_keycode
+ *(void **) (&xkb_keymap_min_keycode_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_min_keycode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_max_keycode
+ *(void **) (&xkb_keymap_max_keycode_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_max_keycode");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_key_for_each
+ *(void **) (&xkb_keymap_key_for_each_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_key_for_each");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_key_get_name
+ *(void **) (&xkb_keymap_key_get_name_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_key_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_key_by_name
+ *(void **) (&xkb_keymap_key_by_name_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_key_by_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_num_mods
+ *(void **) (&xkb_keymap_num_mods_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_num_mods");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_mod_get_name
+ *(void **) (&xkb_keymap_mod_get_name_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_mod_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_mod_get_index
+ *(void **) (&xkb_keymap_mod_get_index_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_mod_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_num_layouts
+ *(void **) (&xkb_keymap_num_layouts_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_num_layouts");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_layout_get_name
+ *(void **) (&xkb_keymap_layout_get_name_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_layout_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_layout_get_index
+ *(void **) (&xkb_keymap_layout_get_index_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_layout_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_num_leds
+ *(void **) (&xkb_keymap_num_leds_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_num_leds");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_led_get_name
+ *(void **) (&xkb_keymap_led_get_name_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_led_get_name");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_led_get_index
+ *(void **) (&xkb_keymap_led_get_index_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_led_get_index");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_num_layouts_for_key
+ *(void **) (&xkb_keymap_num_layouts_for_key_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_num_layouts_for_key");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_num_levels_for_key
+ *(void **) (&xkb_keymap_num_levels_for_key_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_num_levels_for_key");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_key_get_mods_for_level
+ *(void **) (&xkb_keymap_key_get_mods_for_level_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_key_get_mods_for_level");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_key_get_syms_by_level
+ *(void **) (&xkb_keymap_key_get_syms_by_level_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_key_get_syms_by_level");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_keymap_key_repeats
+ *(void **) (&xkb_keymap_key_repeats_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_keymap_key_repeats");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_new
+ *(void **) (&xkb_state_new_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_new");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_ref
+ *(void **) (&xkb_state_ref_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_ref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_unref
+ *(void **) (&xkb_state_unref_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_unref");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_get_keymap
+ *(void **) (&xkb_state_get_keymap_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_get_keymap");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_update_key
+ *(void **) (&xkb_state_update_key_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_update_key");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_update_mask
+ *(void **) (&xkb_state_update_mask_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_update_mask");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_key_get_syms
+ *(void **) (&xkb_state_key_get_syms_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_key_get_syms");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_key_get_utf8
+ *(void **) (&xkb_state_key_get_utf8_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_key_get_utf8");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_key_get_utf32
+ *(void **) (&xkb_state_key_get_utf32_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_key_get_utf32");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_key_get_one_sym
+ *(void **) (&xkb_state_key_get_one_sym_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_key_get_one_sym");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_key_get_layout
+ *(void **) (&xkb_state_key_get_layout_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_key_get_layout");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_key_get_level
+ *(void **) (&xkb_state_key_get_level_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_key_get_level");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_serialize_mods
+ *(void **) (&xkb_state_serialize_mods_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_serialize_mods");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_serialize_layout
+ *(void **) (&xkb_state_serialize_layout_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_serialize_layout");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_mod_name_is_active
+ *(void **) (&xkb_state_mod_name_is_active_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_mod_name_is_active");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_mod_names_are_active
+ *(void **) (&xkb_state_mod_names_are_active_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_mod_names_are_active");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_mod_index_is_active
+ *(void **) (&xkb_state_mod_index_is_active_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_mod_index_is_active");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_mod_indices_are_active
+ *(void **) (&xkb_state_mod_indices_are_active_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_mod_indices_are_active");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_key_get_consumed_mods2
+ *(void **) (&xkb_state_key_get_consumed_mods2_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_key_get_consumed_mods2");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_key_get_consumed_mods
+ *(void **) (&xkb_state_key_get_consumed_mods_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_key_get_consumed_mods");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_mod_index_is_consumed2
+ *(void **) (&xkb_state_mod_index_is_consumed2_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_mod_index_is_consumed2");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_mod_index_is_consumed
+ *(void **) (&xkb_state_mod_index_is_consumed_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_mod_index_is_consumed");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_mod_mask_remove_consumed
+ *(void **) (&xkb_state_mod_mask_remove_consumed_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_mod_mask_remove_consumed");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_layout_name_is_active
+ *(void **) (&xkb_state_layout_name_is_active_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_layout_name_is_active");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_layout_index_is_active
+ *(void **) (&xkb_state_layout_index_is_active_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_layout_index_is_active");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_led_name_is_active
+ *(void **) (&xkb_state_led_name_is_active_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_led_name_is_active");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+// xkb_state_led_index_is_active
+ *(void **) (&xkb_state_led_index_is_active_dylibloader_wrapper_xkbcommon) = dlsym(handle, "xkb_state_led_index_is_active");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
+return 0;
+}
diff --git a/platform/linuxbsd/x11/dynwrappers/xkbcommon-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xkbcommon-so_wrap.h
new file mode 100644
index 0000000000..e1f1c209d8
--- /dev/null
+++ b/platform/linuxbsd/x11/dynwrappers/xkbcommon-so_wrap.h
@@ -0,0 +1,322 @@
+#ifndef DYLIBLOAD_WRAPPER_XKBCOMMON
+#define DYLIBLOAD_WRAPPER_XKBCOMMON
+// This file is generated. Do not edit!
+// see https://github.com/hpvb/dynload-wrapper for details
+// generated by ./generate-wrapper.py 0.3 on 2023-01-23 14:25:23
+// flags: ./generate-wrapper.py --include /usr/include/xkbcommon/xkbcommon.h --sys-include <xkbcommon/xkbcommon.h> --soname libxkbcommon.so.0 --init-name xkbcommon --output-header xkbcommon-so_wrap.h --output-implementation xkbcommon-so_wrap.c
+//
+#include <stdint.h>
+
+#define xkb_keysym_get_name xkb_keysym_get_name_dylibloader_orig_xkbcommon
+#define xkb_keysym_from_name xkb_keysym_from_name_dylibloader_orig_xkbcommon
+#define xkb_keysym_to_utf8 xkb_keysym_to_utf8_dylibloader_orig_xkbcommon
+#define xkb_keysym_to_utf32 xkb_keysym_to_utf32_dylibloader_orig_xkbcommon
+#define xkb_utf32_to_keysym xkb_utf32_to_keysym_dylibloader_orig_xkbcommon
+#define xkb_keysym_to_upper xkb_keysym_to_upper_dylibloader_orig_xkbcommon
+#define xkb_keysym_to_lower xkb_keysym_to_lower_dylibloader_orig_xkbcommon
+#define xkb_context_new xkb_context_new_dylibloader_orig_xkbcommon
+#define xkb_context_ref xkb_context_ref_dylibloader_orig_xkbcommon
+#define xkb_context_unref xkb_context_unref_dylibloader_orig_xkbcommon
+#define xkb_context_set_user_data xkb_context_set_user_data_dylibloader_orig_xkbcommon
+#define xkb_context_get_user_data xkb_context_get_user_data_dylibloader_orig_xkbcommon
+#define xkb_context_include_path_append xkb_context_include_path_append_dylibloader_orig_xkbcommon
+#define xkb_context_include_path_append_default xkb_context_include_path_append_default_dylibloader_orig_xkbcommon
+#define xkb_context_include_path_reset_defaults xkb_context_include_path_reset_defaults_dylibloader_orig_xkbcommon
+#define xkb_context_include_path_clear xkb_context_include_path_clear_dylibloader_orig_xkbcommon
+#define xkb_context_num_include_paths xkb_context_num_include_paths_dylibloader_orig_xkbcommon
+#define xkb_context_include_path_get xkb_context_include_path_get_dylibloader_orig_xkbcommon
+#define xkb_context_set_log_level xkb_context_set_log_level_dylibloader_orig_xkbcommon
+#define xkb_context_get_log_level xkb_context_get_log_level_dylibloader_orig_xkbcommon
+#define xkb_context_set_log_verbosity xkb_context_set_log_verbosity_dylibloader_orig_xkbcommon
+#define xkb_context_get_log_verbosity xkb_context_get_log_verbosity_dylibloader_orig_xkbcommon
+#define xkb_context_set_log_fn xkb_context_set_log_fn_dylibloader_orig_xkbcommon
+#define xkb_keymap_new_from_names xkb_keymap_new_from_names_dylibloader_orig_xkbcommon
+#define xkb_keymap_new_from_file xkb_keymap_new_from_file_dylibloader_orig_xkbcommon
+#define xkb_keymap_new_from_string xkb_keymap_new_from_string_dylibloader_orig_xkbcommon
+#define xkb_keymap_new_from_buffer xkb_keymap_new_from_buffer_dylibloader_orig_xkbcommon
+#define xkb_keymap_ref xkb_keymap_ref_dylibloader_orig_xkbcommon
+#define xkb_keymap_unref xkb_keymap_unref_dylibloader_orig_xkbcommon
+#define xkb_keymap_get_as_string xkb_keymap_get_as_string_dylibloader_orig_xkbcommon
+#define xkb_keymap_min_keycode xkb_keymap_min_keycode_dylibloader_orig_xkbcommon
+#define xkb_keymap_max_keycode xkb_keymap_max_keycode_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_for_each xkb_keymap_key_for_each_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_get_name xkb_keymap_key_get_name_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_by_name xkb_keymap_key_by_name_dylibloader_orig_xkbcommon
+#define xkb_keymap_num_mods xkb_keymap_num_mods_dylibloader_orig_xkbcommon
+#define xkb_keymap_mod_get_name xkb_keymap_mod_get_name_dylibloader_orig_xkbcommon
+#define xkb_keymap_mod_get_index xkb_keymap_mod_get_index_dylibloader_orig_xkbcommon
+#define xkb_keymap_num_layouts xkb_keymap_num_layouts_dylibloader_orig_xkbcommon
+#define xkb_keymap_layout_get_name xkb_keymap_layout_get_name_dylibloader_orig_xkbcommon
+#define xkb_keymap_layout_get_index xkb_keymap_layout_get_index_dylibloader_orig_xkbcommon
+#define xkb_keymap_num_leds xkb_keymap_num_leds_dylibloader_orig_xkbcommon
+#define xkb_keymap_led_get_name xkb_keymap_led_get_name_dylibloader_orig_xkbcommon
+#define xkb_keymap_led_get_index xkb_keymap_led_get_index_dylibloader_orig_xkbcommon
+#define xkb_keymap_num_layouts_for_key xkb_keymap_num_layouts_for_key_dylibloader_orig_xkbcommon
+#define xkb_keymap_num_levels_for_key xkb_keymap_num_levels_for_key_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_get_mods_for_level xkb_keymap_key_get_mods_for_level_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_get_syms_by_level xkb_keymap_key_get_syms_by_level_dylibloader_orig_xkbcommon
+#define xkb_keymap_key_repeats xkb_keymap_key_repeats_dylibloader_orig_xkbcommon
+#define xkb_state_new xkb_state_new_dylibloader_orig_xkbcommon
+#define xkb_state_ref xkb_state_ref_dylibloader_orig_xkbcommon
+#define xkb_state_unref xkb_state_unref_dylibloader_orig_xkbcommon
+#define xkb_state_get_keymap xkb_state_get_keymap_dylibloader_orig_xkbcommon
+#define xkb_state_update_key xkb_state_update_key_dylibloader_orig_xkbcommon
+#define xkb_state_update_mask xkb_state_update_mask_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_syms xkb_state_key_get_syms_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_utf8 xkb_state_key_get_utf8_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_utf32 xkb_state_key_get_utf32_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_one_sym xkb_state_key_get_one_sym_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_layout xkb_state_key_get_layout_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_level xkb_state_key_get_level_dylibloader_orig_xkbcommon
+#define xkb_state_serialize_mods xkb_state_serialize_mods_dylibloader_orig_xkbcommon
+#define xkb_state_serialize_layout xkb_state_serialize_layout_dylibloader_orig_xkbcommon
+#define xkb_state_mod_name_is_active xkb_state_mod_name_is_active_dylibloader_orig_xkbcommon
+#define xkb_state_mod_names_are_active xkb_state_mod_names_are_active_dylibloader_orig_xkbcommon
+#define xkb_state_mod_index_is_active xkb_state_mod_index_is_active_dylibloader_orig_xkbcommon
+#define xkb_state_mod_indices_are_active xkb_state_mod_indices_are_active_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_consumed_mods2 xkb_state_key_get_consumed_mods2_dylibloader_orig_xkbcommon
+#define xkb_state_key_get_consumed_mods xkb_state_key_get_consumed_mods_dylibloader_orig_xkbcommon
+#define xkb_state_mod_index_is_consumed2 xkb_state_mod_index_is_consumed2_dylibloader_orig_xkbcommon
+#define xkb_state_mod_index_is_consumed xkb_state_mod_index_is_consumed_dylibloader_orig_xkbcommon
+#define xkb_state_mod_mask_remove_consumed xkb_state_mod_mask_remove_consumed_dylibloader_orig_xkbcommon
+#define xkb_state_layout_name_is_active xkb_state_layout_name_is_active_dylibloader_orig_xkbcommon
+#define xkb_state_layout_index_is_active xkb_state_layout_index_is_active_dylibloader_orig_xkbcommon
+#define xkb_state_led_name_is_active xkb_state_led_name_is_active_dylibloader_orig_xkbcommon
+#define xkb_state_led_index_is_active xkb_state_led_index_is_active_dylibloader_orig_xkbcommon
+#include <xkbcommon/xkbcommon.h>
+#undef xkb_keysym_get_name
+#undef xkb_keysym_from_name
+#undef xkb_keysym_to_utf8
+#undef xkb_keysym_to_utf32
+#undef xkb_utf32_to_keysym
+#undef xkb_keysym_to_upper
+#undef xkb_keysym_to_lower
+#undef xkb_context_new
+#undef xkb_context_ref
+#undef xkb_context_unref
+#undef xkb_context_set_user_data
+#undef xkb_context_get_user_data
+#undef xkb_context_include_path_append
+#undef xkb_context_include_path_append_default
+#undef xkb_context_include_path_reset_defaults
+#undef xkb_context_include_path_clear
+#undef xkb_context_num_include_paths
+#undef xkb_context_include_path_get
+#undef xkb_context_set_log_level
+#undef xkb_context_get_log_level
+#undef xkb_context_set_log_verbosity
+#undef xkb_context_get_log_verbosity
+#undef xkb_context_set_log_fn
+#undef xkb_keymap_new_from_names
+#undef xkb_keymap_new_from_file
+#undef xkb_keymap_new_from_string
+#undef xkb_keymap_new_from_buffer
+#undef xkb_keymap_ref
+#undef xkb_keymap_unref
+#undef xkb_keymap_get_as_string
+#undef xkb_keymap_min_keycode
+#undef xkb_keymap_max_keycode
+#undef xkb_keymap_key_for_each
+#undef xkb_keymap_key_get_name
+#undef xkb_keymap_key_by_name
+#undef xkb_keymap_num_mods
+#undef xkb_keymap_mod_get_name
+#undef xkb_keymap_mod_get_index
+#undef xkb_keymap_num_layouts
+#undef xkb_keymap_layout_get_name
+#undef xkb_keymap_layout_get_index
+#undef xkb_keymap_num_leds
+#undef xkb_keymap_led_get_name
+#undef xkb_keymap_led_get_index
+#undef xkb_keymap_num_layouts_for_key
+#undef xkb_keymap_num_levels_for_key
+#undef xkb_keymap_key_get_mods_for_level
+#undef xkb_keymap_key_get_syms_by_level
+#undef xkb_keymap_key_repeats
+#undef xkb_state_new
+#undef xkb_state_ref
+#undef xkb_state_unref
+#undef xkb_state_get_keymap
+#undef xkb_state_update_key
+#undef xkb_state_update_mask
+#undef xkb_state_key_get_syms
+#undef xkb_state_key_get_utf8
+#undef xkb_state_key_get_utf32
+#undef xkb_state_key_get_one_sym
+#undef xkb_state_key_get_layout
+#undef xkb_state_key_get_level
+#undef xkb_state_serialize_mods
+#undef xkb_state_serialize_layout
+#undef xkb_state_mod_name_is_active
+#undef xkb_state_mod_names_are_active
+#undef xkb_state_mod_index_is_active
+#undef xkb_state_mod_indices_are_active
+#undef xkb_state_key_get_consumed_mods2
+#undef xkb_state_key_get_consumed_mods
+#undef xkb_state_mod_index_is_consumed2
+#undef xkb_state_mod_index_is_consumed
+#undef xkb_state_mod_mask_remove_consumed
+#undef xkb_state_layout_name_is_active
+#undef xkb_state_layout_index_is_active
+#undef xkb_state_led_name_is_active
+#undef xkb_state_led_index_is_active
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define xkb_keysym_get_name xkb_keysym_get_name_dylibloader_wrapper_xkbcommon
+#define xkb_keysym_from_name xkb_keysym_from_name_dylibloader_wrapper_xkbcommon
+#define xkb_keysym_to_utf8 xkb_keysym_to_utf8_dylibloader_wrapper_xkbcommon
+#define xkb_keysym_to_utf32 xkb_keysym_to_utf32_dylibloader_wrapper_xkbcommon
+#define xkb_utf32_to_keysym xkb_utf32_to_keysym_dylibloader_wrapper_xkbcommon
+#define xkb_keysym_to_upper xkb_keysym_to_upper_dylibloader_wrapper_xkbcommon
+#define xkb_keysym_to_lower xkb_keysym_to_lower_dylibloader_wrapper_xkbcommon
+#define xkb_context_new xkb_context_new_dylibloader_wrapper_xkbcommon
+#define xkb_context_ref xkb_context_ref_dylibloader_wrapper_xkbcommon
+#define xkb_context_unref xkb_context_unref_dylibloader_wrapper_xkbcommon
+#define xkb_context_set_user_data xkb_context_set_user_data_dylibloader_wrapper_xkbcommon
+#define xkb_context_get_user_data xkb_context_get_user_data_dylibloader_wrapper_xkbcommon
+#define xkb_context_include_path_append xkb_context_include_path_append_dylibloader_wrapper_xkbcommon
+#define xkb_context_include_path_append_default xkb_context_include_path_append_default_dylibloader_wrapper_xkbcommon
+#define xkb_context_include_path_reset_defaults xkb_context_include_path_reset_defaults_dylibloader_wrapper_xkbcommon
+#define xkb_context_include_path_clear xkb_context_include_path_clear_dylibloader_wrapper_xkbcommon
+#define xkb_context_num_include_paths xkb_context_num_include_paths_dylibloader_wrapper_xkbcommon
+#define xkb_context_include_path_get xkb_context_include_path_get_dylibloader_wrapper_xkbcommon
+#define xkb_context_set_log_level xkb_context_set_log_level_dylibloader_wrapper_xkbcommon
+#define xkb_context_get_log_level xkb_context_get_log_level_dylibloader_wrapper_xkbcommon
+#define xkb_context_set_log_verbosity xkb_context_set_log_verbosity_dylibloader_wrapper_xkbcommon
+#define xkb_context_get_log_verbosity xkb_context_get_log_verbosity_dylibloader_wrapper_xkbcommon
+#define xkb_context_set_log_fn xkb_context_set_log_fn_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_new_from_names xkb_keymap_new_from_names_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_new_from_file xkb_keymap_new_from_file_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_new_from_string xkb_keymap_new_from_string_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_new_from_buffer xkb_keymap_new_from_buffer_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_ref xkb_keymap_ref_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_unref xkb_keymap_unref_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_get_as_string xkb_keymap_get_as_string_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_min_keycode xkb_keymap_min_keycode_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_max_keycode xkb_keymap_max_keycode_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_key_for_each xkb_keymap_key_for_each_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_key_get_name xkb_keymap_key_get_name_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_key_by_name xkb_keymap_key_by_name_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_num_mods xkb_keymap_num_mods_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_mod_get_name xkb_keymap_mod_get_name_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_mod_get_index xkb_keymap_mod_get_index_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_num_layouts xkb_keymap_num_layouts_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_layout_get_name xkb_keymap_layout_get_name_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_layout_get_index xkb_keymap_layout_get_index_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_num_leds xkb_keymap_num_leds_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_led_get_name xkb_keymap_led_get_name_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_led_get_index xkb_keymap_led_get_index_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_num_layouts_for_key xkb_keymap_num_layouts_for_key_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_num_levels_for_key xkb_keymap_num_levels_for_key_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_key_get_mods_for_level xkb_keymap_key_get_mods_for_level_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_key_get_syms_by_level xkb_keymap_key_get_syms_by_level_dylibloader_wrapper_xkbcommon
+#define xkb_keymap_key_repeats xkb_keymap_key_repeats_dylibloader_wrapper_xkbcommon
+#define xkb_state_new xkb_state_new_dylibloader_wrapper_xkbcommon
+#define xkb_state_ref xkb_state_ref_dylibloader_wrapper_xkbcommon
+#define xkb_state_unref xkb_state_unref_dylibloader_wrapper_xkbcommon
+#define xkb_state_get_keymap xkb_state_get_keymap_dylibloader_wrapper_xkbcommon
+#define xkb_state_update_key xkb_state_update_key_dylibloader_wrapper_xkbcommon
+#define xkb_state_update_mask xkb_state_update_mask_dylibloader_wrapper_xkbcommon
+#define xkb_state_key_get_syms xkb_state_key_get_syms_dylibloader_wrapper_xkbcommon
+#define xkb_state_key_get_utf8 xkb_state_key_get_utf8_dylibloader_wrapper_xkbcommon
+#define xkb_state_key_get_utf32 xkb_state_key_get_utf32_dylibloader_wrapper_xkbcommon
+#define xkb_state_key_get_one_sym xkb_state_key_get_one_sym_dylibloader_wrapper_xkbcommon
+#define xkb_state_key_get_layout xkb_state_key_get_layout_dylibloader_wrapper_xkbcommon
+#define xkb_state_key_get_level xkb_state_key_get_level_dylibloader_wrapper_xkbcommon
+#define xkb_state_serialize_mods xkb_state_serialize_mods_dylibloader_wrapper_xkbcommon
+#define xkb_state_serialize_layout xkb_state_serialize_layout_dylibloader_wrapper_xkbcommon
+#define xkb_state_mod_name_is_active xkb_state_mod_name_is_active_dylibloader_wrapper_xkbcommon
+#define xkb_state_mod_names_are_active xkb_state_mod_names_are_active_dylibloader_wrapper_xkbcommon
+#define xkb_state_mod_index_is_active xkb_state_mod_index_is_active_dylibloader_wrapper_xkbcommon
+#define xkb_state_mod_indices_are_active xkb_state_mod_indices_are_active_dylibloader_wrapper_xkbcommon
+#define xkb_state_key_get_consumed_mods2 xkb_state_key_get_consumed_mods2_dylibloader_wrapper_xkbcommon
+#define xkb_state_key_get_consumed_mods xkb_state_key_get_consumed_mods_dylibloader_wrapper_xkbcommon
+#define xkb_state_mod_index_is_consumed2 xkb_state_mod_index_is_consumed2_dylibloader_wrapper_xkbcommon
+#define xkb_state_mod_index_is_consumed xkb_state_mod_index_is_consumed_dylibloader_wrapper_xkbcommon
+#define xkb_state_mod_mask_remove_consumed xkb_state_mod_mask_remove_consumed_dylibloader_wrapper_xkbcommon
+#define xkb_state_layout_name_is_active xkb_state_layout_name_is_active_dylibloader_wrapper_xkbcommon
+#define xkb_state_layout_index_is_active xkb_state_layout_index_is_active_dylibloader_wrapper_xkbcommon
+#define xkb_state_led_name_is_active xkb_state_led_name_is_active_dylibloader_wrapper_xkbcommon
+#define xkb_state_led_index_is_active xkb_state_led_index_is_active_dylibloader_wrapper_xkbcommon
+extern int (*xkb_keysym_get_name_dylibloader_wrapper_xkbcommon)( xkb_keysym_t, char*, size_t);
+extern xkb_keysym_t (*xkb_keysym_from_name_dylibloader_wrapper_xkbcommon)(const char*,enum xkb_keysym_flags);
+extern int (*xkb_keysym_to_utf8_dylibloader_wrapper_xkbcommon)( xkb_keysym_t, char*, size_t);
+extern uint32_t (*xkb_keysym_to_utf32_dylibloader_wrapper_xkbcommon)( xkb_keysym_t);
+extern xkb_keysym_t (*xkb_utf32_to_keysym_dylibloader_wrapper_xkbcommon)( uint32_t);
+extern xkb_keysym_t (*xkb_keysym_to_upper_dylibloader_wrapper_xkbcommon)( xkb_keysym_t);
+extern xkb_keysym_t (*xkb_keysym_to_lower_dylibloader_wrapper_xkbcommon)( xkb_keysym_t);
+extern struct xkb_context* (*xkb_context_new_dylibloader_wrapper_xkbcommon)(enum xkb_context_flags);
+extern struct xkb_context* (*xkb_context_ref_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+extern void (*xkb_context_unref_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+extern void (*xkb_context_set_user_data_dylibloader_wrapper_xkbcommon)(struct xkb_context*, void*);
+extern void* (*xkb_context_get_user_data_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+extern int (*xkb_context_include_path_append_dylibloader_wrapper_xkbcommon)(struct xkb_context*,const char*);
+extern int (*xkb_context_include_path_append_default_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+extern int (*xkb_context_include_path_reset_defaults_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+extern void (*xkb_context_include_path_clear_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+extern unsigned int (*xkb_context_num_include_paths_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+extern const char* (*xkb_context_include_path_get_dylibloader_wrapper_xkbcommon)(struct xkb_context*, unsigned int);
+extern void (*xkb_context_set_log_level_dylibloader_wrapper_xkbcommon)(struct xkb_context*,enum xkb_log_level);
+extern enum xkb_log_level (*xkb_context_get_log_level_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+extern void (*xkb_context_set_log_verbosity_dylibloader_wrapper_xkbcommon)(struct xkb_context*, int);
+extern int (*xkb_context_get_log_verbosity_dylibloader_wrapper_xkbcommon)(struct xkb_context*);
+extern void (*xkb_context_set_log_fn_dylibloader_wrapper_xkbcommon)(struct xkb_context*, void*);
+extern struct xkb_keymap* (*xkb_keymap_new_from_names_dylibloader_wrapper_xkbcommon)(struct xkb_context*,struct xkb_rule_names*,enum xkb_keymap_compile_flags);
+extern struct xkb_keymap* (*xkb_keymap_new_from_file_dylibloader_wrapper_xkbcommon)(struct xkb_context*, FILE*,enum xkb_keymap_format,enum xkb_keymap_compile_flags);
+extern struct xkb_keymap* (*xkb_keymap_new_from_string_dylibloader_wrapper_xkbcommon)(struct xkb_context*,const char*,enum xkb_keymap_format,enum xkb_keymap_compile_flags);
+extern struct xkb_keymap* (*xkb_keymap_new_from_buffer_dylibloader_wrapper_xkbcommon)(struct xkb_context*,const char*, size_t,enum xkb_keymap_format,enum xkb_keymap_compile_flags);
+extern struct xkb_keymap* (*xkb_keymap_ref_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+extern void (*xkb_keymap_unref_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+extern char* (*xkb_keymap_get_as_string_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*,enum xkb_keymap_format);
+extern xkb_keycode_t (*xkb_keymap_min_keycode_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+extern xkb_keycode_t (*xkb_keymap_max_keycode_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+extern void (*xkb_keymap_key_for_each_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keymap_key_iter_t, void*);
+extern const char* (*xkb_keymap_key_get_name_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t);
+extern xkb_keycode_t (*xkb_keymap_key_by_name_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*,const char*);
+extern xkb_mod_index_t (*xkb_keymap_num_mods_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+extern const char* (*xkb_keymap_mod_get_name_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_mod_index_t);
+extern xkb_mod_index_t (*xkb_keymap_mod_get_index_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*,const char*);
+extern xkb_layout_index_t (*xkb_keymap_num_layouts_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+extern const char* (*xkb_keymap_layout_get_name_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_layout_index_t);
+extern xkb_layout_index_t (*xkb_keymap_layout_get_index_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*,const char*);
+extern xkb_led_index_t (*xkb_keymap_num_leds_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+extern const char* (*xkb_keymap_led_get_name_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_led_index_t);
+extern xkb_led_index_t (*xkb_keymap_led_get_index_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*,const char*);
+extern xkb_layout_index_t (*xkb_keymap_num_layouts_for_key_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t);
+extern xkb_level_index_t (*xkb_keymap_num_levels_for_key_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t);
+extern size_t (*xkb_keymap_key_get_mods_for_level_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t, xkb_mod_mask_t*, size_t);
+extern int (*xkb_keymap_key_get_syms_by_level_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t,const xkb_keysym_t**);
+extern int (*xkb_keymap_key_repeats_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*, xkb_keycode_t);
+extern struct xkb_state* (*xkb_state_new_dylibloader_wrapper_xkbcommon)(struct xkb_keymap*);
+extern struct xkb_state* (*xkb_state_ref_dylibloader_wrapper_xkbcommon)(struct xkb_state*);
+extern void (*xkb_state_unref_dylibloader_wrapper_xkbcommon)(struct xkb_state*);
+extern struct xkb_keymap* (*xkb_state_get_keymap_dylibloader_wrapper_xkbcommon)(struct xkb_state*);
+extern enum xkb_state_component (*xkb_state_update_key_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t,enum xkb_key_direction);
+extern enum xkb_state_component (*xkb_state_update_mask_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t);
+extern int (*xkb_state_key_get_syms_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t,const xkb_keysym_t**);
+extern int (*xkb_state_key_get_utf8_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t, char*, size_t);
+extern uint32_t (*xkb_state_key_get_utf32_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t);
+extern xkb_keysym_t (*xkb_state_key_get_one_sym_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t);
+extern xkb_layout_index_t (*xkb_state_key_get_layout_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t);
+extern xkb_level_index_t (*xkb_state_key_get_level_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t, xkb_layout_index_t);
+extern xkb_mod_mask_t (*xkb_state_serialize_mods_dylibloader_wrapper_xkbcommon)(struct xkb_state*,enum xkb_state_component);
+extern xkb_layout_index_t (*xkb_state_serialize_layout_dylibloader_wrapper_xkbcommon)(struct xkb_state*,enum xkb_state_component);
+extern int (*xkb_state_mod_name_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*,const char*,enum xkb_state_component);
+extern int (*xkb_state_mod_names_are_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*,enum xkb_state_component,enum xkb_state_match,...);
+extern int (*xkb_state_mod_index_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_mod_index_t,enum xkb_state_component);
+extern int (*xkb_state_mod_indices_are_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*,enum xkb_state_component,enum xkb_state_match,...);
+extern xkb_mod_mask_t (*xkb_state_key_get_consumed_mods2_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t,enum xkb_consumed_mode);
+extern xkb_mod_mask_t (*xkb_state_key_get_consumed_mods_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t);
+extern int (*xkb_state_mod_index_is_consumed2_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t, xkb_mod_index_t,enum xkb_consumed_mode);
+extern int (*xkb_state_mod_index_is_consumed_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t, xkb_mod_index_t);
+extern xkb_mod_mask_t (*xkb_state_mod_mask_remove_consumed_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_keycode_t, xkb_mod_mask_t);
+extern int (*xkb_state_layout_name_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*,const char*,enum xkb_state_component);
+extern int (*xkb_state_layout_index_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_layout_index_t,enum xkb_state_component);
+extern int (*xkb_state_led_name_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*,const char*);
+extern int (*xkb_state_led_index_is_active_dylibloader_wrapper_xkbcommon)(struct xkb_state*, xkb_led_index_t);
+int initialize_xkbcommon(int verbose);
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/platform/linuxbsd/x11/key_mapping_x11.cpp b/platform/linuxbsd/x11/key_mapping_x11.cpp
index 52b7e865bd..506372292d 100644
--- a/platform/linuxbsd/x11/key_mapping_x11.cpp
+++ b/platform/linuxbsd/x11/key_mapping_x11.cpp
@@ -30,1972 +30,1136 @@
#include "key_mapping_x11.h"
-/***** SCAN CODE CONVERSION ******/
+#include "core/templates/hash_map.h"
-struct _XTranslatePair {
- KeySym keysym;
- Key keycode;
+struct HashMapHasherKeys {
+ static _FORCE_INLINE_ uint32_t hash(const Key p_key) { return hash_fmix32(static_cast<uint32_t>(p_key)); }
+ static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
+ static _FORCE_INLINE_ uint32_t hash(const unsigned p_key) { return hash_fmix32(p_key); }
+ static _FORCE_INLINE_ uint32_t hash(const KeySym p_key) { return hash_fmix32(p_key); }
};
-static _XTranslatePair _xkeysym_to_keycode[] = {
- // misc keys
+HashMap<KeySym, Key, HashMapHasherKeys> xkeysym_map;
+HashMap<unsigned int, Key, HashMapHasherKeys> scancode_map;
+HashMap<Key, unsigned int, HashMapHasherKeys> scancode_map_inv;
+HashMap<KeySym, char32_t, HashMapHasherKeys> xkeysym_unicode_map;
- { XK_Escape, Key::ESCAPE },
- { XK_Tab, Key::TAB },
- { XK_ISO_Left_Tab, Key::BACKTAB },
- { XK_BackSpace, Key::BACKSPACE },
- { XK_Return, Key::ENTER },
- { XK_Insert, Key::INSERT },
- { XK_Delete, Key::KEY_DELETE },
- { XK_Clear, Key::KEY_DELETE },
- { XK_Pause, Key::PAUSE },
- { XK_Print, Key::PRINT },
- { XK_Home, Key::HOME },
- { XK_End, Key::END },
- { XK_Left, Key::LEFT },
- { XK_Up, Key::UP },
- { XK_Right, Key::RIGHT },
- { XK_Down, Key::DOWN },
- { XK_Prior, Key::PAGEUP },
- { XK_Next, Key::PAGEDOWN },
- { XK_Shift_L, Key::SHIFT },
- { XK_Shift_R, Key::SHIFT },
- { XK_Shift_Lock, Key::SHIFT },
- { XK_Control_L, Key::CTRL },
- { XK_Control_R, Key::CTRL },
- { XK_Meta_L, Key::META },
- { XK_Meta_R, Key::META },
- { XK_Alt_L, Key::ALT },
- { XK_Alt_R, Key::ALT },
- { XK_Caps_Lock, Key::CAPSLOCK },
- { XK_Num_Lock, Key::NUMLOCK },
- { XK_Scroll_Lock, Key::SCROLLLOCK },
- { XK_Super_L, Key::SUPER_L },
- { XK_Super_R, Key::SUPER_R },
- { XK_Menu, Key::MENU },
- { XK_Hyper_L, Key::HYPER_L },
- { XK_Hyper_R, Key::HYPER_R },
- { XK_Help, Key::HELP },
- { XK_KP_Space, Key::SPACE },
- { XK_KP_Tab, Key::TAB },
- { XK_KP_Enter, Key::KP_ENTER },
- { XK_Home, Key::HOME },
- { XK_Left, Key::LEFT },
- { XK_Up, Key::UP },
- { XK_Right, Key::RIGHT },
- { XK_Down, Key::DOWN },
- { XK_Prior, Key::PAGEUP },
- { XK_Next, Key::PAGEDOWN },
- { XK_End, Key::END },
- { XK_Begin, Key::CLEAR },
- { XK_Insert, Key::INSERT },
- { XK_Delete, Key::KEY_DELETE },
- //{ XK_KP_Equal, Key::EQUAL },
- //{ XK_KP_Separator, Key::COMMA },
- { XK_KP_Decimal, Key::KP_PERIOD },
- { XK_KP_Delete, Key::KP_PERIOD },
- { XK_KP_Multiply, Key::KP_MULTIPLY },
- { XK_KP_Divide, Key::KP_DIVIDE },
- { XK_KP_Subtract, Key::KP_SUBTRACT },
- { XK_KP_Add, Key::KP_ADD },
- { XK_KP_0, Key::KP_0 },
- { XK_KP_1, Key::KP_1 },
- { XK_KP_2, Key::KP_2 },
- { XK_KP_3, Key::KP_3 },
- { XK_KP_4, Key::KP_4 },
- { XK_KP_5, Key::KP_5 },
- { XK_KP_6, Key::KP_6 },
- { XK_KP_7, Key::KP_7 },
- { XK_KP_8, Key::KP_8 },
- { XK_KP_9, Key::KP_9 },
- // same keys but with numlock off
- { XK_KP_Insert, Key::INSERT },
- { XK_KP_End, Key::END },
- { XK_KP_Down, Key::DOWN },
- { XK_KP_Page_Down, Key::PAGEDOWN },
- { XK_KP_Left, Key::LEFT },
- // X11 documents this (numpad 5) as "begin of line" but no toolkit
- // seems to interpret it this way.
- // On Windows this is emitting Key::Clear so for consistency it
- // will be mapped to Key::Clear
- { XK_KP_Begin, Key::CLEAR },
- { XK_KP_Right, Key::RIGHT },
- { XK_KP_Home, Key::HOME },
- { XK_KP_Up, Key::UP },
- { XK_KP_Page_Up, Key::PAGEUP },
- { XK_F1, Key::F1 },
- { XK_F2, Key::F2 },
- { XK_F3, Key::F3 },
- { XK_F4, Key::F4 },
- { XK_F5, Key::F5 },
- { XK_F6, Key::F6 },
- { XK_F7, Key::F7 },
- { XK_F8, Key::F8 },
- { XK_F9, Key::F9 },
- { XK_F10, Key::F10 },
- { XK_F11, Key::F11 },
- { XK_F12, Key::F12 },
- { XK_F13, Key::F13 },
- { XK_F14, Key::F14 },
- { XK_F15, Key::F15 },
- { XK_F16, Key::F16 },
- { XK_F17, Key::F17 },
- { XK_F18, Key::F18 },
- { XK_F19, Key::F19 },
- { XK_F20, Key::F20 },
- { XK_F21, Key::F21 },
- { XK_F22, Key::F22 },
- { XK_F23, Key::F23 },
- { XK_F24, Key::F24 },
- { XK_F25, Key::F25 },
- { XK_F26, Key::F26 },
- { XK_F27, Key::F27 },
- { XK_F28, Key::F28 },
- { XK_F29, Key::F29 },
- { XK_F30, Key::F30 },
- { XK_F31, Key::F31 },
- { XK_F32, Key::F32 },
- { XK_F33, Key::F33 },
- { XK_F34, Key::F34 },
- { XK_F35, Key::F35 },
+void KeyMappingX11::initialize() {
+ // X11 Keysym to Godot Key map.
- // media keys
- { XF86XK_Back, Key::BACK },
- { XF86XK_Forward, Key::FORWARD },
- { XF86XK_Stop, Key::STOP },
- { XF86XK_Refresh, Key::REFRESH },
- { XF86XK_Favorites, Key::FAVORITES },
- { XF86XK_AudioMedia, Key::LAUNCHMEDIA },
- { XF86XK_OpenURL, Key::OPENURL },
- { XF86XK_HomePage, Key::HOMEPAGE },
- { XF86XK_Search, Key::SEARCH },
- { XF86XK_AudioLowerVolume, Key::VOLUMEDOWN },
- { XF86XK_AudioMute, Key::VOLUMEMUTE },
- { XF86XK_AudioRaiseVolume, Key::VOLUMEUP },
- { XF86XK_AudioPlay, Key::MEDIAPLAY },
- { XF86XK_AudioStop, Key::MEDIASTOP },
- { XF86XK_AudioPrev, Key::MEDIAPREVIOUS },
- { XF86XK_AudioNext, Key::MEDIANEXT },
- { XF86XK_AudioRecord, Key::MEDIARECORD },
+ xkeysym_map[XK_Escape] = Key::ESCAPE;
+ xkeysym_map[XK_Tab] = Key::TAB;
+ xkeysym_map[XK_ISO_Left_Tab] = Key::BACKTAB;
+ xkeysym_map[XK_BackSpace] = Key::BACKSPACE;
+ xkeysym_map[XK_Return] = Key::ENTER;
+ xkeysym_map[XK_Insert] = Key::INSERT;
+ xkeysym_map[XK_Delete] = Key::KEY_DELETE;
+ xkeysym_map[XK_Clear] = Key::KEY_DELETE;
+ xkeysym_map[XK_Pause] = Key::PAUSE;
+ xkeysym_map[XK_Print] = Key::PRINT;
+ xkeysym_map[XK_Home] = Key::HOME;
+ xkeysym_map[XK_End] = Key::END;
+ xkeysym_map[XK_Left] = Key::LEFT;
+ xkeysym_map[XK_Up] = Key::UP;
+ xkeysym_map[XK_Right] = Key::RIGHT;
+ xkeysym_map[XK_Down] = Key::DOWN;
+ xkeysym_map[XK_Prior] = Key::PAGEUP;
+ xkeysym_map[XK_Next] = Key::PAGEDOWN;
+ xkeysym_map[XK_Shift_L] = Key::SHIFT;
+ xkeysym_map[XK_Shift_R] = Key::SHIFT;
+ xkeysym_map[XK_Shift_Lock] = Key::SHIFT;
+ xkeysym_map[XK_Control_L] = Key::CTRL;
+ xkeysym_map[XK_Control_R] = Key::CTRL;
+ xkeysym_map[XK_Meta_L] = Key::META;
+ xkeysym_map[XK_Meta_R] = Key::META;
+ xkeysym_map[XK_Alt_L] = Key::ALT;
+ xkeysym_map[XK_Alt_R] = Key::ALT;
+ xkeysym_map[XK_Caps_Lock] = Key::CAPSLOCK;
+ xkeysym_map[XK_Num_Lock] = Key::NUMLOCK;
+ xkeysym_map[XK_Scroll_Lock] = Key::SCROLLLOCK;
+ xkeysym_map[XK_less] = Key::QUOTELEFT;
+ xkeysym_map[XK_grave] = Key::SECTION;
+ xkeysym_map[XK_Super_L] = Key::META;
+ xkeysym_map[XK_Super_R] = Key::META;
+ xkeysym_map[XK_Menu] = Key::MENU;
+ xkeysym_map[XK_Hyper_L] = Key::HYPER;
+ xkeysym_map[XK_Hyper_R] = Key::HYPER;
+ xkeysym_map[XK_Help] = Key::HELP;
+ xkeysym_map[XK_KP_Space] = Key::SPACE;
+ xkeysym_map[XK_KP_Tab] = Key::TAB;
+ xkeysym_map[XK_KP_Enter] = Key::KP_ENTER;
+ xkeysym_map[XK_Home] = Key::HOME;
+ xkeysym_map[XK_Left] = Key::LEFT;
+ xkeysym_map[XK_Up] = Key::UP;
+ xkeysym_map[XK_Right] = Key::RIGHT;
+ xkeysym_map[XK_Down] = Key::DOWN;
+ xkeysym_map[XK_Prior] = Key::PAGEUP;
+ xkeysym_map[XK_Next] = Key::PAGEDOWN;
+ xkeysym_map[XK_End] = Key::END;
+ xkeysym_map[XK_Begin] = Key::CLEAR;
+ xkeysym_map[XK_Insert] = Key::INSERT;
+ xkeysym_map[XK_Delete] = Key::KEY_DELETE;
+ //xkeysym_map[XK_KP_Equal]
+ //xkeysym_map[XK_KP_Separator]
+ xkeysym_map[XK_KP_Decimal] = Key::KP_PERIOD;
+ xkeysym_map[XK_KP_Delete] = Key::KP_PERIOD;
+ xkeysym_map[XK_KP_Multiply] = Key::KP_MULTIPLY;
+ xkeysym_map[XK_KP_Divide] = Key::KP_DIVIDE;
+ xkeysym_map[XK_KP_Subtract] = Key::KP_SUBTRACT;
+ xkeysym_map[XK_KP_Add] = Key::KP_ADD;
+ xkeysym_map[XK_KP_0] = Key::KP_0;
+ xkeysym_map[XK_KP_1] = Key::KP_1;
+ xkeysym_map[XK_KP_2] = Key::KP_2;
+ xkeysym_map[XK_KP_3] = Key::KP_3;
+ xkeysym_map[XK_KP_4] = Key::KP_4;
+ xkeysym_map[XK_KP_5] = Key::KP_5;
+ xkeysym_map[XK_KP_6] = Key::KP_6;
+ xkeysym_map[XK_KP_7] = Key::KP_7;
+ xkeysym_map[XK_KP_8] = Key::KP_8;
+ xkeysym_map[XK_KP_9] = Key::KP_9;
+ // Same keys but with numlock off.
+ xkeysym_map[XK_KP_Insert] = Key::INSERT;
+ xkeysym_map[XK_KP_End] = Key::END;
+ xkeysym_map[XK_KP_Down] = Key::DOWN;
+ xkeysym_map[XK_KP_Page_Down] = Key::PAGEDOWN;
+ xkeysym_map[XK_KP_Left] = Key::LEFT;
+ // X11 documents this (numpad 5) as "begin of line" but no toolkit seems to interpret it this way.
+ // On Windows this is emitting Key::Clear so for consistency it will be mapped to Key::Clear
+ xkeysym_map[XK_KP_Begin] = Key::CLEAR;
+ xkeysym_map[XK_KP_Right] = Key::RIGHT;
+ xkeysym_map[XK_KP_Home] = Key::HOME;
+ xkeysym_map[XK_KP_Up] = Key::UP;
+ xkeysym_map[XK_KP_Page_Up] = Key::PAGEUP;
+ xkeysym_map[XK_F1] = Key::F1;
+ xkeysym_map[XK_F2] = Key::F2;
+ xkeysym_map[XK_F3] = Key::F3;
+ xkeysym_map[XK_F4] = Key::F4;
+ xkeysym_map[XK_F5] = Key::F5;
+ xkeysym_map[XK_F6] = Key::F6;
+ xkeysym_map[XK_F7] = Key::F7;
+ xkeysym_map[XK_F8] = Key::F8;
+ xkeysym_map[XK_F9] = Key::F9;
+ xkeysym_map[XK_F10] = Key::F10;
+ xkeysym_map[XK_F11] = Key::F11;
+ xkeysym_map[XK_F12] = Key::F12;
+ xkeysym_map[XK_F13] = Key::F13;
+ xkeysym_map[XK_F14] = Key::F14;
+ xkeysym_map[XK_F15] = Key::F15;
+ xkeysym_map[XK_F16] = Key::F16;
+ xkeysym_map[XK_F17] = Key::F17;
+ xkeysym_map[XK_F18] = Key::F18;
+ xkeysym_map[XK_F19] = Key::F19;
+ xkeysym_map[XK_F20] = Key::F20;
+ xkeysym_map[XK_F21] = Key::F21;
+ xkeysym_map[XK_F22] = Key::F22;
+ xkeysym_map[XK_F23] = Key::F23;
+ xkeysym_map[XK_F24] = Key::F24;
+ xkeysym_map[XK_F25] = Key::F25;
+ xkeysym_map[XK_F26] = Key::F26;
+ xkeysym_map[XK_F27] = Key::F27;
+ xkeysym_map[XK_F28] = Key::F28;
+ xkeysym_map[XK_F29] = Key::F29;
+ xkeysym_map[XK_F30] = Key::F30;
+ xkeysym_map[XK_F31] = Key::F31;
+ xkeysym_map[XK_F32] = Key::F32;
+ xkeysym_map[XK_F33] = Key::F33;
+ xkeysym_map[XK_F34] = Key::F34;
+ xkeysym_map[XK_F35] = Key::F35;
+ xkeysym_map[XK_yen] = Key::YEN;
+ xkeysym_map[XK_section] = Key::SECTION;
+ // Media keys.
+ xkeysym_map[XF86XK_Back] = Key::BACK;
+ xkeysym_map[XF86XK_Forward] = Key::FORWARD;
+ xkeysym_map[XF86XK_Stop] = Key::STOP;
+ xkeysym_map[XF86XK_Refresh] = Key::REFRESH;
+ xkeysym_map[XF86XK_Favorites] = Key::FAVORITES;
+ xkeysym_map[XF86XK_OpenURL] = Key::OPENURL;
+ xkeysym_map[XF86XK_HomePage] = Key::HOMEPAGE;
+ xkeysym_map[XF86XK_Search] = Key::SEARCH;
+ xkeysym_map[XF86XK_AudioLowerVolume] = Key::VOLUMEDOWN;
+ xkeysym_map[XF86XK_AudioMute] = Key::VOLUMEMUTE;
+ xkeysym_map[XF86XK_AudioRaiseVolume] = Key::VOLUMEUP;
+ xkeysym_map[XF86XK_AudioPlay] = Key::MEDIAPLAY;
+ xkeysym_map[XF86XK_AudioStop] = Key::MEDIASTOP;
+ xkeysym_map[XF86XK_AudioPrev] = Key::MEDIAPREVIOUS;
+ xkeysym_map[XF86XK_AudioNext] = Key::MEDIANEXT;
+ xkeysym_map[XF86XK_AudioRecord] = Key::MEDIARECORD;
+ xkeysym_map[XF86XK_Standby] = Key::STANDBY;
+ // Launch keys.
+ xkeysym_map[XF86XK_Mail] = Key::LAUNCHMAIL;
+ xkeysym_map[XF86XK_AudioMedia] = Key::LAUNCHMEDIA;
+ xkeysym_map[XF86XK_MyComputer] = Key::LAUNCH0;
+ xkeysym_map[XF86XK_Calculator] = Key::LAUNCH1;
+ xkeysym_map[XF86XK_Launch0] = Key::LAUNCH2;
+ xkeysym_map[XF86XK_Launch1] = Key::LAUNCH3;
+ xkeysym_map[XF86XK_Launch2] = Key::LAUNCH4;
+ xkeysym_map[XF86XK_Launch3] = Key::LAUNCH5;
+ xkeysym_map[XF86XK_Launch4] = Key::LAUNCH6;
+ xkeysym_map[XF86XK_Launch5] = Key::LAUNCH7;
+ xkeysym_map[XF86XK_Launch6] = Key::LAUNCH8;
+ xkeysym_map[XF86XK_Launch7] = Key::LAUNCH9;
+ xkeysym_map[XF86XK_Launch8] = Key::LAUNCHA;
+ xkeysym_map[XF86XK_Launch9] = Key::LAUNCHB;
+ xkeysym_map[XF86XK_LaunchA] = Key::LAUNCHC;
+ xkeysym_map[XF86XK_LaunchB] = Key::LAUNCHD;
+ xkeysym_map[XF86XK_LaunchC] = Key::LAUNCHE;
+ xkeysym_map[XF86XK_LaunchD] = Key::LAUNCHF;
- // launch keys
- { XF86XK_Mail, Key::LAUNCHMAIL },
- { XF86XK_MyComputer, Key::LAUNCH0 },
- { XF86XK_Calculator, Key::LAUNCH1 },
- { XF86XK_Standby, Key::STANDBY },
+ // Scancode to Godot Key map.
+ scancode_map[0x09] = Key::ESCAPE;
+ scancode_map[0x0A] = Key::KEY_1;
+ scancode_map[0x0B] = Key::KEY_2;
+ scancode_map[0x0C] = Key::KEY_3;
+ scancode_map[0x0D] = Key::KEY_4;
+ scancode_map[0x0E] = Key::KEY_5;
+ scancode_map[0x0F] = Key::KEY_6;
+ scancode_map[0x10] = Key::KEY_7;
+ scancode_map[0x11] = Key::KEY_8;
+ scancode_map[0x12] = Key::KEY_9;
+ scancode_map[0x13] = Key::KEY_0;
+ scancode_map[0x14] = Key::MINUS;
+ scancode_map[0x15] = Key::EQUAL;
+ scancode_map[0x16] = Key::BACKSPACE;
+ scancode_map[0x17] = Key::TAB;
+ scancode_map[0x18] = Key::Q;
+ scancode_map[0x19] = Key::W;
+ scancode_map[0x1A] = Key::E;
+ scancode_map[0x1B] = Key::R;
+ scancode_map[0x1C] = Key::T;
+ scancode_map[0x1D] = Key::Y;
+ scancode_map[0x1E] = Key::U;
+ scancode_map[0x1F] = Key::I;
+ scancode_map[0x20] = Key::O;
+ scancode_map[0x21] = Key::P;
+ scancode_map[0x22] = Key::BRACELEFT;
+ scancode_map[0x23] = Key::BRACERIGHT;
+ scancode_map[0x24] = Key::ENTER;
+ scancode_map[0x25] = Key::CTRL;
+ scancode_map[0x26] = Key::A;
+ scancode_map[0x27] = Key::S;
+ scancode_map[0x28] = Key::D;
+ scancode_map[0x29] = Key::F;
+ scancode_map[0x2A] = Key::G;
+ scancode_map[0x2B] = Key::H;
+ scancode_map[0x2C] = Key::J;
+ scancode_map[0x2D] = Key::K;
+ scancode_map[0x2E] = Key::L;
+ scancode_map[0x2F] = Key::SEMICOLON;
+ scancode_map[0x30] = Key::APOSTROPHE;
+ scancode_map[0x31] = Key::SECTION;
+ scancode_map[0x32] = Key::SHIFT;
+ scancode_map[0x33] = Key::BACKSLASH;
+ scancode_map[0x34] = Key::Z;
+ scancode_map[0x35] = Key::X;
+ scancode_map[0x36] = Key::C;
+ scancode_map[0x37] = Key::V;
+ scancode_map[0x38] = Key::B;
+ scancode_map[0x39] = Key::N;
+ scancode_map[0x3A] = Key::M;
+ scancode_map[0x3B] = Key::COMMA;
+ scancode_map[0x3C] = Key::PERIOD;
+ scancode_map[0x3D] = Key::SLASH;
+ scancode_map[0x3E] = Key::SHIFT;
+ scancode_map[0x3F] = Key::KP_MULTIPLY;
+ scancode_map[0x40] = Key::ALT;
+ scancode_map[0x41] = Key::SPACE;
+ scancode_map[0x42] = Key::CAPSLOCK;
+ scancode_map[0x43] = Key::F1;
+ scancode_map[0x44] = Key::F2;
+ scancode_map[0x45] = Key::F3;
+ scancode_map[0x46] = Key::F4;
+ scancode_map[0x47] = Key::F5;
+ scancode_map[0x48] = Key::F6;
+ scancode_map[0x49] = Key::F7;
+ scancode_map[0x4A] = Key::F8;
+ scancode_map[0x4B] = Key::F9;
+ scancode_map[0x4C] = Key::F10;
+ scancode_map[0x4D] = Key::NUMLOCK;
+ scancode_map[0x4E] = Key::SCROLLLOCK;
+ scancode_map[0x4F] = Key::KP_7;
+ scancode_map[0x50] = Key::KP_8;
+ scancode_map[0x51] = Key::KP_9;
+ scancode_map[0x52] = Key::KP_SUBTRACT;
+ scancode_map[0x53] = Key::KP_4;
+ scancode_map[0x54] = Key::KP_5;
+ scancode_map[0x55] = Key::KP_6;
+ scancode_map[0x56] = Key::KP_ADD;
+ scancode_map[0x57] = Key::KP_1;
+ scancode_map[0x58] = Key::KP_2;
+ scancode_map[0x59] = Key::KP_3;
+ scancode_map[0x5A] = Key::KP_0;
+ scancode_map[0x5B] = Key::KP_PERIOD;
+ scancode_map[0x5E] = Key::QUOTELEFT;
+ scancode_map[0x5F] = Key::F11;
+ scancode_map[0x60] = Key::F12;
+ scancode_map[0x68] = Key::KP_ENTER;
+ scancode_map[0x69] = Key::CTRL;
+ scancode_map[0x6A] = Key::KP_DIVIDE;
+ scancode_map[0x6B] = Key::PRINT;
+ scancode_map[0x6C] = Key::ALT;
+ scancode_map[0x6D] = Key::ENTER;
+ scancode_map[0x6E] = Key::HOME;
+ scancode_map[0x6F] = Key::UP;
+ scancode_map[0x70] = Key::PAGEUP;
+ scancode_map[0x71] = Key::LEFT;
+ scancode_map[0x72] = Key::RIGHT;
+ scancode_map[0x73] = Key::END;
+ scancode_map[0x74] = Key::DOWN;
+ scancode_map[0x75] = Key::PAGEDOWN;
+ scancode_map[0x76] = Key::INSERT;
+ scancode_map[0x77] = Key::KEY_DELETE;
+ scancode_map[0x79] = Key::VOLUMEMUTE;
+ scancode_map[0x7A] = Key::VOLUMEDOWN;
+ scancode_map[0x7B] = Key::VOLUMEUP;
+ scancode_map[0x7F] = Key::PAUSE;
+ scancode_map[0x85] = Key::META;
+ scancode_map[0x86] = Key::META;
+ scancode_map[0x87] = Key::MENU;
+ scancode_map[0xBF] = Key::F13;
+ scancode_map[0xC0] = Key::F14;
+ scancode_map[0xC1] = Key::F15;
+ scancode_map[0xC2] = Key::F16;
+ scancode_map[0xC3] = Key::F17;
+ scancode_map[0xC4] = Key::F18;
+ scancode_map[0xC5] = Key::F19;
+ scancode_map[0xC6] = Key::F20;
+ scancode_map[0xC7] = Key::F21;
+ scancode_map[0xC8] = Key::F22;
+ scancode_map[0xC9] = Key::F23;
+ scancode_map[0xCA] = Key::F24;
+ scancode_map[0xCB] = Key::F25;
+ scancode_map[0xCC] = Key::F26;
+ scancode_map[0xCD] = Key::F27;
+ scancode_map[0xCE] = Key::F28;
+ scancode_map[0xCF] = Key::F29;
+ scancode_map[0xD0] = Key::F30;
+ scancode_map[0xD1] = Key::F31;
+ scancode_map[0xD2] = Key::F32;
+ scancode_map[0xD3] = Key::F33;
+ scancode_map[0xD4] = Key::F34;
+ scancode_map[0xD5] = Key::F35;
- { XF86XK_Launch0, Key::LAUNCH2 },
- { XF86XK_Launch1, Key::LAUNCH3 },
- { XF86XK_Launch2, Key::LAUNCH4 },
- { XF86XK_Launch3, Key::LAUNCH5 },
- { XF86XK_Launch4, Key::LAUNCH6 },
- { XF86XK_Launch5, Key::LAUNCH7 },
- { XF86XK_Launch6, Key::LAUNCH8 },
- { XF86XK_Launch7, Key::LAUNCH9 },
- { XF86XK_Launch8, Key::LAUNCHA },
- { XF86XK_Launch9, Key::LAUNCHB },
- { XF86XK_LaunchA, Key::LAUNCHC },
- { XF86XK_LaunchB, Key::LAUNCHD },
- { XF86XK_LaunchC, Key::LAUNCHE },
- { XF86XK_LaunchD, Key::LAUNCHF },
-
- { 0, Key::NONE }
-};
-
-struct _TranslatePair {
- Key keysym;
- unsigned int keycode;
-};
-
-static _TranslatePair _scancode_to_keycode[] = {
- { Key::ESCAPE, 0x09 },
- { Key::KEY_1, 0x0A },
- { Key::KEY_2, 0x0B },
- { Key::KEY_3, 0x0C },
- { Key::KEY_4, 0x0D },
- { Key::KEY_5, 0x0E },
- { Key::KEY_6, 0x0F },
- { Key::KEY_7, 0x10 },
- { Key::KEY_8, 0x11 },
- { Key::KEY_9, 0x12 },
- { Key::KEY_0, 0x13 },
- { Key::MINUS, 0x14 },
- { Key::EQUAL, 0x15 },
- { Key::BACKSPACE, 0x16 },
- { Key::TAB, 0x17 },
- { Key::Q, 0x18 },
- { Key::W, 0x19 },
- { Key::E, 0x1A },
- { Key::R, 0x1B },
- { Key::T, 0x1C },
- { Key::Y, 0x1D },
- { Key::U, 0x1E },
- { Key::I, 0x1F },
- { Key::O, 0x20 },
- { Key::P, 0x21 },
- { Key::BRACELEFT, 0x22 },
- { Key::BRACERIGHT, 0x23 },
- { Key::ENTER, 0x24 },
- { Key::CTRL, 0x25 },
- { Key::A, 0x26 },
- { Key::S, 0x27 },
- { Key::D, 0x28 },
- { Key::F, 0x29 },
- { Key::G, 0x2A },
- { Key::H, 0x2B },
- { Key::J, 0x2C },
- { Key::K, 0x2D },
- { Key::L, 0x2E },
- { Key::SEMICOLON, 0x2F },
- { Key::APOSTROPHE, 0x30 },
- { Key::QUOTELEFT, 0x31 },
- { Key::SHIFT, 0x32 },
- { Key::BACKSLASH, 0x33 },
- { Key::Z, 0x34 },
- { Key::X, 0x35 },
- { Key::C, 0x36 },
- { Key::V, 0x37 },
- { Key::B, 0x38 },
- { Key::N, 0x39 },
- { Key::M, 0x3A },
- { Key::COMMA, 0x3B },
- { Key::PERIOD, 0x3C },
- { Key::SLASH, 0x3D },
- { Key::SHIFT, 0x3E },
- { Key::KP_MULTIPLY, 0x3F },
- { Key::ALT, 0x40 },
- { Key::SPACE, 0x41 },
- { Key::CAPSLOCK, 0x42 },
- { Key::F1, 0x43 },
- { Key::F2, 0x44 },
- { Key::F3, 0x45 },
- { Key::F4, 0x46 },
- { Key::F5, 0x47 },
- { Key::F6, 0x48 },
- { Key::F7, 0x49 },
- { Key::F8, 0x4A },
- { Key::F9, 0x4B },
- { Key::F10, 0x4C },
- { Key::NUMLOCK, 0x4D },
- { Key::SCROLLLOCK, 0x4E },
- { Key::KP_7, 0x4F },
- { Key::KP_8, 0x50 },
- { Key::KP_9, 0x51 },
- { Key::KP_SUBTRACT, 0x52 },
- { Key::KP_4, 0x53 },
- { Key::KP_5, 0x54 },
- { Key::KP_6, 0x55 },
- { Key::KP_ADD, 0x56 },
- { Key::KP_1, 0x57 },
- { Key::KP_2, 0x58 },
- { Key::KP_3, 0x59 },
- { Key::KP_0, 0x5A },
- { Key::KP_PERIOD, 0x5B },
- //{ Key::???, 0x5E }, //NON US BACKSLASH
- { Key::F11, 0x5F },
- { Key::F12, 0x60 },
- { Key::KP_ENTER, 0x68 },
- { Key::CTRL, 0x69 },
- { Key::KP_DIVIDE, 0x6A },
- { Key::PRINT, 0x6B },
- { Key::ALT, 0x6C },
- { Key::ENTER, 0x6D },
- { Key::HOME, 0x6E },
- { Key::UP, 0x6F },
- { Key::PAGEUP, 0x70 },
- { Key::LEFT, 0x71 },
- { Key::RIGHT, 0x72 },
- { Key::END, 0x73 },
- { Key::DOWN, 0x74 },
- { Key::PAGEDOWN, 0x75 },
- { Key::INSERT, 0x76 },
- { Key::KEY_DELETE, 0x77 },
- { Key::VOLUMEMUTE, 0x79 },
- { Key::VOLUMEDOWN, 0x7A },
- { Key::VOLUMEUP, 0x7B },
- { Key::PAUSE, 0x7F },
- { Key::SUPER_L, 0x85 },
- { Key::SUPER_R, 0x86 },
- { Key::MENU, 0x87 },
- { Key::F13, 0xBF },
- { Key::F14, 0xC0 },
- { Key::F15, 0xC1 },
- { Key::F16, 0xC2 },
- { Key::F17, 0xC3 },
- { Key::F18, 0xC4 },
- { Key::F19, 0xC5 },
- { Key::F20, 0xC6 },
- { Key::F21, 0xC7 },
- { Key::F22, 0xC8 },
- { Key::F23, 0xC9 },
- { Key::F24, 0xCA },
- { Key::F25, 0xCB },
- { Key::F26, 0xCC },
- { Key::F27, 0xCD },
- { Key::F28, 0xCE },
- { Key::F29, 0xCF },
- { Key::F30, 0xD0 },
- { Key::F31, 0xD1 },
- { Key::F32, 0xD2 },
- { Key::F33, 0xD3 },
- { Key::F34, 0xD4 },
- { Key::F35, 0xD5 },
- { Key::UNKNOWN, 0 }
-};
-
-Key KeyMappingX11::get_scancode(unsigned int p_code) {
- Key keycode = Key::UNKNOWN;
- for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) {
- if (_scancode_to_keycode[i].keycode == p_code) {
- keycode = _scancode_to_keycode[i].keysym;
- break;
- }
+ // Godot to scancode map.
+ for (const KeyValue<unsigned int, Key> &E : scancode_map) {
+ scancode_map_inv[E.value] = E.key;
}
- return keycode;
+ // Keysym to Unicode map, tables taken from FOX toolkit.
+ xkeysym_unicode_map[0x01A1] = 0x0104;
+ xkeysym_unicode_map[0x01A2] = 0x02D8;
+ xkeysym_unicode_map[0x01A3] = 0x0141;
+ xkeysym_unicode_map[0x01A5] = 0x013D;
+ xkeysym_unicode_map[0x01A6] = 0x015A;
+ xkeysym_unicode_map[0x01A9] = 0x0160;
+ xkeysym_unicode_map[0x01AA] = 0x015E;
+ xkeysym_unicode_map[0x01AB] = 0x0164;
+ xkeysym_unicode_map[0x01AC] = 0x0179;
+ xkeysym_unicode_map[0x01AE] = 0x017D;
+ xkeysym_unicode_map[0x01AF] = 0x017B;
+ xkeysym_unicode_map[0x01B1] = 0x0105;
+ xkeysym_unicode_map[0x01B2] = 0x02DB;
+ xkeysym_unicode_map[0x01B3] = 0x0142;
+ xkeysym_unicode_map[0x01B5] = 0x013E;
+ xkeysym_unicode_map[0x01B6] = 0x015B;
+ xkeysym_unicode_map[0x01B7] = 0x02C7;
+ xkeysym_unicode_map[0x01B9] = 0x0161;
+ xkeysym_unicode_map[0x01BA] = 0x015F;
+ xkeysym_unicode_map[0x01BB] = 0x0165;
+ xkeysym_unicode_map[0x01BC] = 0x017A;
+ xkeysym_unicode_map[0x01BD] = 0x02DD;
+ xkeysym_unicode_map[0x01BE] = 0x017E;
+ xkeysym_unicode_map[0x01BF] = 0x017C;
+ xkeysym_unicode_map[0x01C0] = 0x0154;
+ xkeysym_unicode_map[0x01C3] = 0x0102;
+ xkeysym_unicode_map[0x01C5] = 0x0139;
+ xkeysym_unicode_map[0x01C6] = 0x0106;
+ xkeysym_unicode_map[0x01C8] = 0x010C;
+ xkeysym_unicode_map[0x01CA] = 0x0118;
+ xkeysym_unicode_map[0x01CC] = 0x011A;
+ xkeysym_unicode_map[0x01CF] = 0x010E;
+ xkeysym_unicode_map[0x01D0] = 0x0110;
+ xkeysym_unicode_map[0x01D1] = 0x0143;
+ xkeysym_unicode_map[0x01D2] = 0x0147;
+ xkeysym_unicode_map[0x01D5] = 0x0150;
+ xkeysym_unicode_map[0x01D8] = 0x0158;
+ xkeysym_unicode_map[0x01D9] = 0x016E;
+ xkeysym_unicode_map[0x01DB] = 0x0170;
+ xkeysym_unicode_map[0x01DE] = 0x0162;
+ xkeysym_unicode_map[0x01E0] = 0x0155;
+ xkeysym_unicode_map[0x01E3] = 0x0103;
+ xkeysym_unicode_map[0x01E5] = 0x013A;
+ xkeysym_unicode_map[0x01E6] = 0x0107;
+ xkeysym_unicode_map[0x01E8] = 0x010D;
+ xkeysym_unicode_map[0x01EA] = 0x0119;
+ xkeysym_unicode_map[0x01EC] = 0x011B;
+ xkeysym_unicode_map[0x01EF] = 0x010F;
+ xkeysym_unicode_map[0x01F0] = 0x0111;
+ xkeysym_unicode_map[0x01F1] = 0x0144;
+ xkeysym_unicode_map[0x01F2] = 0x0148;
+ xkeysym_unicode_map[0x01F5] = 0x0151;
+ xkeysym_unicode_map[0x01F8] = 0x0159;
+ xkeysym_unicode_map[0x01F9] = 0x016F;
+ xkeysym_unicode_map[0x01FB] = 0x0171;
+ xkeysym_unicode_map[0x01FE] = 0x0163;
+ xkeysym_unicode_map[0x01FF] = 0x02D9;
+ xkeysym_unicode_map[0x02A1] = 0x0126;
+ xkeysym_unicode_map[0x02A6] = 0x0124;
+ xkeysym_unicode_map[0x02A9] = 0x0130;
+ xkeysym_unicode_map[0x02AB] = 0x011E;
+ xkeysym_unicode_map[0x02AC] = 0x0134;
+ xkeysym_unicode_map[0x02B1] = 0x0127;
+ xkeysym_unicode_map[0x02B6] = 0x0125;
+ xkeysym_unicode_map[0x02B9] = 0x0131;
+ xkeysym_unicode_map[0x02BB] = 0x011F;
+ xkeysym_unicode_map[0x02BC] = 0x0135;
+ xkeysym_unicode_map[0x02C5] = 0x010A;
+ xkeysym_unicode_map[0x02C6] = 0x0108;
+ xkeysym_unicode_map[0x02D5] = 0x0120;
+ xkeysym_unicode_map[0x02D8] = 0x011C;
+ xkeysym_unicode_map[0x02DD] = 0x016C;
+ xkeysym_unicode_map[0x02DE] = 0x015C;
+ xkeysym_unicode_map[0x02E5] = 0x010B;
+ xkeysym_unicode_map[0x02E6] = 0x0109;
+ xkeysym_unicode_map[0x02F5] = 0x0121;
+ xkeysym_unicode_map[0x02F8] = 0x011D;
+ xkeysym_unicode_map[0x02FD] = 0x016D;
+ xkeysym_unicode_map[0x02FE] = 0x015D;
+ xkeysym_unicode_map[0x03A2] = 0x0138;
+ xkeysym_unicode_map[0x03A3] = 0x0156;
+ xkeysym_unicode_map[0x03A5] = 0x0128;
+ xkeysym_unicode_map[0x03A6] = 0x013B;
+ xkeysym_unicode_map[0x03AA] = 0x0112;
+ xkeysym_unicode_map[0x03AB] = 0x0122;
+ xkeysym_unicode_map[0x03AC] = 0x0166;
+ xkeysym_unicode_map[0x03B3] = 0x0157;
+ xkeysym_unicode_map[0x03B5] = 0x0129;
+ xkeysym_unicode_map[0x03B6] = 0x013C;
+ xkeysym_unicode_map[0x03BA] = 0x0113;
+ xkeysym_unicode_map[0x03BB] = 0x0123;
+ xkeysym_unicode_map[0x03BC] = 0x0167;
+ xkeysym_unicode_map[0x03BD] = 0x014A;
+ xkeysym_unicode_map[0x03BF] = 0x014B;
+ xkeysym_unicode_map[0x03C0] = 0x0100;
+ xkeysym_unicode_map[0x03C7] = 0x012E;
+ xkeysym_unicode_map[0x03CC] = 0x0116;
+ xkeysym_unicode_map[0x03CF] = 0x012A;
+ xkeysym_unicode_map[0x03D1] = 0x0145;
+ xkeysym_unicode_map[0x03D2] = 0x014C;
+ xkeysym_unicode_map[0x03D3] = 0x0136;
+ xkeysym_unicode_map[0x03D9] = 0x0172;
+ xkeysym_unicode_map[0x03DD] = 0x0168;
+ xkeysym_unicode_map[0x03DE] = 0x016A;
+ xkeysym_unicode_map[0x03E0] = 0x0101;
+ xkeysym_unicode_map[0x03E7] = 0x012F;
+ xkeysym_unicode_map[0x03EC] = 0x0117;
+ xkeysym_unicode_map[0x03EF] = 0x012B;
+ xkeysym_unicode_map[0x03F1] = 0x0146;
+ xkeysym_unicode_map[0x03F2] = 0x014D;
+ xkeysym_unicode_map[0x03F3] = 0x0137;
+ xkeysym_unicode_map[0x03F9] = 0x0173;
+ xkeysym_unicode_map[0x03FD] = 0x0169;
+ xkeysym_unicode_map[0x03FE] = 0x016B;
+ xkeysym_unicode_map[0x047E] = 0x203E;
+ xkeysym_unicode_map[0x04A1] = 0x3002;
+ xkeysym_unicode_map[0x04A2] = 0x300C;
+ xkeysym_unicode_map[0x04A3] = 0x300D;
+ xkeysym_unicode_map[0x04A4] = 0x3001;
+ xkeysym_unicode_map[0x04A5] = 0x30FB;
+ xkeysym_unicode_map[0x04A6] = 0x30F2;
+ xkeysym_unicode_map[0x04A7] = 0x30A1;
+ xkeysym_unicode_map[0x04A8] = 0x30A3;
+ xkeysym_unicode_map[0x04A9] = 0x30A5;
+ xkeysym_unicode_map[0x04AA] = 0x30A7;
+ xkeysym_unicode_map[0x04AB] = 0x30A9;
+ xkeysym_unicode_map[0x04AC] = 0x30E3;
+ xkeysym_unicode_map[0x04AD] = 0x30E5;
+ xkeysym_unicode_map[0x04AE] = 0x30E7;
+ xkeysym_unicode_map[0x04AF] = 0x30C3;
+ xkeysym_unicode_map[0x04B0] = 0x30FC;
+ xkeysym_unicode_map[0x04B1] = 0x30A2;
+ xkeysym_unicode_map[0x04B2] = 0x30A4;
+ xkeysym_unicode_map[0x04B3] = 0x30A6;
+ xkeysym_unicode_map[0x04B4] = 0x30A8;
+ xkeysym_unicode_map[0x04B5] = 0x30AA;
+ xkeysym_unicode_map[0x04B6] = 0x30AB;
+ xkeysym_unicode_map[0x04B7] = 0x30AD;
+ xkeysym_unicode_map[0x04B8] = 0x30AF;
+ xkeysym_unicode_map[0x04B9] = 0x30B1;
+ xkeysym_unicode_map[0x04BA] = 0x30B3;
+ xkeysym_unicode_map[0x04BB] = 0x30B5;
+ xkeysym_unicode_map[0x04BC] = 0x30B7;
+ xkeysym_unicode_map[0x04BD] = 0x30B9;
+ xkeysym_unicode_map[0x04BE] = 0x30BB;
+ xkeysym_unicode_map[0x04BF] = 0x30BD;
+ xkeysym_unicode_map[0x04C0] = 0x30BF;
+ xkeysym_unicode_map[0x04C1] = 0x30C1;
+ xkeysym_unicode_map[0x04C2] = 0x30C4;
+ xkeysym_unicode_map[0x04C3] = 0x30C6;
+ xkeysym_unicode_map[0x04C4] = 0x30C8;
+ xkeysym_unicode_map[0x04C5] = 0x30CA;
+ xkeysym_unicode_map[0x04C6] = 0x30CB;
+ xkeysym_unicode_map[0x04C7] = 0x30CC;
+ xkeysym_unicode_map[0x04C8] = 0x30CD;
+ xkeysym_unicode_map[0x04C9] = 0x30CE;
+ xkeysym_unicode_map[0x04CA] = 0x30CF;
+ xkeysym_unicode_map[0x04CB] = 0x30D2;
+ xkeysym_unicode_map[0x04CC] = 0x30D5;
+ xkeysym_unicode_map[0x04CD] = 0x30D8;
+ xkeysym_unicode_map[0x04CE] = 0x30DB;
+ xkeysym_unicode_map[0x04CF] = 0x30DE;
+ xkeysym_unicode_map[0x04D0] = 0x30DF;
+ xkeysym_unicode_map[0x04D1] = 0x30E0;
+ xkeysym_unicode_map[0x04D2] = 0x30E1;
+ xkeysym_unicode_map[0x04D3] = 0x30E2;
+ xkeysym_unicode_map[0x04D4] = 0x30E4;
+ xkeysym_unicode_map[0x04D5] = 0x30E6;
+ xkeysym_unicode_map[0x04D6] = 0x30E8;
+ xkeysym_unicode_map[0x04D7] = 0x30E9;
+ xkeysym_unicode_map[0x04D8] = 0x30EA;
+ xkeysym_unicode_map[0x04D9] = 0x30EB;
+ xkeysym_unicode_map[0x04DA] = 0x30EC;
+ xkeysym_unicode_map[0x04DB] = 0x30ED;
+ xkeysym_unicode_map[0x04DC] = 0x30EF;
+ xkeysym_unicode_map[0x04DD] = 0x30F3;
+ xkeysym_unicode_map[0x04DE] = 0x309B;
+ xkeysym_unicode_map[0x04DF] = 0x309C;
+ xkeysym_unicode_map[0x05AC] = 0x060C;
+ xkeysym_unicode_map[0x05BB] = 0x061B;
+ xkeysym_unicode_map[0x05BF] = 0x061F;
+ xkeysym_unicode_map[0x05C1] = 0x0621;
+ xkeysym_unicode_map[0x05C2] = 0x0622;
+ xkeysym_unicode_map[0x05C3] = 0x0623;
+ xkeysym_unicode_map[0x05C4] = 0x0624;
+ xkeysym_unicode_map[0x05C5] = 0x0625;
+ xkeysym_unicode_map[0x05C6] = 0x0626;
+ xkeysym_unicode_map[0x05C7] = 0x0627;
+ xkeysym_unicode_map[0x05C8] = 0x0628;
+ xkeysym_unicode_map[0x05C9] = 0x0629;
+ xkeysym_unicode_map[0x05CA] = 0x062A;
+ xkeysym_unicode_map[0x05CB] = 0x062B;
+ xkeysym_unicode_map[0x05CC] = 0x062C;
+ xkeysym_unicode_map[0x05CD] = 0x062D;
+ xkeysym_unicode_map[0x05CE] = 0x062E;
+ xkeysym_unicode_map[0x05CF] = 0x062F;
+ xkeysym_unicode_map[0x05D0] = 0x0630;
+ xkeysym_unicode_map[0x05D1] = 0x0631;
+ xkeysym_unicode_map[0x05D2] = 0x0632;
+ xkeysym_unicode_map[0x05D3] = 0x0633;
+ xkeysym_unicode_map[0x05D4] = 0x0634;
+ xkeysym_unicode_map[0x05D5] = 0x0635;
+ xkeysym_unicode_map[0x05D6] = 0x0636;
+ xkeysym_unicode_map[0x05D7] = 0x0637;
+ xkeysym_unicode_map[0x05D8] = 0x0638;
+ xkeysym_unicode_map[0x05D9] = 0x0639;
+ xkeysym_unicode_map[0x05DA] = 0x063A;
+ xkeysym_unicode_map[0x05E0] = 0x0640;
+ xkeysym_unicode_map[0x05E1] = 0x0641;
+ xkeysym_unicode_map[0x05E2] = 0x0642;
+ xkeysym_unicode_map[0x05E3] = 0x0643;
+ xkeysym_unicode_map[0x05E4] = 0x0644;
+ xkeysym_unicode_map[0x05E5] = 0x0645;
+ xkeysym_unicode_map[0x05E6] = 0x0646;
+ xkeysym_unicode_map[0x05E7] = 0x0647;
+ xkeysym_unicode_map[0x05E8] = 0x0648;
+ xkeysym_unicode_map[0x05E9] = 0x0649;
+ xkeysym_unicode_map[0x05EA] = 0x064A;
+ xkeysym_unicode_map[0x05EB] = 0x064B;
+ xkeysym_unicode_map[0x05EC] = 0x064C;
+ xkeysym_unicode_map[0x05ED] = 0x064D;
+ xkeysym_unicode_map[0x05EE] = 0x064E;
+ xkeysym_unicode_map[0x05EF] = 0x064F;
+ xkeysym_unicode_map[0x05F0] = 0x0650;
+ xkeysym_unicode_map[0x05F1] = 0x0651;
+ xkeysym_unicode_map[0x05F2] = 0x0652;
+ xkeysym_unicode_map[0x06A1] = 0x0452;
+ xkeysym_unicode_map[0x06A2] = 0x0453;
+ xkeysym_unicode_map[0x06A3] = 0x0451;
+ xkeysym_unicode_map[0x06A4] = 0x0454;
+ xkeysym_unicode_map[0x06A5] = 0x0455;
+ xkeysym_unicode_map[0x06A6] = 0x0456;
+ xkeysym_unicode_map[0x06A7] = 0x0457;
+ xkeysym_unicode_map[0x06A8] = 0x0458;
+ xkeysym_unicode_map[0x06A9] = 0x0459;
+ xkeysym_unicode_map[0x06AA] = 0x045A;
+ xkeysym_unicode_map[0x06AB] = 0x045B;
+ xkeysym_unicode_map[0x06AC] = 0x045C;
+ xkeysym_unicode_map[0x06AE] = 0x045E;
+ xkeysym_unicode_map[0x06AF] = 0x045F;
+ xkeysym_unicode_map[0x06B0] = 0x2116;
+ xkeysym_unicode_map[0x06B1] = 0x0402;
+ xkeysym_unicode_map[0x06B2] = 0x0403;
+ xkeysym_unicode_map[0x06B3] = 0x0401;
+ xkeysym_unicode_map[0x06B4] = 0x0404;
+ xkeysym_unicode_map[0x06B5] = 0x0405;
+ xkeysym_unicode_map[0x06B6] = 0x0406;
+ xkeysym_unicode_map[0x06B7] = 0x0407;
+ xkeysym_unicode_map[0x06B8] = 0x0408;
+ xkeysym_unicode_map[0x06B9] = 0x0409;
+ xkeysym_unicode_map[0x06BA] = 0x040A;
+ xkeysym_unicode_map[0x06BB] = 0x040B;
+ xkeysym_unicode_map[0x06BC] = 0x040C;
+ xkeysym_unicode_map[0x06BE] = 0x040E;
+ xkeysym_unicode_map[0x06BF] = 0x040F;
+ xkeysym_unicode_map[0x06C0] = 0x044E;
+ xkeysym_unicode_map[0x06C1] = 0x0430;
+ xkeysym_unicode_map[0x06C2] = 0x0431;
+ xkeysym_unicode_map[0x06C3] = 0x0446;
+ xkeysym_unicode_map[0x06C4] = 0x0434;
+ xkeysym_unicode_map[0x06C5] = 0x0435;
+ xkeysym_unicode_map[0x06C6] = 0x0444;
+ xkeysym_unicode_map[0x06C7] = 0x0433;
+ xkeysym_unicode_map[0x06C8] = 0x0445;
+ xkeysym_unicode_map[0x06C9] = 0x0438;
+ xkeysym_unicode_map[0x06CA] = 0x0439;
+ xkeysym_unicode_map[0x06CB] = 0x043A;
+ xkeysym_unicode_map[0x06CC] = 0x043B;
+ xkeysym_unicode_map[0x06CD] = 0x043C;
+ xkeysym_unicode_map[0x06CE] = 0x043D;
+ xkeysym_unicode_map[0x06CF] = 0x043E;
+ xkeysym_unicode_map[0x06D0] = 0x043F;
+ xkeysym_unicode_map[0x06D1] = 0x044F;
+ xkeysym_unicode_map[0x06D2] = 0x0440;
+ xkeysym_unicode_map[0x06D3] = 0x0441;
+ xkeysym_unicode_map[0x06D4] = 0x0442;
+ xkeysym_unicode_map[0x06D5] = 0x0443;
+ xkeysym_unicode_map[0x06D6] = 0x0436;
+ xkeysym_unicode_map[0x06D7] = 0x0432;
+ xkeysym_unicode_map[0x06D8] = 0x044C;
+ xkeysym_unicode_map[0x06D9] = 0x044B;
+ xkeysym_unicode_map[0x06DA] = 0x0437;
+ xkeysym_unicode_map[0x06DB] = 0x0448;
+ xkeysym_unicode_map[0x06DC] = 0x044D;
+ xkeysym_unicode_map[0x06DD] = 0x0449;
+ xkeysym_unicode_map[0x06DE] = 0x0447;
+ xkeysym_unicode_map[0x06DF] = 0x044A;
+ xkeysym_unicode_map[0x06E0] = 0x042E;
+ xkeysym_unicode_map[0x06E1] = 0x0410;
+ xkeysym_unicode_map[0x06E2] = 0x0411;
+ xkeysym_unicode_map[0x06E3] = 0x0426;
+ xkeysym_unicode_map[0x06E4] = 0x0414;
+ xkeysym_unicode_map[0x06E5] = 0x0415;
+ xkeysym_unicode_map[0x06E6] = 0x0424;
+ xkeysym_unicode_map[0x06E7] = 0x0413;
+ xkeysym_unicode_map[0x06E8] = 0x0425;
+ xkeysym_unicode_map[0x06E9] = 0x0418;
+ xkeysym_unicode_map[0x06EA] = 0x0419;
+ xkeysym_unicode_map[0x06EB] = 0x041A;
+ xkeysym_unicode_map[0x06EC] = 0x041B;
+ xkeysym_unicode_map[0x06ED] = 0x041C;
+ xkeysym_unicode_map[0x06EE] = 0x041D;
+ xkeysym_unicode_map[0x06EF] = 0x041E;
+ xkeysym_unicode_map[0x06F0] = 0x041F;
+ xkeysym_unicode_map[0x06F1] = 0x042F;
+ xkeysym_unicode_map[0x06F2] = 0x0420;
+ xkeysym_unicode_map[0x06F3] = 0x0421;
+ xkeysym_unicode_map[0x06F4] = 0x0422;
+ xkeysym_unicode_map[0x06F5] = 0x0423;
+ xkeysym_unicode_map[0x06F6] = 0x0416;
+ xkeysym_unicode_map[0x06F7] = 0x0412;
+ xkeysym_unicode_map[0x06F8] = 0x042C;
+ xkeysym_unicode_map[0x06F9] = 0x042B;
+ xkeysym_unicode_map[0x06FA] = 0x0417;
+ xkeysym_unicode_map[0x06FB] = 0x0428;
+ xkeysym_unicode_map[0x06FC] = 0x042D;
+ xkeysym_unicode_map[0x06FD] = 0x0429;
+ xkeysym_unicode_map[0x06FE] = 0x0427;
+ xkeysym_unicode_map[0x06FF] = 0x042A;
+ xkeysym_unicode_map[0x07A1] = 0x0386;
+ xkeysym_unicode_map[0x07A2] = 0x0388;
+ xkeysym_unicode_map[0x07A3] = 0x0389;
+ xkeysym_unicode_map[0x07A4] = 0x038A;
+ xkeysym_unicode_map[0x07A5] = 0x03AA;
+ xkeysym_unicode_map[0x07A7] = 0x038C;
+ xkeysym_unicode_map[0x07A8] = 0x038E;
+ xkeysym_unicode_map[0x07A9] = 0x03AB;
+ xkeysym_unicode_map[0x07AB] = 0x038F;
+ xkeysym_unicode_map[0x07AE] = 0x0385;
+ xkeysym_unicode_map[0x07AF] = 0x2015;
+ xkeysym_unicode_map[0x07B1] = 0x03AC;
+ xkeysym_unicode_map[0x07B2] = 0x03AD;
+ xkeysym_unicode_map[0x07B3] = 0x03AE;
+ xkeysym_unicode_map[0x07B4] = 0x03AF;
+ xkeysym_unicode_map[0x07B5] = 0x03CA;
+ xkeysym_unicode_map[0x07B6] = 0x0390;
+ xkeysym_unicode_map[0x07B7] = 0x03CC;
+ xkeysym_unicode_map[0x07B8] = 0x03CD;
+ xkeysym_unicode_map[0x07B9] = 0x03CB;
+ xkeysym_unicode_map[0x07BA] = 0x03B0;
+ xkeysym_unicode_map[0x07BB] = 0x03CE;
+ xkeysym_unicode_map[0x07C1] = 0x0391;
+ xkeysym_unicode_map[0x07C2] = 0x0392;
+ xkeysym_unicode_map[0x07C3] = 0x0393;
+ xkeysym_unicode_map[0x07C4] = 0x0394;
+ xkeysym_unicode_map[0x07C5] = 0x0395;
+ xkeysym_unicode_map[0x07C6] = 0x0396;
+ xkeysym_unicode_map[0x07C7] = 0x0397;
+ xkeysym_unicode_map[0x07C8] = 0x0398;
+ xkeysym_unicode_map[0x07C9] = 0x0399;
+ xkeysym_unicode_map[0x07CA] = 0x039A;
+ xkeysym_unicode_map[0x07CB] = 0x039B;
+ xkeysym_unicode_map[0x07CC] = 0x039C;
+ xkeysym_unicode_map[0x07CD] = 0x039D;
+ xkeysym_unicode_map[0x07CE] = 0x039E;
+ xkeysym_unicode_map[0x07CF] = 0x039F;
+ xkeysym_unicode_map[0x07D0] = 0x03A0;
+ xkeysym_unicode_map[0x07D1] = 0x03A1;
+ xkeysym_unicode_map[0x07D2] = 0x03A3;
+ xkeysym_unicode_map[0x07D4] = 0x03A4;
+ xkeysym_unicode_map[0x07D5] = 0x03A5;
+ xkeysym_unicode_map[0x07D6] = 0x03A6;
+ xkeysym_unicode_map[0x07D7] = 0x03A7;
+ xkeysym_unicode_map[0x07D8] = 0x03A8;
+ xkeysym_unicode_map[0x07D9] = 0x03A9;
+ xkeysym_unicode_map[0x07E1] = 0x03B1;
+ xkeysym_unicode_map[0x07E2] = 0x03B2;
+ xkeysym_unicode_map[0x07E3] = 0x03B3;
+ xkeysym_unicode_map[0x07E4] = 0x03B4;
+ xkeysym_unicode_map[0x07E5] = 0x03B5;
+ xkeysym_unicode_map[0x07E6] = 0x03B6;
+ xkeysym_unicode_map[0x07E7] = 0x03B7;
+ xkeysym_unicode_map[0x07E8] = 0x03B8;
+ xkeysym_unicode_map[0x07E9] = 0x03B9;
+ xkeysym_unicode_map[0x07EA] = 0x03BA;
+ xkeysym_unicode_map[0x07EB] = 0x03BB;
+ xkeysym_unicode_map[0x07EC] = 0x03BC;
+ xkeysym_unicode_map[0x07ED] = 0x03BD;
+ xkeysym_unicode_map[0x07EE] = 0x03BE;
+ xkeysym_unicode_map[0x07EF] = 0x03BF;
+ xkeysym_unicode_map[0x07F0] = 0x03C0;
+ xkeysym_unicode_map[0x07F1] = 0x03C1;
+ xkeysym_unicode_map[0x07F2] = 0x03C3;
+ xkeysym_unicode_map[0x07F3] = 0x03C2;
+ xkeysym_unicode_map[0x07F4] = 0x03C4;
+ xkeysym_unicode_map[0x07F5] = 0x03C5;
+ xkeysym_unicode_map[0x07F6] = 0x03C6;
+ xkeysym_unicode_map[0x07F7] = 0x03C7;
+ xkeysym_unicode_map[0x07F8] = 0x03C8;
+ xkeysym_unicode_map[0x07F9] = 0x03C9;
+ xkeysym_unicode_map[0x08A1] = 0x23B7;
+ xkeysym_unicode_map[0x08A2] = 0x250C;
+ xkeysym_unicode_map[0x08A3] = 0x2500;
+ xkeysym_unicode_map[0x08A4] = 0x2320;
+ xkeysym_unicode_map[0x08A5] = 0x2321;
+ xkeysym_unicode_map[0x08A6] = 0x2502;
+ xkeysym_unicode_map[0x08A7] = 0x23A1;
+ xkeysym_unicode_map[0x08A8] = 0x23A3;
+ xkeysym_unicode_map[0x08A9] = 0x23A4;
+ xkeysym_unicode_map[0x08AA] = 0x23A6;
+ xkeysym_unicode_map[0x08AB] = 0x239B;
+ xkeysym_unicode_map[0x08AC] = 0x239D;
+ xkeysym_unicode_map[0x08AD] = 0x239E;
+ xkeysym_unicode_map[0x08AE] = 0x23A0;
+ xkeysym_unicode_map[0x08AF] = 0x23A8;
+ xkeysym_unicode_map[0x08B0] = 0x23AC;
+ xkeysym_unicode_map[0x08BC] = 0x2264;
+ xkeysym_unicode_map[0x08BD] = 0x2260;
+ xkeysym_unicode_map[0x08BE] = 0x2265;
+ xkeysym_unicode_map[0x08BF] = 0x222B;
+ xkeysym_unicode_map[0x08C0] = 0x2234;
+ xkeysym_unicode_map[0x08C1] = 0x221D;
+ xkeysym_unicode_map[0x08C2] = 0x221E;
+ xkeysym_unicode_map[0x08C5] = 0x2207;
+ xkeysym_unicode_map[0x08C8] = 0x223C;
+ xkeysym_unicode_map[0x08C9] = 0x2243;
+ xkeysym_unicode_map[0x08CD] = 0x21D4;
+ xkeysym_unicode_map[0x08CE] = 0x21D2;
+ xkeysym_unicode_map[0x08CF] = 0x2261;
+ xkeysym_unicode_map[0x08D6] = 0x221A;
+ xkeysym_unicode_map[0x08DA] = 0x2282;
+ xkeysym_unicode_map[0x08DB] = 0x2283;
+ xkeysym_unicode_map[0x08DC] = 0x2229;
+ xkeysym_unicode_map[0x08DD] = 0x222A;
+ xkeysym_unicode_map[0x08DE] = 0x2227;
+ xkeysym_unicode_map[0x08DF] = 0x2228;
+ xkeysym_unicode_map[0x08EF] = 0x2202;
+ xkeysym_unicode_map[0x08F6] = 0x0192;
+ xkeysym_unicode_map[0x08FB] = 0x2190;
+ xkeysym_unicode_map[0x08FC] = 0x2191;
+ xkeysym_unicode_map[0x08FD] = 0x2192;
+ xkeysym_unicode_map[0x08FE] = 0x2193;
+ xkeysym_unicode_map[0x09E0] = 0x25C6;
+ xkeysym_unicode_map[0x09E1] = 0x2592;
+ xkeysym_unicode_map[0x09E2] = 0x2409;
+ xkeysym_unicode_map[0x09E3] = 0x240C;
+ xkeysym_unicode_map[0x09E4] = 0x240D;
+ xkeysym_unicode_map[0x09E5] = 0x240A;
+ xkeysym_unicode_map[0x09E8] = 0x2424;
+ xkeysym_unicode_map[0x09E9] = 0x240B;
+ xkeysym_unicode_map[0x09EA] = 0x2518;
+ xkeysym_unicode_map[0x09EB] = 0x2510;
+ xkeysym_unicode_map[0x09EC] = 0x250C;
+ xkeysym_unicode_map[0x09ED] = 0x2514;
+ xkeysym_unicode_map[0x09EE] = 0x253C;
+ xkeysym_unicode_map[0x09EF] = 0x23BA;
+ xkeysym_unicode_map[0x09F0] = 0x23BB;
+ xkeysym_unicode_map[0x09F1] = 0x2500;
+ xkeysym_unicode_map[0x09F2] = 0x23BC;
+ xkeysym_unicode_map[0x09F3] = 0x23BD;
+ xkeysym_unicode_map[0x09F4] = 0x251C;
+ xkeysym_unicode_map[0x09F5] = 0x2524;
+ xkeysym_unicode_map[0x09F6] = 0x2534;
+ xkeysym_unicode_map[0x09F7] = 0x252C;
+ xkeysym_unicode_map[0x09F8] = 0x2502;
+ xkeysym_unicode_map[0x0AA1] = 0x2003;
+ xkeysym_unicode_map[0x0AA2] = 0x2002;
+ xkeysym_unicode_map[0x0AA3] = 0x2004;
+ xkeysym_unicode_map[0x0AA4] = 0x2005;
+ xkeysym_unicode_map[0x0AA5] = 0x2007;
+ xkeysym_unicode_map[0x0AA6] = 0x2008;
+ xkeysym_unicode_map[0x0AA7] = 0x2009;
+ xkeysym_unicode_map[0x0AA8] = 0x200A;
+ xkeysym_unicode_map[0x0AA9] = 0x2014;
+ xkeysym_unicode_map[0x0AAA] = 0x2013;
+ xkeysym_unicode_map[0x0AAE] = 0x2026;
+ xkeysym_unicode_map[0x0AAF] = 0x2025;
+ xkeysym_unicode_map[0x0AB0] = 0x2153;
+ xkeysym_unicode_map[0x0AB1] = 0x2154;
+ xkeysym_unicode_map[0x0AB2] = 0x2155;
+ xkeysym_unicode_map[0x0AB3] = 0x2156;
+ xkeysym_unicode_map[0x0AB4] = 0x2157;
+ xkeysym_unicode_map[0x0AB5] = 0x2158;
+ xkeysym_unicode_map[0x0AB6] = 0x2159;
+ xkeysym_unicode_map[0x0AB7] = 0x215A;
+ xkeysym_unicode_map[0x0AB8] = 0x2105;
+ xkeysym_unicode_map[0x0ABB] = 0x2012;
+ xkeysym_unicode_map[0x0ABC] = 0x2329;
+ xkeysym_unicode_map[0x0ABE] = 0x232A;
+ xkeysym_unicode_map[0x0AC3] = 0x215B;
+ xkeysym_unicode_map[0x0AC4] = 0x215C;
+ xkeysym_unicode_map[0x0AC5] = 0x215D;
+ xkeysym_unicode_map[0x0AC6] = 0x215E;
+ xkeysym_unicode_map[0x0AC9] = 0x2122;
+ xkeysym_unicode_map[0x0ACA] = 0x2613;
+ xkeysym_unicode_map[0x0ACC] = 0x25C1;
+ xkeysym_unicode_map[0x0ACD] = 0x25B7;
+ xkeysym_unicode_map[0x0ACE] = 0x25CB;
+ xkeysym_unicode_map[0x0ACF] = 0x25AF;
+ xkeysym_unicode_map[0x0AD0] = 0x2018;
+ xkeysym_unicode_map[0x0AD1] = 0x2019;
+ xkeysym_unicode_map[0x0AD2] = 0x201C;
+ xkeysym_unicode_map[0x0AD3] = 0x201D;
+ xkeysym_unicode_map[0x0AD4] = 0x211E;
+ xkeysym_unicode_map[0x0AD6] = 0x2032;
+ xkeysym_unicode_map[0x0AD7] = 0x2033;
+ xkeysym_unicode_map[0x0AD9] = 0x271D;
+ xkeysym_unicode_map[0x0ADB] = 0x25AC;
+ xkeysym_unicode_map[0x0ADC] = 0x25C0;
+ xkeysym_unicode_map[0x0ADD] = 0x25B6;
+ xkeysym_unicode_map[0x0ADE] = 0x25CF;
+ xkeysym_unicode_map[0x0ADF] = 0x25AE;
+ xkeysym_unicode_map[0x0AE0] = 0x25E6;
+ xkeysym_unicode_map[0x0AE1] = 0x25AB;
+ xkeysym_unicode_map[0x0AE2] = 0x25AD;
+ xkeysym_unicode_map[0x0AE3] = 0x25B3;
+ xkeysym_unicode_map[0x0AE4] = 0x25BD;
+ xkeysym_unicode_map[0x0AE5] = 0x2606;
+ xkeysym_unicode_map[0x0AE6] = 0x2022;
+ xkeysym_unicode_map[0x0AE7] = 0x25AA;
+ xkeysym_unicode_map[0x0AE8] = 0x25B2;
+ xkeysym_unicode_map[0x0AE9] = 0x25BC;
+ xkeysym_unicode_map[0x0AEA] = 0x261C;
+ xkeysym_unicode_map[0x0AEB] = 0x261E;
+ xkeysym_unicode_map[0x0AEC] = 0x2663;
+ xkeysym_unicode_map[0x0AED] = 0x2666;
+ xkeysym_unicode_map[0x0AEE] = 0x2665;
+ xkeysym_unicode_map[0x0AF0] = 0x2720;
+ xkeysym_unicode_map[0x0AF1] = 0x2020;
+ xkeysym_unicode_map[0x0AF2] = 0x2021;
+ xkeysym_unicode_map[0x0AF3] = 0x2713;
+ xkeysym_unicode_map[0x0AF4] = 0x2717;
+ xkeysym_unicode_map[0x0AF5] = 0x266F;
+ xkeysym_unicode_map[0x0AF6] = 0x266D;
+ xkeysym_unicode_map[0x0AF7] = 0x2642;
+ xkeysym_unicode_map[0x0AF8] = 0x2640;
+ xkeysym_unicode_map[0x0AF9] = 0x260E;
+ xkeysym_unicode_map[0x0AFA] = 0x2315;
+ xkeysym_unicode_map[0x0AFB] = 0x2117;
+ xkeysym_unicode_map[0x0AFC] = 0x2038;
+ xkeysym_unicode_map[0x0AFD] = 0x201A;
+ xkeysym_unicode_map[0x0AFE] = 0x201E;
+ xkeysym_unicode_map[0x0BA3] = 0x003C;
+ xkeysym_unicode_map[0x0BA6] = 0x003E;
+ xkeysym_unicode_map[0x0BA8] = 0x2228;
+ xkeysym_unicode_map[0x0BA9] = 0x2227;
+ xkeysym_unicode_map[0x0BC0] = 0x00AF;
+ xkeysym_unicode_map[0x0BC2] = 0x22A5;
+ xkeysym_unicode_map[0x0BC3] = 0x2229;
+ xkeysym_unicode_map[0x0BC4] = 0x230A;
+ xkeysym_unicode_map[0x0BC6] = 0x005F;
+ xkeysym_unicode_map[0x0BCA] = 0x2218;
+ xkeysym_unicode_map[0x0BCC] = 0x2395;
+ xkeysym_unicode_map[0x0BCE] = 0x22A4;
+ xkeysym_unicode_map[0x0BCF] = 0x25CB;
+ xkeysym_unicode_map[0x0BD3] = 0x2308;
+ xkeysym_unicode_map[0x0BD6] = 0x222A;
+ xkeysym_unicode_map[0x0BD8] = 0x2283;
+ xkeysym_unicode_map[0x0BDA] = 0x2282;
+ xkeysym_unicode_map[0x0BDC] = 0x22A2;
+ xkeysym_unicode_map[0x0BFC] = 0x22A3;
+ xkeysym_unicode_map[0x0CDF] = 0x2017;
+ xkeysym_unicode_map[0x0CE0] = 0x05D0;
+ xkeysym_unicode_map[0x0CE1] = 0x05D1;
+ xkeysym_unicode_map[0x0CE2] = 0x05D2;
+ xkeysym_unicode_map[0x0CE3] = 0x05D3;
+ xkeysym_unicode_map[0x0CE4] = 0x05D4;
+ xkeysym_unicode_map[0x0CE5] = 0x05D5;
+ xkeysym_unicode_map[0x0CE6] = 0x05D6;
+ xkeysym_unicode_map[0x0CE7] = 0x05D7;
+ xkeysym_unicode_map[0x0CE8] = 0x05D8;
+ xkeysym_unicode_map[0x0CE9] = 0x05D9;
+ xkeysym_unicode_map[0x0CEA] = 0x05DA;
+ xkeysym_unicode_map[0x0CEB] = 0x05DB;
+ xkeysym_unicode_map[0x0CEC] = 0x05DC;
+ xkeysym_unicode_map[0x0CED] = 0x05DD;
+ xkeysym_unicode_map[0x0CEE] = 0x05DE;
+ xkeysym_unicode_map[0x0CEF] = 0x05DF;
+ xkeysym_unicode_map[0x0CF0] = 0x05E0;
+ xkeysym_unicode_map[0x0CF1] = 0x05E1;
+ xkeysym_unicode_map[0x0CF2] = 0x05E2;
+ xkeysym_unicode_map[0x0CF3] = 0x05E3;
+ xkeysym_unicode_map[0x0CF4] = 0x05E4;
+ xkeysym_unicode_map[0x0CF5] = 0x05E5;
+ xkeysym_unicode_map[0x0CF6] = 0x05E6;
+ xkeysym_unicode_map[0x0CF7] = 0x05E7;
+ xkeysym_unicode_map[0x0CF8] = 0x05E8;
+ xkeysym_unicode_map[0x0CF9] = 0x05E9;
+ xkeysym_unicode_map[0x0CFA] = 0x05EA;
+ xkeysym_unicode_map[0x0DA1] = 0x0E01;
+ xkeysym_unicode_map[0x0DA2] = 0x0E02;
+ xkeysym_unicode_map[0x0DA3] = 0x0E03;
+ xkeysym_unicode_map[0x0DA4] = 0x0E04;
+ xkeysym_unicode_map[0x0DA5] = 0x0E05;
+ xkeysym_unicode_map[0x0DA6] = 0x0E06;
+ xkeysym_unicode_map[0x0DA7] = 0x0E07;
+ xkeysym_unicode_map[0x0DA8] = 0x0E08;
+ xkeysym_unicode_map[0x0DA9] = 0x0E09;
+ xkeysym_unicode_map[0x0DAA] = 0x0E0A;
+ xkeysym_unicode_map[0x0DAB] = 0x0E0B;
+ xkeysym_unicode_map[0x0DAC] = 0x0E0C;
+ xkeysym_unicode_map[0x0DAD] = 0x0E0D;
+ xkeysym_unicode_map[0x0DAE] = 0x0E0E;
+ xkeysym_unicode_map[0x0DAF] = 0x0E0F;
+ xkeysym_unicode_map[0x0DB0] = 0x0E10;
+ xkeysym_unicode_map[0x0DB1] = 0x0E11;
+ xkeysym_unicode_map[0x0DB2] = 0x0E12;
+ xkeysym_unicode_map[0x0DB3] = 0x0E13;
+ xkeysym_unicode_map[0x0DB4] = 0x0E14;
+ xkeysym_unicode_map[0x0DB5] = 0x0E15;
+ xkeysym_unicode_map[0x0DB6] = 0x0E16;
+ xkeysym_unicode_map[0x0DB7] = 0x0E17;
+ xkeysym_unicode_map[0x0DB8] = 0x0E18;
+ xkeysym_unicode_map[0x0DB9] = 0x0E19;
+ xkeysym_unicode_map[0x0DBA] = 0x0E1A;
+ xkeysym_unicode_map[0x0DBB] = 0x0E1B;
+ xkeysym_unicode_map[0x0DBC] = 0x0E1C;
+ xkeysym_unicode_map[0x0DBD] = 0x0E1D;
+ xkeysym_unicode_map[0x0DBE] = 0x0E1E;
+ xkeysym_unicode_map[0x0DBF] = 0x0E1F;
+ xkeysym_unicode_map[0x0DC0] = 0x0E20;
+ xkeysym_unicode_map[0x0DC1] = 0x0E21;
+ xkeysym_unicode_map[0x0DC2] = 0x0E22;
+ xkeysym_unicode_map[0x0DC3] = 0x0E23;
+ xkeysym_unicode_map[0x0DC4] = 0x0E24;
+ xkeysym_unicode_map[0x0DC5] = 0x0E25;
+ xkeysym_unicode_map[0x0DC6] = 0x0E26;
+ xkeysym_unicode_map[0x0DC7] = 0x0E27;
+ xkeysym_unicode_map[0x0DC8] = 0x0E28;
+ xkeysym_unicode_map[0x0DC9] = 0x0E29;
+ xkeysym_unicode_map[0x0DCA] = 0x0E2A;
+ xkeysym_unicode_map[0x0DCB] = 0x0E2B;
+ xkeysym_unicode_map[0x0DCC] = 0x0E2C;
+ xkeysym_unicode_map[0x0DCD] = 0x0E2D;
+ xkeysym_unicode_map[0x0DCE] = 0x0E2E;
+ xkeysym_unicode_map[0x0DCF] = 0x0E2F;
+ xkeysym_unicode_map[0x0DD0] = 0x0E30;
+ xkeysym_unicode_map[0x0DD1] = 0x0E31;
+ xkeysym_unicode_map[0x0DD2] = 0x0E32;
+ xkeysym_unicode_map[0x0DD3] = 0x0E33;
+ xkeysym_unicode_map[0x0DD4] = 0x0E34;
+ xkeysym_unicode_map[0x0DD5] = 0x0E35;
+ xkeysym_unicode_map[0x0DD6] = 0x0E36;
+ xkeysym_unicode_map[0x0DD7] = 0x0E37;
+ xkeysym_unicode_map[0x0DD8] = 0x0E38;
+ xkeysym_unicode_map[0x0DD9] = 0x0E39;
+ xkeysym_unicode_map[0x0DDA] = 0x0E3A;
+ xkeysym_unicode_map[0x0DDF] = 0x0E3F;
+ xkeysym_unicode_map[0x0DE0] = 0x0E40;
+ xkeysym_unicode_map[0x0DE1] = 0x0E41;
+ xkeysym_unicode_map[0x0DE2] = 0x0E42;
+ xkeysym_unicode_map[0x0DE3] = 0x0E43;
+ xkeysym_unicode_map[0x0DE4] = 0x0E44;
+ xkeysym_unicode_map[0x0DE5] = 0x0E45;
+ xkeysym_unicode_map[0x0DE6] = 0x0E46;
+ xkeysym_unicode_map[0x0DE7] = 0x0E47;
+ xkeysym_unicode_map[0x0DE8] = 0x0E48;
+ xkeysym_unicode_map[0x0DE9] = 0x0E49;
+ xkeysym_unicode_map[0x0DEA] = 0x0E4A;
+ xkeysym_unicode_map[0x0DEB] = 0x0E4B;
+ xkeysym_unicode_map[0x0DEC] = 0x0E4C;
+ xkeysym_unicode_map[0x0DED] = 0x0E4D;
+ xkeysym_unicode_map[0x0DF0] = 0x0E50;
+ xkeysym_unicode_map[0x0DF1] = 0x0E51;
+ xkeysym_unicode_map[0x0DF2] = 0x0E52;
+ xkeysym_unicode_map[0x0DF3] = 0x0E53;
+ xkeysym_unicode_map[0x0DF4] = 0x0E54;
+ xkeysym_unicode_map[0x0DF5] = 0x0E55;
+ xkeysym_unicode_map[0x0DF6] = 0x0E56;
+ xkeysym_unicode_map[0x0DF7] = 0x0E57;
+ xkeysym_unicode_map[0x0DF8] = 0x0E58;
+ xkeysym_unicode_map[0x0DF9] = 0x0E59;
+ xkeysym_unicode_map[0x0EA1] = 0x3131;
+ xkeysym_unicode_map[0x0EA2] = 0x3132;
+ xkeysym_unicode_map[0x0EA3] = 0x3133;
+ xkeysym_unicode_map[0x0EA4] = 0x3134;
+ xkeysym_unicode_map[0x0EA5] = 0x3135;
+ xkeysym_unicode_map[0x0EA6] = 0x3136;
+ xkeysym_unicode_map[0x0EA7] = 0x3137;
+ xkeysym_unicode_map[0x0EA8] = 0x3138;
+ xkeysym_unicode_map[0x0EA9] = 0x3139;
+ xkeysym_unicode_map[0x0EAA] = 0x313A;
+ xkeysym_unicode_map[0x0EAB] = 0x313B;
+ xkeysym_unicode_map[0x0EAC] = 0x313C;
+ xkeysym_unicode_map[0x0EAD] = 0x313D;
+ xkeysym_unicode_map[0x0EAE] = 0x313E;
+ xkeysym_unicode_map[0x0EAF] = 0x313F;
+ xkeysym_unicode_map[0x0EB0] = 0x3140;
+ xkeysym_unicode_map[0x0EB1] = 0x3141;
+ xkeysym_unicode_map[0x0EB2] = 0x3142;
+ xkeysym_unicode_map[0x0EB3] = 0x3143;
+ xkeysym_unicode_map[0x0EB4] = 0x3144;
+ xkeysym_unicode_map[0x0EB5] = 0x3145;
+ xkeysym_unicode_map[0x0EB6] = 0x3146;
+ xkeysym_unicode_map[0x0EB7] = 0x3147;
+ xkeysym_unicode_map[0x0EB8] = 0x3148;
+ xkeysym_unicode_map[0x0EB9] = 0x3149;
+ xkeysym_unicode_map[0x0EBA] = 0x314A;
+ xkeysym_unicode_map[0x0EBB] = 0x314B;
+ xkeysym_unicode_map[0x0EBC] = 0x314C;
+ xkeysym_unicode_map[0x0EBD] = 0x314D;
+ xkeysym_unicode_map[0x0EBE] = 0x314E;
+ xkeysym_unicode_map[0x0EBF] = 0x314F;
+ xkeysym_unicode_map[0x0EC0] = 0x3150;
+ xkeysym_unicode_map[0x0EC1] = 0x3151;
+ xkeysym_unicode_map[0x0EC2] = 0x3152;
+ xkeysym_unicode_map[0x0EC3] = 0x3153;
+ xkeysym_unicode_map[0x0EC4] = 0x3154;
+ xkeysym_unicode_map[0x0EC5] = 0x3155;
+ xkeysym_unicode_map[0x0EC6] = 0x3156;
+ xkeysym_unicode_map[0x0EC7] = 0x3157;
+ xkeysym_unicode_map[0x0EC8] = 0x3158;
+ xkeysym_unicode_map[0x0EC9] = 0x3159;
+ xkeysym_unicode_map[0x0ECA] = 0x315A;
+ xkeysym_unicode_map[0x0ECB] = 0x315B;
+ xkeysym_unicode_map[0x0ECC] = 0x315C;
+ xkeysym_unicode_map[0x0ECD] = 0x315D;
+ xkeysym_unicode_map[0x0ECE] = 0x315E;
+ xkeysym_unicode_map[0x0ECF] = 0x315F;
+ xkeysym_unicode_map[0x0ED0] = 0x3160;
+ xkeysym_unicode_map[0x0ED1] = 0x3161;
+ xkeysym_unicode_map[0x0ED2] = 0x3162;
+ xkeysym_unicode_map[0x0ED3] = 0x3163;
+ xkeysym_unicode_map[0x0ED4] = 0x11A8;
+ xkeysym_unicode_map[0x0ED5] = 0x11A9;
+ xkeysym_unicode_map[0x0ED6] = 0x11AA;
+ xkeysym_unicode_map[0x0ED7] = 0x11AB;
+ xkeysym_unicode_map[0x0ED8] = 0x11AC;
+ xkeysym_unicode_map[0x0ED9] = 0x11AD;
+ xkeysym_unicode_map[0x0EDA] = 0x11AE;
+ xkeysym_unicode_map[0x0EDB] = 0x11AF;
+ xkeysym_unicode_map[0x0EDC] = 0x11B0;
+ xkeysym_unicode_map[0x0EDD] = 0x11B1;
+ xkeysym_unicode_map[0x0EDE] = 0x11B2;
+ xkeysym_unicode_map[0x0EDF] = 0x11B3;
+ xkeysym_unicode_map[0x0EE0] = 0x11B4;
+ xkeysym_unicode_map[0x0EE1] = 0x11B5;
+ xkeysym_unicode_map[0x0EE2] = 0x11B6;
+ xkeysym_unicode_map[0x0EE3] = 0x11B7;
+ xkeysym_unicode_map[0x0EE4] = 0x11B8;
+ xkeysym_unicode_map[0x0EE5] = 0x11B9;
+ xkeysym_unicode_map[0x0EE6] = 0x11BA;
+ xkeysym_unicode_map[0x0EE7] = 0x11BB;
+ xkeysym_unicode_map[0x0EE8] = 0x11BC;
+ xkeysym_unicode_map[0x0EE9] = 0x11BD;
+ xkeysym_unicode_map[0x0EEA] = 0x11BE;
+ xkeysym_unicode_map[0x0EEB] = 0x11BF;
+ xkeysym_unicode_map[0x0EEC] = 0x11C0;
+ xkeysym_unicode_map[0x0EED] = 0x11C1;
+ xkeysym_unicode_map[0x0EEE] = 0x11C2;
+ xkeysym_unicode_map[0x0EEF] = 0x316D;
+ xkeysym_unicode_map[0x0EF0] = 0x3171;
+ xkeysym_unicode_map[0x0EF1] = 0x3178;
+ xkeysym_unicode_map[0x0EF2] = 0x317F;
+ xkeysym_unicode_map[0x0EF3] = 0x3181;
+ xkeysym_unicode_map[0x0EF4] = 0x3184;
+ xkeysym_unicode_map[0x0EF5] = 0x3186;
+ xkeysym_unicode_map[0x0EF6] = 0x318D;
+ xkeysym_unicode_map[0x0EF7] = 0x318E;
+ xkeysym_unicode_map[0x0EF8] = 0x11EB;
+ xkeysym_unicode_map[0x0EF9] = 0x11F0;
+ xkeysym_unicode_map[0x0EFA] = 0x11F9;
+ xkeysym_unicode_map[0x0EFF] = 0x20A9;
+ xkeysym_unicode_map[0x13A4] = 0x20AC;
+ xkeysym_unicode_map[0x13BC] = 0x0152;
+ xkeysym_unicode_map[0x13BD] = 0x0153;
+ xkeysym_unicode_map[0x13BE] = 0x0178;
+ xkeysym_unicode_map[0x20AC] = 0x20AC;
}
-unsigned int KeyMappingX11::get_xlibcode(Key p_keysym) {
- unsigned int code = 0;
- for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) {
- if (_scancode_to_keycode[i].keysym == p_keysym) {
- code = _scancode_to_keycode[i].keycode;
- break;
+Key KeyMappingX11::get_keycode(KeySym p_keysym) {
+ if (p_keysym >= 0x20 && p_keysym < 0x7E) { // ASCII, maps 1-1
+ if (p_keysym > 0x60 && p_keysym < 0x7B) { // Lowercase ASCII.
+ return (Key)(p_keysym - 32);
+ } else {
+ return (Key)p_keysym;
}
}
- return code;
-}
-
-Key KeyMappingX11::get_keycode(KeySym p_keysym) {
- // kinda bruteforce.. could optimize.
-
- if (p_keysym < 0x100) { // Latin 1, maps 1-1
- return (Key)p_keysym;
+ const Key *key = xkeysym_map.getptr(p_keysym);
+ if (key) {
+ return *key;
}
+ return Key::NONE;
+}
- // look for special key
- for (int idx = 0; _xkeysym_to_keycode[idx].keysym != 0; idx++) {
- if (_xkeysym_to_keycode[idx].keysym == p_keysym) {
- return _xkeysym_to_keycode[idx].keycode;
- }
+Key KeyMappingX11::get_scancode(unsigned int p_code) {
+ const Key *key = scancode_map.getptr(p_code);
+ if (key) {
+ return *key;
}
return Key::NONE;
}
-KeySym KeyMappingX11::get_keysym(Key p_code) {
- // kinda bruteforce.. could optimize.
-
- if (p_code < Key::END_LATIN1) { // Latin 1, maps 1-1
- return (KeySym)p_code;
- }
-
- // look for special key
- for (int idx = 0; _xkeysym_to_keycode[idx].keysym != 0; idx++) {
- if (_xkeysym_to_keycode[idx].keycode == p_code) {
- return _xkeysym_to_keycode[idx].keysym;
- }
+unsigned int KeyMappingX11::get_xlibcode(Key p_keysym) {
+ const unsigned int *key = scancode_map_inv.getptr(p_keysym);
+ if (key) {
+ return *key;
}
-
- return (KeySym)Key::NONE;
+ return 0x00;
}
-/***** UNICODE CONVERSION ******/
-
-// Tables taken from FOX toolkit
-
-struct _XTranslateUnicodePair {
- KeySym keysym;
- unsigned int unicode;
-};
-
-enum {
- _KEYSYM_MAX = 759
-};
-
-static _XTranslateUnicodePair _xkeysym_to_unicode[_KEYSYM_MAX] = {
- { 0x01A1, 0x0104 },
- { 0x01A2, 0x02D8 },
- { 0x01A3, 0x0141 },
- { 0x01A5, 0x013D },
- { 0x01A6, 0x015A },
- { 0x01A9, 0x0160 },
- { 0x01AA, 0x015E },
- { 0x01AB, 0x0164 },
- { 0x01AC, 0x0179 },
- { 0x01AE, 0x017D },
- { 0x01AF, 0x017B },
- { 0x01B1, 0x0105 },
- { 0x01B2, 0x02DB },
- { 0x01B3, 0x0142 },
- { 0x01B5, 0x013E },
- { 0x01B6, 0x015B },
- { 0x01B7, 0x02C7 },
- { 0x01B9, 0x0161 },
- { 0x01BA, 0x015F },
- { 0x01BB, 0x0165 },
- { 0x01BC, 0x017A },
- { 0x01BD, 0x02DD },
- { 0x01BE, 0x017E },
- { 0x01BF, 0x017C },
- { 0x01C0, 0x0154 },
- { 0x01C3, 0x0102 },
- { 0x01C5, 0x0139 },
- { 0x01C6, 0x0106 },
- { 0x01C8, 0x010C },
- { 0x01CA, 0x0118 },
- { 0x01CC, 0x011A },
- { 0x01CF, 0x010E },
- { 0x01D0, 0x0110 },
- { 0x01D1, 0x0143 },
- { 0x01D2, 0x0147 },
- { 0x01D5, 0x0150 },
- { 0x01D8, 0x0158 },
- { 0x01D9, 0x016E },
- { 0x01DB, 0x0170 },
- { 0x01DE, 0x0162 },
- { 0x01E0, 0x0155 },
- { 0x01E3, 0x0103 },
- { 0x01E5, 0x013A },
- { 0x01E6, 0x0107 },
- { 0x01E8, 0x010D },
- { 0x01EA, 0x0119 },
- { 0x01EC, 0x011B },
- { 0x01EF, 0x010F },
- { 0x01F0, 0x0111 },
- { 0x01F1, 0x0144 },
- { 0x01F2, 0x0148 },
- { 0x01F5, 0x0151 },
- { 0x01F8, 0x0159 },
- { 0x01F9, 0x016F },
- { 0x01FB, 0x0171 },
- { 0x01FE, 0x0163 },
- { 0x01FF, 0x02D9 },
- { 0x02A1, 0x0126 },
- { 0x02A6, 0x0124 },
- { 0x02A9, 0x0130 },
- { 0x02AB, 0x011E },
- { 0x02AC, 0x0134 },
- { 0x02B1, 0x0127 },
- { 0x02B6, 0x0125 },
- { 0x02B9, 0x0131 },
- { 0x02BB, 0x011F },
- { 0x02BC, 0x0135 },
- { 0x02C5, 0x010A },
- { 0x02C6, 0x0108 },
- { 0x02D5, 0x0120 },
- { 0x02D8, 0x011C },
- { 0x02DD, 0x016C },
- { 0x02DE, 0x015C },
- { 0x02E5, 0x010B },
- { 0x02E6, 0x0109 },
- { 0x02F5, 0x0121 },
- { 0x02F8, 0x011D },
- { 0x02FD, 0x016D },
- { 0x02FE, 0x015D },
- { 0x03A2, 0x0138 },
- { 0x03A3, 0x0156 },
- { 0x03A5, 0x0128 },
- { 0x03A6, 0x013B },
- { 0x03AA, 0x0112 },
- { 0x03AB, 0x0122 },
- { 0x03AC, 0x0166 },
- { 0x03B3, 0x0157 },
- { 0x03B5, 0x0129 },
- { 0x03B6, 0x013C },
- { 0x03BA, 0x0113 },
- { 0x03BB, 0x0123 },
- { 0x03BC, 0x0167 },
- { 0x03BD, 0x014A },
- { 0x03BF, 0x014B },
- { 0x03C0, 0x0100 },
- { 0x03C7, 0x012E },
- { 0x03CC, 0x0116 },
- { 0x03CF, 0x012A },
- { 0x03D1, 0x0145 },
- { 0x03D2, 0x014C },
- { 0x03D3, 0x0136 },
- { 0x03D9, 0x0172 },
- { 0x03DD, 0x0168 },
- { 0x03DE, 0x016A },
- { 0x03E0, 0x0101 },
- { 0x03E7, 0x012F },
- { 0x03EC, 0x0117 },
- { 0x03EF, 0x012B },
- { 0x03F1, 0x0146 },
- { 0x03F2, 0x014D },
- { 0x03F3, 0x0137 },
- { 0x03F9, 0x0173 },
- { 0x03FD, 0x0169 },
- { 0x03FE, 0x016B },
- { 0x047E, 0x203E },
- { 0x04A1, 0x3002 },
- { 0x04A2, 0x300C },
- { 0x04A3, 0x300D },
- { 0x04A4, 0x3001 },
- { 0x04A5, 0x30FB },
- { 0x04A6, 0x30F2 },
- { 0x04A7, 0x30A1 },
- { 0x04A8, 0x30A3 },
- { 0x04A9, 0x30A5 },
- { 0x04AA, 0x30A7 },
- { 0x04AB, 0x30A9 },
- { 0x04AC, 0x30E3 },
- { 0x04AD, 0x30E5 },
- { 0x04AE, 0x30E7 },
- { 0x04AF, 0x30C3 },
- { 0x04B0, 0x30FC },
- { 0x04B1, 0x30A2 },
- { 0x04B2, 0x30A4 },
- { 0x04B3, 0x30A6 },
- { 0x04B4, 0x30A8 },
- { 0x04B5, 0x30AA },
- { 0x04B6, 0x30AB },
- { 0x04B7, 0x30AD },
- { 0x04B8, 0x30AF },
- { 0x04B9, 0x30B1 },
- { 0x04BA, 0x30B3 },
- { 0x04BB, 0x30B5 },
- { 0x04BC, 0x30B7 },
- { 0x04BD, 0x30B9 },
- { 0x04BE, 0x30BB },
- { 0x04BF, 0x30BD },
- { 0x04C0, 0x30BF },
- { 0x04C1, 0x30C1 },
- { 0x04C2, 0x30C4 },
- { 0x04C3, 0x30C6 },
- { 0x04C4, 0x30C8 },
- { 0x04C5, 0x30CA },
- { 0x04C6, 0x30CB },
- { 0x04C7, 0x30CC },
- { 0x04C8, 0x30CD },
- { 0x04C9, 0x30CE },
- { 0x04CA, 0x30CF },
- { 0x04CB, 0x30D2 },
- { 0x04CC, 0x30D5 },
- { 0x04CD, 0x30D8 },
- { 0x04CE, 0x30DB },
- { 0x04CF, 0x30DE },
- { 0x04D0, 0x30DF },
- { 0x04D1, 0x30E0 },
- { 0x04D2, 0x30E1 },
- { 0x04D3, 0x30E2 },
- { 0x04D4, 0x30E4 },
- { 0x04D5, 0x30E6 },
- { 0x04D6, 0x30E8 },
- { 0x04D7, 0x30E9 },
- { 0x04D8, 0x30EA },
- { 0x04D9, 0x30EB },
- { 0x04DA, 0x30EC },
- { 0x04DB, 0x30ED },
- { 0x04DC, 0x30EF },
- { 0x04DD, 0x30F3 },
- { 0x04DE, 0x309B },
- { 0x04DF, 0x309C },
- { 0x05AC, 0x060C },
- { 0x05BB, 0x061B },
- { 0x05BF, 0x061F },
- { 0x05C1, 0x0621 },
- { 0x05C2, 0x0622 },
- { 0x05C3, 0x0623 },
- { 0x05C4, 0x0624 },
- { 0x05C5, 0x0625 },
- { 0x05C6, 0x0626 },
- { 0x05C7, 0x0627 },
- { 0x05C8, 0x0628 },
- { 0x05C9, 0x0629 },
- { 0x05CA, 0x062A },
- { 0x05CB, 0x062B },
- { 0x05CC, 0x062C },
- { 0x05CD, 0x062D },
- { 0x05CE, 0x062E },
- { 0x05CF, 0x062F },
- { 0x05D0, 0x0630 },
- { 0x05D1, 0x0631 },
- { 0x05D2, 0x0632 },
- { 0x05D3, 0x0633 },
- { 0x05D4, 0x0634 },
- { 0x05D5, 0x0635 },
- { 0x05D6, 0x0636 },
- { 0x05D7, 0x0637 },
- { 0x05D8, 0x0638 },
- { 0x05D9, 0x0639 },
- { 0x05DA, 0x063A },
- { 0x05E0, 0x0640 },
- { 0x05E1, 0x0641 },
- { 0x05E2, 0x0642 },
- { 0x05E3, 0x0643 },
- { 0x05E4, 0x0644 },
- { 0x05E5, 0x0645 },
- { 0x05E6, 0x0646 },
- { 0x05E7, 0x0647 },
- { 0x05E8, 0x0648 },
- { 0x05E9, 0x0649 },
- { 0x05EA, 0x064A },
- { 0x05EB, 0x064B },
- { 0x05EC, 0x064C },
- { 0x05ED, 0x064D },
- { 0x05EE, 0x064E },
- { 0x05EF, 0x064F },
- { 0x05F0, 0x0650 },
- { 0x05F1, 0x0651 },
- { 0x05F2, 0x0652 },
- { 0x06A1, 0x0452 },
- { 0x06A2, 0x0453 },
- { 0x06A3, 0x0451 },
- { 0x06A4, 0x0454 },
- { 0x06A5, 0x0455 },
- { 0x06A6, 0x0456 },
- { 0x06A7, 0x0457 },
- { 0x06A8, 0x0458 },
- { 0x06A9, 0x0459 },
- { 0x06AA, 0x045A },
- { 0x06AB, 0x045B },
- { 0x06AC, 0x045C },
- { 0x06AE, 0x045E },
- { 0x06AF, 0x045F },
- { 0x06B0, 0x2116 },
- { 0x06B1, 0x0402 },
- { 0x06B2, 0x0403 },
- { 0x06B3, 0x0401 },
- { 0x06B4, 0x0404 },
- { 0x06B5, 0x0405 },
- { 0x06B6, 0x0406 },
- { 0x06B7, 0x0407 },
- { 0x06B8, 0x0408 },
- { 0x06B9, 0x0409 },
- { 0x06BA, 0x040A },
- { 0x06BB, 0x040B },
- { 0x06BC, 0x040C },
- { 0x06BE, 0x040E },
- { 0x06BF, 0x040F },
- { 0x06C0, 0x044E },
- { 0x06C1, 0x0430 },
- { 0x06C2, 0x0431 },
- { 0x06C3, 0x0446 },
- { 0x06C4, 0x0434 },
- { 0x06C5, 0x0435 },
- { 0x06C6, 0x0444 },
- { 0x06C7, 0x0433 },
- { 0x06C8, 0x0445 },
- { 0x06C9, 0x0438 },
- { 0x06CA, 0x0439 },
- { 0x06CB, 0x043A },
- { 0x06CC, 0x043B },
- { 0x06CD, 0x043C },
- { 0x06CE, 0x043D },
- { 0x06CF, 0x043E },
- { 0x06D0, 0x043F },
- { 0x06D1, 0x044F },
- { 0x06D2, 0x0440 },
- { 0x06D3, 0x0441 },
- { 0x06D4, 0x0442 },
- { 0x06D5, 0x0443 },
- { 0x06D6, 0x0436 },
- { 0x06D7, 0x0432 },
- { 0x06D8, 0x044C },
- { 0x06D9, 0x044B },
- { 0x06DA, 0x0437 },
- { 0x06DB, 0x0448 },
- { 0x06DC, 0x044D },
- { 0x06DD, 0x0449 },
- { 0x06DE, 0x0447 },
- { 0x06DF, 0x044A },
- { 0x06E0, 0x042E },
- { 0x06E1, 0x0410 },
- { 0x06E2, 0x0411 },
- { 0x06E3, 0x0426 },
- { 0x06E4, 0x0414 },
- { 0x06E5, 0x0415 },
- { 0x06E6, 0x0424 },
- { 0x06E7, 0x0413 },
- { 0x06E8, 0x0425 },
- { 0x06E9, 0x0418 },
- { 0x06EA, 0x0419 },
- { 0x06EB, 0x041A },
- { 0x06EC, 0x041B },
- { 0x06ED, 0x041C },
- { 0x06EE, 0x041D },
- { 0x06EF, 0x041E },
- { 0x06F0, 0x041F },
- { 0x06F1, 0x042F },
- { 0x06F2, 0x0420 },
- { 0x06F3, 0x0421 },
- { 0x06F4, 0x0422 },
- { 0x06F5, 0x0423 },
- { 0x06F6, 0x0416 },
- { 0x06F7, 0x0412 },
- { 0x06F8, 0x042C },
- { 0x06F9, 0x042B },
- { 0x06FA, 0x0417 },
- { 0x06FB, 0x0428 },
- { 0x06FC, 0x042D },
- { 0x06FD, 0x0429 },
- { 0x06FE, 0x0427 },
- { 0x06FF, 0x042A },
- { 0x07A1, 0x0386 },
- { 0x07A2, 0x0388 },
- { 0x07A3, 0x0389 },
- { 0x07A4, 0x038A },
- { 0x07A5, 0x03AA },
- { 0x07A7, 0x038C },
- { 0x07A8, 0x038E },
- { 0x07A9, 0x03AB },
- { 0x07AB, 0x038F },
- { 0x07AE, 0x0385 },
- { 0x07AF, 0x2015 },
- { 0x07B1, 0x03AC },
- { 0x07B2, 0x03AD },
- { 0x07B3, 0x03AE },
- { 0x07B4, 0x03AF },
- { 0x07B5, 0x03CA },
- { 0x07B6, 0x0390 },
- { 0x07B7, 0x03CC },
- { 0x07B8, 0x03CD },
- { 0x07B9, 0x03CB },
- { 0x07BA, 0x03B0 },
- { 0x07BB, 0x03CE },
- { 0x07C1, 0x0391 },
- { 0x07C2, 0x0392 },
- { 0x07C3, 0x0393 },
- { 0x07C4, 0x0394 },
- { 0x07C5, 0x0395 },
- { 0x07C6, 0x0396 },
- { 0x07C7, 0x0397 },
- { 0x07C8, 0x0398 },
- { 0x07C9, 0x0399 },
- { 0x07CA, 0x039A },
- { 0x07CB, 0x039B },
- { 0x07CC, 0x039C },
- { 0x07CD, 0x039D },
- { 0x07CE, 0x039E },
- { 0x07CF, 0x039F },
- { 0x07D0, 0x03A0 },
- { 0x07D1, 0x03A1 },
- { 0x07D2, 0x03A3 },
- { 0x07D4, 0x03A4 },
- { 0x07D5, 0x03A5 },
- { 0x07D6, 0x03A6 },
- { 0x07D7, 0x03A7 },
- { 0x07D8, 0x03A8 },
- { 0x07D9, 0x03A9 },
- { 0x07E1, 0x03B1 },
- { 0x07E2, 0x03B2 },
- { 0x07E3, 0x03B3 },
- { 0x07E4, 0x03B4 },
- { 0x07E5, 0x03B5 },
- { 0x07E6, 0x03B6 },
- { 0x07E7, 0x03B7 },
- { 0x07E8, 0x03B8 },
- { 0x07E9, 0x03B9 },
- { 0x07EA, 0x03BA },
- { 0x07EB, 0x03BB },
- { 0x07EC, 0x03BC },
- { 0x07ED, 0x03BD },
- { 0x07EE, 0x03BE },
- { 0x07EF, 0x03BF },
- { 0x07F0, 0x03C0 },
- { 0x07F1, 0x03C1 },
- { 0x07F2, 0x03C3 },
- { 0x07F3, 0x03C2 },
- { 0x07F4, 0x03C4 },
- { 0x07F5, 0x03C5 },
- { 0x07F6, 0x03C6 },
- { 0x07F7, 0x03C7 },
- { 0x07F8, 0x03C8 },
- { 0x07F9, 0x03C9 },
- { 0x08A1, 0x23B7 },
- { 0x08A2, 0x250C },
- { 0x08A3, 0x2500 },
- { 0x08A4, 0x2320 },
- { 0x08A5, 0x2321 },
- { 0x08A6, 0x2502 },
- { 0x08A7, 0x23A1 },
- { 0x08A8, 0x23A3 },
- { 0x08A9, 0x23A4 },
- { 0x08AA, 0x23A6 },
- { 0x08AB, 0x239B },
- { 0x08AC, 0x239D },
- { 0x08AD, 0x239E },
- { 0x08AE, 0x23A0 },
- { 0x08AF, 0x23A8 },
- { 0x08B0, 0x23AC },
- { 0x08BC, 0x2264 },
- { 0x08BD, 0x2260 },
- { 0x08BE, 0x2265 },
- { 0x08BF, 0x222B },
- { 0x08C0, 0x2234 },
- { 0x08C1, 0x221D },
- { 0x08C2, 0x221E },
- { 0x08C5, 0x2207 },
- { 0x08C8, 0x223C },
- { 0x08C9, 0x2243 },
- { 0x08CD, 0x21D4 },
- { 0x08CE, 0x21D2 },
- { 0x08CF, 0x2261 },
- { 0x08D6, 0x221A },
- { 0x08DA, 0x2282 },
- { 0x08DB, 0x2283 },
- { 0x08DC, 0x2229 },
- { 0x08DD, 0x222A },
- { 0x08DE, 0x2227 },
- { 0x08DF, 0x2228 },
- { 0x08EF, 0x2202 },
- { 0x08F6, 0x0192 },
- { 0x08FB, 0x2190 },
- { 0x08FC, 0x2191 },
- { 0x08FD, 0x2192 },
- { 0x08FE, 0x2193 },
- { 0x09E0, 0x25C6 },
- { 0x09E1, 0x2592 },
- { 0x09E2, 0x2409 },
- { 0x09E3, 0x240C },
- { 0x09E4, 0x240D },
- { 0x09E5, 0x240A },
- { 0x09E8, 0x2424 },
- { 0x09E9, 0x240B },
- { 0x09EA, 0x2518 },
- { 0x09EB, 0x2510 },
- { 0x09EC, 0x250C },
- { 0x09ED, 0x2514 },
- { 0x09EE, 0x253C },
- { 0x09EF, 0x23BA },
- { 0x09F0, 0x23BB },
- { 0x09F1, 0x2500 },
- { 0x09F2, 0x23BC },
- { 0x09F3, 0x23BD },
- { 0x09F4, 0x251C },
- { 0x09F5, 0x2524 },
- { 0x09F6, 0x2534 },
- { 0x09F7, 0x252C },
- { 0x09F8, 0x2502 },
- { 0x0AA1, 0x2003 },
- { 0x0AA2, 0x2002 },
- { 0x0AA3, 0x2004 },
- { 0x0AA4, 0x2005 },
- { 0x0AA5, 0x2007 },
- { 0x0AA6, 0x2008 },
- { 0x0AA7, 0x2009 },
- { 0x0AA8, 0x200A },
- { 0x0AA9, 0x2014 },
- { 0x0AAA, 0x2013 },
- { 0x0AAE, 0x2026 },
- { 0x0AAF, 0x2025 },
- { 0x0AB0, 0x2153 },
- { 0x0AB1, 0x2154 },
- { 0x0AB2, 0x2155 },
- { 0x0AB3, 0x2156 },
- { 0x0AB4, 0x2157 },
- { 0x0AB5, 0x2158 },
- { 0x0AB6, 0x2159 },
- { 0x0AB7, 0x215A },
- { 0x0AB8, 0x2105 },
- { 0x0ABB, 0x2012 },
- { 0x0ABC, 0x2329 },
- { 0x0ABE, 0x232A },
- { 0x0AC3, 0x215B },
- { 0x0AC4, 0x215C },
- { 0x0AC5, 0x215D },
- { 0x0AC6, 0x215E },
- { 0x0AC9, 0x2122 },
- { 0x0ACA, 0x2613 },
- { 0x0ACC, 0x25C1 },
- { 0x0ACD, 0x25B7 },
- { 0x0ACE, 0x25CB },
- { 0x0ACF, 0x25AF },
- { 0x0AD0, 0x2018 },
- { 0x0AD1, 0x2019 },
- { 0x0AD2, 0x201C },
- { 0x0AD3, 0x201D },
- { 0x0AD4, 0x211E },
- { 0x0AD6, 0x2032 },
- { 0x0AD7, 0x2033 },
- { 0x0AD9, 0x271D },
- { 0x0ADB, 0x25AC },
- { 0x0ADC, 0x25C0 },
- { 0x0ADD, 0x25B6 },
- { 0x0ADE, 0x25CF },
- { 0x0ADF, 0x25AE },
- { 0x0AE0, 0x25E6 },
- { 0x0AE1, 0x25AB },
- { 0x0AE2, 0x25AD },
- { 0x0AE3, 0x25B3 },
- { 0x0AE4, 0x25BD },
- { 0x0AE5, 0x2606 },
- { 0x0AE6, 0x2022 },
- { 0x0AE7, 0x25AA },
- { 0x0AE8, 0x25B2 },
- { 0x0AE9, 0x25BC },
- { 0x0AEA, 0x261C },
- { 0x0AEB, 0x261E },
- { 0x0AEC, 0x2663 },
- { 0x0AED, 0x2666 },
- { 0x0AEE, 0x2665 },
- { 0x0AF0, 0x2720 },
- { 0x0AF1, 0x2020 },
- { 0x0AF2, 0x2021 },
- { 0x0AF3, 0x2713 },
- { 0x0AF4, 0x2717 },
- { 0x0AF5, 0x266F },
- { 0x0AF6, 0x266D },
- { 0x0AF7, 0x2642 },
- { 0x0AF8, 0x2640 },
- { 0x0AF9, 0x260E },
- { 0x0AFA, 0x2315 },
- { 0x0AFB, 0x2117 },
- { 0x0AFC, 0x2038 },
- { 0x0AFD, 0x201A },
- { 0x0AFE, 0x201E },
- { 0x0BA3, 0x003C },
- { 0x0BA6, 0x003E },
- { 0x0BA8, 0x2228 },
- { 0x0BA9, 0x2227 },
- { 0x0BC0, 0x00AF },
- { 0x0BC2, 0x22A5 },
- { 0x0BC3, 0x2229 },
- { 0x0BC4, 0x230A },
- { 0x0BC6, 0x005F },
- { 0x0BCA, 0x2218 },
- { 0x0BCC, 0x2395 },
- { 0x0BCE, 0x22A4 },
- { 0x0BCF, 0x25CB },
- { 0x0BD3, 0x2308 },
- { 0x0BD6, 0x222A },
- { 0x0BD8, 0x2283 },
- { 0x0BDA, 0x2282 },
- { 0x0BDC, 0x22A2 },
- { 0x0BFC, 0x22A3 },
- { 0x0CDF, 0x2017 },
- { 0x0CE0, 0x05D0 },
- { 0x0CE1, 0x05D1 },
- { 0x0CE2, 0x05D2 },
- { 0x0CE3, 0x05D3 },
- { 0x0CE4, 0x05D4 },
- { 0x0CE5, 0x05D5 },
- { 0x0CE6, 0x05D6 },
- { 0x0CE7, 0x05D7 },
- { 0x0CE8, 0x05D8 },
- { 0x0CE9, 0x05D9 },
- { 0x0CEA, 0x05DA },
- { 0x0CEB, 0x05DB },
- { 0x0CEC, 0x05DC },
- { 0x0CED, 0x05DD },
- { 0x0CEE, 0x05DE },
- { 0x0CEF, 0x05DF },
- { 0x0CF0, 0x05E0 },
- { 0x0CF1, 0x05E1 },
- { 0x0CF2, 0x05E2 },
- { 0x0CF3, 0x05E3 },
- { 0x0CF4, 0x05E4 },
- { 0x0CF5, 0x05E5 },
- { 0x0CF6, 0x05E6 },
- { 0x0CF7, 0x05E7 },
- { 0x0CF8, 0x05E8 },
- { 0x0CF9, 0x05E9 },
- { 0x0CFA, 0x05EA },
- { 0x0DA1, 0x0E01 },
- { 0x0DA2, 0x0E02 },
- { 0x0DA3, 0x0E03 },
- { 0x0DA4, 0x0E04 },
- { 0x0DA5, 0x0E05 },
- { 0x0DA6, 0x0E06 },
- { 0x0DA7, 0x0E07 },
- { 0x0DA8, 0x0E08 },
- { 0x0DA9, 0x0E09 },
- { 0x0DAA, 0x0E0A },
- { 0x0DAB, 0x0E0B },
- { 0x0DAC, 0x0E0C },
- { 0x0DAD, 0x0E0D },
- { 0x0DAE, 0x0E0E },
- { 0x0DAF, 0x0E0F },
- { 0x0DB0, 0x0E10 },
- { 0x0DB1, 0x0E11 },
- { 0x0DB2, 0x0E12 },
- { 0x0DB3, 0x0E13 },
- { 0x0DB4, 0x0E14 },
- { 0x0DB5, 0x0E15 },
- { 0x0DB6, 0x0E16 },
- { 0x0DB7, 0x0E17 },
- { 0x0DB8, 0x0E18 },
- { 0x0DB9, 0x0E19 },
- { 0x0DBA, 0x0E1A },
- { 0x0DBB, 0x0E1B },
- { 0x0DBC, 0x0E1C },
- { 0x0DBD, 0x0E1D },
- { 0x0DBE, 0x0E1E },
- { 0x0DBF, 0x0E1F },
- { 0x0DC0, 0x0E20 },
- { 0x0DC1, 0x0E21 },
- { 0x0DC2, 0x0E22 },
- { 0x0DC3, 0x0E23 },
- { 0x0DC4, 0x0E24 },
- { 0x0DC5, 0x0E25 },
- { 0x0DC6, 0x0E26 },
- { 0x0DC7, 0x0E27 },
- { 0x0DC8, 0x0E28 },
- { 0x0DC9, 0x0E29 },
- { 0x0DCA, 0x0E2A },
- { 0x0DCB, 0x0E2B },
- { 0x0DCC, 0x0E2C },
- { 0x0DCD, 0x0E2D },
- { 0x0DCE, 0x0E2E },
- { 0x0DCF, 0x0E2F },
- { 0x0DD0, 0x0E30 },
- { 0x0DD1, 0x0E31 },
- { 0x0DD2, 0x0E32 },
- { 0x0DD3, 0x0E33 },
- { 0x0DD4, 0x0E34 },
- { 0x0DD5, 0x0E35 },
- { 0x0DD6, 0x0E36 },
- { 0x0DD7, 0x0E37 },
- { 0x0DD8, 0x0E38 },
- { 0x0DD9, 0x0E39 },
- { 0x0DDA, 0x0E3A },
- { 0x0DDF, 0x0E3F },
- { 0x0DE0, 0x0E40 },
- { 0x0DE1, 0x0E41 },
- { 0x0DE2, 0x0E42 },
- { 0x0DE3, 0x0E43 },
- { 0x0DE4, 0x0E44 },
- { 0x0DE5, 0x0E45 },
- { 0x0DE6, 0x0E46 },
- { 0x0DE7, 0x0E47 },
- { 0x0DE8, 0x0E48 },
- { 0x0DE9, 0x0E49 },
- { 0x0DEA, 0x0E4A },
- { 0x0DEB, 0x0E4B },
- { 0x0DEC, 0x0E4C },
- { 0x0DED, 0x0E4D },
- { 0x0DF0, 0x0E50 },
- { 0x0DF1, 0x0E51 },
- { 0x0DF2, 0x0E52 },
- { 0x0DF3, 0x0E53 },
- { 0x0DF4, 0x0E54 },
- { 0x0DF5, 0x0E55 },
- { 0x0DF6, 0x0E56 },
- { 0x0DF7, 0x0E57 },
- { 0x0DF8, 0x0E58 },
- { 0x0DF9, 0x0E59 },
- { 0x0EA1, 0x3131 },
- { 0x0EA2, 0x3132 },
- { 0x0EA3, 0x3133 },
- { 0x0EA4, 0x3134 },
- { 0x0EA5, 0x3135 },
- { 0x0EA6, 0x3136 },
- { 0x0EA7, 0x3137 },
- { 0x0EA8, 0x3138 },
- { 0x0EA9, 0x3139 },
- { 0x0EAA, 0x313A },
- { 0x0EAB, 0x313B },
- { 0x0EAC, 0x313C },
- { 0x0EAD, 0x313D },
- { 0x0EAE, 0x313E },
- { 0x0EAF, 0x313F },
- { 0x0EB0, 0x3140 },
- { 0x0EB1, 0x3141 },
- { 0x0EB2, 0x3142 },
- { 0x0EB3, 0x3143 },
- { 0x0EB4, 0x3144 },
- { 0x0EB5, 0x3145 },
- { 0x0EB6, 0x3146 },
- { 0x0EB7, 0x3147 },
- { 0x0EB8, 0x3148 },
- { 0x0EB9, 0x3149 },
- { 0x0EBA, 0x314A },
- { 0x0EBB, 0x314B },
- { 0x0EBC, 0x314C },
- { 0x0EBD, 0x314D },
- { 0x0EBE, 0x314E },
- { 0x0EBF, 0x314F },
- { 0x0EC0, 0x3150 },
- { 0x0EC1, 0x3151 },
- { 0x0EC2, 0x3152 },
- { 0x0EC3, 0x3153 },
- { 0x0EC4, 0x3154 },
- { 0x0EC5, 0x3155 },
- { 0x0EC6, 0x3156 },
- { 0x0EC7, 0x3157 },
- { 0x0EC8, 0x3158 },
- { 0x0EC9, 0x3159 },
- { 0x0ECA, 0x315A },
- { 0x0ECB, 0x315B },
- { 0x0ECC, 0x315C },
- { 0x0ECD, 0x315D },
- { 0x0ECE, 0x315E },
- { 0x0ECF, 0x315F },
- { 0x0ED0, 0x3160 },
- { 0x0ED1, 0x3161 },
- { 0x0ED2, 0x3162 },
- { 0x0ED3, 0x3163 },
- { 0x0ED4, 0x11A8 },
- { 0x0ED5, 0x11A9 },
- { 0x0ED6, 0x11AA },
- { 0x0ED7, 0x11AB },
- { 0x0ED8, 0x11AC },
- { 0x0ED9, 0x11AD },
- { 0x0EDA, 0x11AE },
- { 0x0EDB, 0x11AF },
- { 0x0EDC, 0x11B0 },
- { 0x0EDD, 0x11B1 },
- { 0x0EDE, 0x11B2 },
- { 0x0EDF, 0x11B3 },
- { 0x0EE0, 0x11B4 },
- { 0x0EE1, 0x11B5 },
- { 0x0EE2, 0x11B6 },
- { 0x0EE3, 0x11B7 },
- { 0x0EE4, 0x11B8 },
- { 0x0EE5, 0x11B9 },
- { 0x0EE6, 0x11BA },
- { 0x0EE7, 0x11BB },
- { 0x0EE8, 0x11BC },
- { 0x0EE9, 0x11BD },
- { 0x0EEA, 0x11BE },
- { 0x0EEB, 0x11BF },
- { 0x0EEC, 0x11C0 },
- { 0x0EED, 0x11C1 },
- { 0x0EEE, 0x11C2 },
- { 0x0EEF, 0x316D },
- { 0x0EF0, 0x3171 },
- { 0x0EF1, 0x3178 },
- { 0x0EF2, 0x317F },
- { 0x0EF3, 0x3181 },
- { 0x0EF4, 0x3184 },
- { 0x0EF5, 0x3186 },
- { 0x0EF6, 0x318D },
- { 0x0EF7, 0x318E },
- { 0x0EF8, 0x11EB },
- { 0x0EF9, 0x11F0 },
- { 0x0EFA, 0x11F9 },
- { 0x0EFF, 0x20A9 },
- { 0x13A4, 0x20AC },
- { 0x13BC, 0x0152 },
- { 0x13BD, 0x0153 },
- { 0x13BE, 0x0178 },
- { 0x20AC, 0x20AC },
-};
-
-unsigned int KeyMappingX11::get_unicode_from_keysym(KeySym p_keysym) {
- /* Latin-1 */
- if (p_keysym >= 0x20 && p_keysym <= 0x7e) {
+char32_t KeyMappingX11::get_unicode_from_keysym(KeySym p_keysym) {
+ // Latin-1
+ if (p_keysym >= 0x20 && p_keysym <= 0x7E) {
return p_keysym;
}
- if (p_keysym >= 0xa0 && p_keysym <= 0xff) {
+ if (p_keysym >= 0xA0 && p_keysym <= 0xFF) {
return p_keysym;
}
- // keypad to latin1 is easy
- if (p_keysym >= 0xffaa && p_keysym <= 0xffb9) {
- return p_keysym - 0xff80;
- }
- /* Unicode (may be present)*/
-
- if ((p_keysym & 0xff000000) == 0x01000000) {
- return p_keysym & 0x00ffffff;
+ // Keypad to Latin-1.
+ if (p_keysym >= 0xFFAA && p_keysym <= 0xFFB9) {
+ return p_keysym - 0xFF80;
}
- int middle, low = 0, high = _KEYSYM_MAX - 1;
- do {
- middle = (high + low) / 2;
- if (_xkeysym_to_unicode[middle].keysym == p_keysym) {
- return _xkeysym_to_unicode[middle].unicode;
- }
- if (_xkeysym_to_unicode[middle].keysym <= p_keysym) {
- low = middle + 1;
- } else {
- high = middle - 1;
- }
- } while (high >= low);
-
- return 0;
-}
-
-struct _XTranslateUnicodePairReverse {
- unsigned int unicode;
- KeySym keysym;
-};
-
-enum {
- _UNICODE_MAX = 750
-};
-
-static _XTranslateUnicodePairReverse _unicode_to_xkeysym[_UNICODE_MAX] = {
- { 0x0ABD, 0x002E },
- { 0x0BA3, 0x003C },
- { 0x0BA6, 0x003E },
- { 0x0BC6, 0x005F },
- { 0x0BC0, 0x00AF },
- { 0x03C0, 0x0100 },
- { 0x03E0, 0x0101 },
- { 0x01C3, 0x0102 },
- { 0x01E3, 0x0103 },
- { 0x01A1, 0x0104 },
- { 0x01B1, 0x0105 },
- { 0x01C6, 0x0106 },
- { 0x01E6, 0x0107 },
- { 0x02C6, 0x0108 },
- { 0x02E6, 0x0109 },
- { 0x02C5, 0x010A },
- { 0x02E5, 0x010B },
- { 0x01C8, 0x010C },
- { 0x01E8, 0x010D },
- { 0x01CF, 0x010E },
- { 0x01EF, 0x010F },
- { 0x01D0, 0x0110 },
- { 0x01F0, 0x0111 },
- { 0x03AA, 0x0112 },
- { 0x03BA, 0x0113 },
- { 0x03CC, 0x0116 },
- { 0x03EC, 0x0117 },
- { 0x01CA, 0x0118 },
- { 0x01EA, 0x0119 },
- { 0x01CC, 0x011A },
- { 0x01EC, 0x011B },
- { 0x02D8, 0x011C },
- { 0x02F8, 0x011D },
- { 0x02AB, 0x011E },
- { 0x02BB, 0x011F },
- { 0x02D5, 0x0120 },
- { 0x02F5, 0x0121 },
- { 0x03AB, 0x0122 },
- { 0x03BB, 0x0123 },
- { 0x02A6, 0x0124 },
- { 0x02B6, 0x0125 },
- { 0x02A1, 0x0126 },
- { 0x02B1, 0x0127 },
- { 0x03A5, 0x0128 },
- { 0x03B5, 0x0129 },
- { 0x03CF, 0x012A },
- { 0x03EF, 0x012B },
- { 0x03C7, 0x012E },
- { 0x03E7, 0x012F },
- { 0x02A9, 0x0130 },
- { 0x02B9, 0x0131 },
- { 0x02AC, 0x0134 },
- { 0x02BC, 0x0135 },
- { 0x03D3, 0x0136 },
- { 0x03F3, 0x0137 },
- { 0x03A2, 0x0138 },
- { 0x01C5, 0x0139 },
- { 0x01E5, 0x013A },
- { 0x03A6, 0x013B },
- { 0x03B6, 0x013C },
- { 0x01A5, 0x013D },
- { 0x01B5, 0x013E },
- { 0x01A3, 0x0141 },
- { 0x01B3, 0x0142 },
- { 0x01D1, 0x0143 },
- { 0x01F1, 0x0144 },
- { 0x03D1, 0x0145 },
- { 0x03F1, 0x0146 },
- { 0x01D2, 0x0147 },
- { 0x01F2, 0x0148 },
- { 0x03BD, 0x014A },
- { 0x03BF, 0x014B },
- { 0x03D2, 0x014C },
- { 0x03F2, 0x014D },
- { 0x01D5, 0x0150 },
- { 0x01F5, 0x0151 },
- { 0x13BC, 0x0152 },
- { 0x13BD, 0x0153 },
- { 0x01C0, 0x0154 },
- { 0x01E0, 0x0155 },
- { 0x03A3, 0x0156 },
- { 0x03B3, 0x0157 },
- { 0x01D8, 0x0158 },
- { 0x01F8, 0x0159 },
- { 0x01A6, 0x015A },
- { 0x01B6, 0x015B },
- { 0x02DE, 0x015C },
- { 0x02FE, 0x015D },
- { 0x01AA, 0x015E },
- { 0x01BA, 0x015F },
- { 0x01A9, 0x0160 },
- { 0x01B9, 0x0161 },
- { 0x01DE, 0x0162 },
- { 0x01FE, 0x0163 },
- { 0x01AB, 0x0164 },
- { 0x01BB, 0x0165 },
- { 0x03AC, 0x0166 },
- { 0x03BC, 0x0167 },
- { 0x03DD, 0x0168 },
- { 0x03FD, 0x0169 },
- { 0x03DE, 0x016A },
- { 0x03FE, 0x016B },
- { 0x02DD, 0x016C },
- { 0x02FD, 0x016D },
- { 0x01D9, 0x016E },
- { 0x01F9, 0x016F },
- { 0x01DB, 0x0170 },
- { 0x01FB, 0x0171 },
- { 0x03D9, 0x0172 },
- { 0x03F9, 0x0173 },
- { 0x13BE, 0x0178 },
- { 0x01AC, 0x0179 },
- { 0x01BC, 0x017A },
- { 0x01AF, 0x017B },
- { 0x01BF, 0x017C },
- { 0x01AE, 0x017D },
- { 0x01BE, 0x017E },
- { 0x08F6, 0x0192 },
- { 0x01B7, 0x02C7 },
- { 0x01A2, 0x02D8 },
- { 0x01FF, 0x02D9 },
- { 0x01B2, 0x02DB },
- { 0x01BD, 0x02DD },
- { 0x07AE, 0x0385 },
- { 0x07A1, 0x0386 },
- { 0x07A2, 0x0388 },
- { 0x07A3, 0x0389 },
- { 0x07A4, 0x038A },
- { 0x07A7, 0x038C },
- { 0x07A8, 0x038E },
- { 0x07AB, 0x038F },
- { 0x07B6, 0x0390 },
- { 0x07C1, 0x0391 },
- { 0x07C2, 0x0392 },
- { 0x07C3, 0x0393 },
- { 0x07C4, 0x0394 },
- { 0x07C5, 0x0395 },
- { 0x07C6, 0x0396 },
- { 0x07C7, 0x0397 },
- { 0x07C8, 0x0398 },
- { 0x07C9, 0x0399 },
- { 0x07CA, 0x039A },
- { 0x07CB, 0x039B },
- { 0x07CC, 0x039C },
- { 0x07CD, 0x039D },
- { 0x07CE, 0x039E },
- { 0x07CF, 0x039F },
- { 0x07D0, 0x03A0 },
- { 0x07D1, 0x03A1 },
- { 0x07D2, 0x03A3 },
- { 0x07D4, 0x03A4 },
- { 0x07D5, 0x03A5 },
- { 0x07D6, 0x03A6 },
- { 0x07D7, 0x03A7 },
- { 0x07D8, 0x03A8 },
- { 0x07D9, 0x03A9 },
- { 0x07A5, 0x03AA },
- { 0x07A9, 0x03AB },
- { 0x07B1, 0x03AC },
- { 0x07B2, 0x03AD },
- { 0x07B3, 0x03AE },
- { 0x07B4, 0x03AF },
- { 0x07BA, 0x03B0 },
- { 0x07E1, 0x03B1 },
- { 0x07E2, 0x03B2 },
- { 0x07E3, 0x03B3 },
- { 0x07E4, 0x03B4 },
- { 0x07E5, 0x03B5 },
- { 0x07E6, 0x03B6 },
- { 0x07E7, 0x03B7 },
- { 0x07E8, 0x03B8 },
- { 0x07E9, 0x03B9 },
- { 0x07EA, 0x03BA },
- { 0x07EB, 0x03BB },
- { 0x07EC, 0x03BC },
- { 0x07ED, 0x03BD },
- { 0x07EE, 0x03BE },
- { 0x07EF, 0x03BF },
- { 0x07F0, 0x03C0 },
- { 0x07F1, 0x03C1 },
- { 0x07F3, 0x03C2 },
- { 0x07F2, 0x03C3 },
- { 0x07F4, 0x03C4 },
- { 0x07F5, 0x03C5 },
- { 0x07F6, 0x03C6 },
- { 0x07F7, 0x03C7 },
- { 0x07F8, 0x03C8 },
- { 0x07F9, 0x03C9 },
- { 0x07B5, 0x03CA },
- { 0x07B9, 0x03CB },
- { 0x07B7, 0x03CC },
- { 0x07B8, 0x03CD },
- { 0x07BB, 0x03CE },
- { 0x06B3, 0x0401 },
- { 0x06B1, 0x0402 },
- { 0x06B2, 0x0403 },
- { 0x06B4, 0x0404 },
- { 0x06B5, 0x0405 },
- { 0x06B6, 0x0406 },
- { 0x06B7, 0x0407 },
- { 0x06B8, 0x0408 },
- { 0x06B9, 0x0409 },
- { 0x06BA, 0x040A },
- { 0x06BB, 0x040B },
- { 0x06BC, 0x040C },
- { 0x06BE, 0x040E },
- { 0x06BF, 0x040F },
- { 0x06E1, 0x0410 },
- { 0x06E2, 0x0411 },
- { 0x06F7, 0x0412 },
- { 0x06E7, 0x0413 },
- { 0x06E4, 0x0414 },
- { 0x06E5, 0x0415 },
- { 0x06F6, 0x0416 },
- { 0x06FA, 0x0417 },
- { 0x06E9, 0x0418 },
- { 0x06EA, 0x0419 },
- { 0x06EB, 0x041A },
- { 0x06EC, 0x041B },
- { 0x06ED, 0x041C },
- { 0x06EE, 0x041D },
- { 0x06EF, 0x041E },
- { 0x06F0, 0x041F },
- { 0x06F2, 0x0420 },
- { 0x06F3, 0x0421 },
- { 0x06F4, 0x0422 },
- { 0x06F5, 0x0423 },
- { 0x06E6, 0x0424 },
- { 0x06E8, 0x0425 },
- { 0x06E3, 0x0426 },
- { 0x06FE, 0x0427 },
- { 0x06FB, 0x0428 },
- { 0x06FD, 0x0429 },
- { 0x06FF, 0x042A },
- { 0x06F9, 0x042B },
- { 0x06F8, 0x042C },
- { 0x06FC, 0x042D },
- { 0x06E0, 0x042E },
- { 0x06F1, 0x042F },
- { 0x06C1, 0x0430 },
- { 0x06C2, 0x0431 },
- { 0x06D7, 0x0432 },
- { 0x06C7, 0x0433 },
- { 0x06C4, 0x0434 },
- { 0x06C5, 0x0435 },
- { 0x06D6, 0x0436 },
- { 0x06DA, 0x0437 },
- { 0x06C9, 0x0438 },
- { 0x06CA, 0x0439 },
- { 0x06CB, 0x043A },
- { 0x06CC, 0x043B },
- { 0x06CD, 0x043C },
- { 0x06CE, 0x043D },
- { 0x06CF, 0x043E },
- { 0x06D0, 0x043F },
- { 0x06D2, 0x0440 },
- { 0x06D3, 0x0441 },
- { 0x06D4, 0x0442 },
- { 0x06D5, 0x0443 },
- { 0x06C6, 0x0444 },
- { 0x06C8, 0x0445 },
- { 0x06C3, 0x0446 },
- { 0x06DE, 0x0447 },
- { 0x06DB, 0x0448 },
- { 0x06DD, 0x0449 },
- { 0x06DF, 0x044A },
- { 0x06D9, 0x044B },
- { 0x06D8, 0x044C },
- { 0x06DC, 0x044D },
- { 0x06C0, 0x044E },
- { 0x06D1, 0x044F },
- { 0x06A3, 0x0451 },
- { 0x06A1, 0x0452 },
- { 0x06A2, 0x0453 },
- { 0x06A4, 0x0454 },
- { 0x06A5, 0x0455 },
- { 0x06A6, 0x0456 },
- { 0x06A7, 0x0457 },
- { 0x06A8, 0x0458 },
- { 0x06A9, 0x0459 },
- { 0x06AA, 0x045A },
- { 0x06AB, 0x045B },
- { 0x06AC, 0x045C },
- { 0x06AE, 0x045E },
- { 0x06AF, 0x045F },
- { 0x0CE0, 0x05D0 },
- { 0x0CE1, 0x05D1 },
- { 0x0CE2, 0x05D2 },
- { 0x0CE3, 0x05D3 },
- { 0x0CE4, 0x05D4 },
- { 0x0CE5, 0x05D5 },
- { 0x0CE6, 0x05D6 },
- { 0x0CE7, 0x05D7 },
- { 0x0CE8, 0x05D8 },
- { 0x0CE9, 0x05D9 },
- { 0x0CEA, 0x05DA },
- { 0x0CEB, 0x05DB },
- { 0x0CEC, 0x05DC },
- { 0x0CED, 0x05DD },
- { 0x0CEE, 0x05DE },
- { 0x0CEF, 0x05DF },
- { 0x0CF0, 0x05E0 },
- { 0x0CF1, 0x05E1 },
- { 0x0CF2, 0x05E2 },
- { 0x0CF3, 0x05E3 },
- { 0x0CF4, 0x05E4 },
- { 0x0CF5, 0x05E5 },
- { 0x0CF6, 0x05E6 },
- { 0x0CF7, 0x05E7 },
- { 0x0CF8, 0x05E8 },
- { 0x0CF9, 0x05E9 },
- { 0x0CFA, 0x05EA },
- { 0x05AC, 0x060C },
- { 0x05BB, 0x061B },
- { 0x05BF, 0x061F },
- { 0x05C1, 0x0621 },
- { 0x05C2, 0x0622 },
- { 0x05C3, 0x0623 },
- { 0x05C4, 0x0624 },
- { 0x05C5, 0x0625 },
- { 0x05C6, 0x0626 },
- { 0x05C7, 0x0627 },
- { 0x05C8, 0x0628 },
- { 0x05C9, 0x0629 },
- { 0x05CA, 0x062A },
- { 0x05CB, 0x062B },
- { 0x05CC, 0x062C },
- { 0x05CD, 0x062D },
- { 0x05CE, 0x062E },
- { 0x05CF, 0x062F },
- { 0x05D0, 0x0630 },
- { 0x05D1, 0x0631 },
- { 0x05D2, 0x0632 },
- { 0x05D3, 0x0633 },
- { 0x05D4, 0x0634 },
- { 0x05D5, 0x0635 },
- { 0x05D6, 0x0636 },
- { 0x05D7, 0x0637 },
- { 0x05D8, 0x0638 },
- { 0x05D9, 0x0639 },
- { 0x05DA, 0x063A },
- { 0x05E0, 0x0640 },
- { 0x05E1, 0x0641 },
- { 0x05E2, 0x0642 },
- { 0x05E3, 0x0643 },
- { 0x05E4, 0x0644 },
- { 0x05E5, 0x0645 },
- { 0x05E6, 0x0646 },
- { 0x05E7, 0x0647 },
- { 0x05E8, 0x0648 },
- { 0x05E9, 0x0649 },
- { 0x05EA, 0x064A },
- { 0x05EB, 0x064B },
- { 0x05EC, 0x064C },
- { 0x05ED, 0x064D },
- { 0x05EE, 0x064E },
- { 0x05EF, 0x064F },
- { 0x05F0, 0x0650 },
- { 0x05F1, 0x0651 },
- { 0x05F2, 0x0652 },
- { 0x0DA1, 0x0E01 },
- { 0x0DA2, 0x0E02 },
- { 0x0DA3, 0x0E03 },
- { 0x0DA4, 0x0E04 },
- { 0x0DA5, 0x0E05 },
- { 0x0DA6, 0x0E06 },
- { 0x0DA7, 0x0E07 },
- { 0x0DA8, 0x0E08 },
- { 0x0DA9, 0x0E09 },
- { 0x0DAA, 0x0E0A },
- { 0x0DAB, 0x0E0B },
- { 0x0DAC, 0x0E0C },
- { 0x0DAD, 0x0E0D },
- { 0x0DAE, 0x0E0E },
- { 0x0DAF, 0x0E0F },
- { 0x0DB0, 0x0E10 },
- { 0x0DB1, 0x0E11 },
- { 0x0DB2, 0x0E12 },
- { 0x0DB3, 0x0E13 },
- { 0x0DB4, 0x0E14 },
- { 0x0DB5, 0x0E15 },
- { 0x0DB6, 0x0E16 },
- { 0x0DB7, 0x0E17 },
- { 0x0DB8, 0x0E18 },
- { 0x0DB9, 0x0E19 },
- { 0x0DBA, 0x0E1A },
- { 0x0DBB, 0x0E1B },
- { 0x0DBC, 0x0E1C },
- { 0x0DBD, 0x0E1D },
- { 0x0DBE, 0x0E1E },
- { 0x0DBF, 0x0E1F },
- { 0x0DC0, 0x0E20 },
- { 0x0DC1, 0x0E21 },
- { 0x0DC2, 0x0E22 },
- { 0x0DC3, 0x0E23 },
- { 0x0DC4, 0x0E24 },
- { 0x0DC5, 0x0E25 },
- { 0x0DC6, 0x0E26 },
- { 0x0DC7, 0x0E27 },
- { 0x0DC8, 0x0E28 },
- { 0x0DC9, 0x0E29 },
- { 0x0DCA, 0x0E2A },
- { 0x0DCB, 0x0E2B },
- { 0x0DCC, 0x0E2C },
- { 0x0DCD, 0x0E2D },
- { 0x0DCE, 0x0E2E },
- { 0x0DCF, 0x0E2F },
- { 0x0DD0, 0x0E30 },
- { 0x0DD1, 0x0E31 },
- { 0x0DD2, 0x0E32 },
- { 0x0DD3, 0x0E33 },
- { 0x0DD4, 0x0E34 },
- { 0x0DD5, 0x0E35 },
- { 0x0DD6, 0x0E36 },
- { 0x0DD7, 0x0E37 },
- { 0x0DD8, 0x0E38 },
- { 0x0DD9, 0x0E39 },
- { 0x0DDA, 0x0E3A },
- { 0x0DDF, 0x0E3F },
- { 0x0DE0, 0x0E40 },
- { 0x0DE1, 0x0E41 },
- { 0x0DE2, 0x0E42 },
- { 0x0DE3, 0x0E43 },
- { 0x0DE4, 0x0E44 },
- { 0x0DE5, 0x0E45 },
- { 0x0DE6, 0x0E46 },
- { 0x0DE7, 0x0E47 },
- { 0x0DE8, 0x0E48 },
- { 0x0DE9, 0x0E49 },
- { 0x0DEA, 0x0E4A },
- { 0x0DEB, 0x0E4B },
- { 0x0DEC, 0x0E4C },
- { 0x0DED, 0x0E4D },
- { 0x0DF0, 0x0E50 },
- { 0x0DF1, 0x0E51 },
- { 0x0DF2, 0x0E52 },
- { 0x0DF3, 0x0E53 },
- { 0x0DF4, 0x0E54 },
- { 0x0DF5, 0x0E55 },
- { 0x0DF6, 0x0E56 },
- { 0x0DF7, 0x0E57 },
- { 0x0DF8, 0x0E58 },
- { 0x0DF9, 0x0E59 },
- { 0x0ED4, 0x11A8 },
- { 0x0ED5, 0x11A9 },
- { 0x0ED6, 0x11AA },
- { 0x0ED7, 0x11AB },
- { 0x0ED8, 0x11AC },
- { 0x0ED9, 0x11AD },
- { 0x0EDA, 0x11AE },
- { 0x0EDB, 0x11AF },
- { 0x0EDC, 0x11B0 },
- { 0x0EDD, 0x11B1 },
- { 0x0EDE, 0x11B2 },
- { 0x0EDF, 0x11B3 },
- { 0x0EE0, 0x11B4 },
- { 0x0EE1, 0x11B5 },
- { 0x0EE2, 0x11B6 },
- { 0x0EE3, 0x11B7 },
- { 0x0EE4, 0x11B8 },
- { 0x0EE5, 0x11B9 },
- { 0x0EE6, 0x11BA },
- { 0x0EE7, 0x11BB },
- { 0x0EE8, 0x11BC },
- { 0x0EE9, 0x11BD },
- { 0x0EEA, 0x11BE },
- { 0x0EEB, 0x11BF },
- { 0x0EEC, 0x11C0 },
- { 0x0EED, 0x11C1 },
- { 0x0EEE, 0x11C2 },
- { 0x0EF8, 0x11EB },
- { 0x0EFA, 0x11F9 },
- { 0x0AA2, 0x2002 },
- { 0x0AA1, 0x2003 },
- { 0x0AA3, 0x2004 },
- { 0x0AA4, 0x2005 },
- { 0x0AA5, 0x2007 },
- { 0x0AA6, 0x2008 },
- { 0x0AA7, 0x2009 },
- { 0x0AA8, 0x200A },
- { 0x0ABB, 0x2012 },
- { 0x0AAA, 0x2013 },
- { 0x0AA9, 0x2014 },
- { 0x07AF, 0x2015 },
- { 0x0CDF, 0x2017 },
- { 0x0AD0, 0x2018 },
- { 0x0AD1, 0x2019 },
- { 0x0AFD, 0x201A },
- { 0x0AD2, 0x201C },
- { 0x0AD3, 0x201D },
- { 0x0AFE, 0x201E },
- { 0x0AF1, 0x2020 },
- { 0x0AF2, 0x2021 },
- { 0x0AE6, 0x2022 },
- { 0x0AAE, 0x2026 },
- { 0x0AD6, 0x2032 },
- { 0x0AD7, 0x2033 },
- { 0x0AFC, 0x2038 },
- { 0x047E, 0x203E },
- { 0x20A0, 0x20A0 },
- { 0x20A1, 0x20A1 },
- { 0x20A2, 0x20A2 },
- { 0x20A3, 0x20A3 },
- { 0x20A4, 0x20A4 },
- { 0x20A5, 0x20A5 },
- { 0x20A6, 0x20A6 },
- { 0x20A7, 0x20A7 },
- { 0x20A8, 0x20A8 },
- { 0x0EFF, 0x20A9 },
- { 0x20A9, 0x20A9 },
- { 0x20AA, 0x20AA },
- { 0x20AB, 0x20AB },
- { 0x20AC, 0x20AC },
- { 0x0AB8, 0x2105 },
- { 0x06B0, 0x2116 },
- { 0x0AFB, 0x2117 },
- { 0x0AD4, 0x211E },
- { 0x0AC9, 0x2122 },
- { 0x0AB0, 0x2153 },
- { 0x0AB1, 0x2154 },
- { 0x0AB2, 0x2155 },
- { 0x0AB3, 0x2156 },
- { 0x0AB4, 0x2157 },
- { 0x0AB5, 0x2158 },
- { 0x0AB6, 0x2159 },
- { 0x0AB7, 0x215A },
- { 0x0AC3, 0x215B },
- { 0x0AC4, 0x215C },
- { 0x0AC5, 0x215D },
- { 0x0AC6, 0x215E },
- { 0x08FB, 0x2190 },
- { 0x08FC, 0x2191 },
- { 0x08FD, 0x2192 },
- { 0x08FE, 0x2193 },
- { 0x08CE, 0x21D2 },
- { 0x08CD, 0x21D4 },
- { 0x08EF, 0x2202 },
- { 0x08C5, 0x2207 },
- { 0x0BCA, 0x2218 },
- { 0x08D6, 0x221A },
- { 0x08C1, 0x221D },
- { 0x08C2, 0x221E },
- { 0x08DE, 0x2227 },
- { 0x0BA9, 0x2227 },
- { 0x08DF, 0x2228 },
- { 0x0BA8, 0x2228 },
- { 0x08DC, 0x2229 },
- { 0x0BC3, 0x2229 },
- { 0x08DD, 0x222A },
- { 0x0BD6, 0x222A },
- { 0x08BF, 0x222B },
- { 0x08C0, 0x2234 },
- { 0x08C8, 0x2245 },
- { 0x08BD, 0x2260 },
- { 0x08CF, 0x2261 },
- { 0x08BC, 0x2264 },
- { 0x08BE, 0x2265 },
- { 0x08DA, 0x2282 },
- { 0x0BDA, 0x2282 },
- { 0x08DB, 0x2283 },
- { 0x0BD8, 0x2283 },
- { 0x0BFC, 0x22A2 },
- { 0x0BDC, 0x22A3 },
- { 0x0BC2, 0x22A4 },
- { 0x0BCE, 0x22A5 },
- { 0x0BD3, 0x2308 },
- { 0x0BC4, 0x230A },
- { 0x0AFA, 0x2315 },
- { 0x08A4, 0x2320 },
- { 0x08A5, 0x2321 },
- { 0x0ABC, 0x2329 },
- { 0x0ABE, 0x232A },
- { 0x0BCC, 0x2395 },
- { 0x09E2, 0x2409 },
- { 0x09E5, 0x240A },
- { 0x09E9, 0x240B },
- { 0x09E3, 0x240C },
- { 0x09E4, 0x240D },
- { 0x09DF, 0x2422 },
- { 0x09E8, 0x2424 },
- { 0x09F1, 0x2500 },
- { 0x08A6, 0x2502 },
- { 0x09F8, 0x2502 },
- { 0x09EC, 0x250C },
- { 0x09EB, 0x2510 },
- { 0x09ED, 0x2514 },
- { 0x09EA, 0x2518 },
- { 0x09F4, 0x251C },
- { 0x09F5, 0x2524 },
- { 0x09F7, 0x252C },
- { 0x09F6, 0x2534 },
- { 0x09EE, 0x253C },
- { 0x09E1, 0x2592 },
- { 0x0ADF, 0x25A0 },
- { 0x0ACF, 0x25A1 },
- { 0x0AE7, 0x25AA },
- { 0x0AE1, 0x25AB },
- { 0x0ADB, 0x25AC },
- { 0x0AE2, 0x25AD },
- { 0x0AE8, 0x25B2 },
- { 0x0AE3, 0x25B3 },
- { 0x0ADD, 0x25B6 },
- { 0x0ACD, 0x25B7 },
- { 0x0AE9, 0x25BC },
- { 0x0AE4, 0x25BD },
- { 0x0ADC, 0x25C0 },
- { 0x0ACC, 0x25C1 },
- { 0x09E0, 0x25C6 },
- { 0x0ACE, 0x25CB },
- { 0x0BCF, 0x25CB },
- { 0x0ADE, 0x25CF },
- { 0x0AE0, 0x25E6 },
- { 0x0AE5, 0x2606 },
- { 0x0AF9, 0x260E },
- { 0x0ACA, 0x2613 },
- { 0x0AEA, 0x261C },
- { 0x0AEB, 0x261E },
- { 0x0AF8, 0x2640 },
- { 0x0AF7, 0x2642 },
- { 0x0AEC, 0x2663 },
- { 0x0AEE, 0x2665 },
- { 0x0AED, 0x2666 },
- { 0x0AF6, 0x266D },
- { 0x0AF5, 0x266F },
- { 0x0AF3, 0x2713 },
- { 0x0AF4, 0x2717 },
- { 0x0AD9, 0x271D },
- { 0x0AF0, 0x2720 },
- { 0x04A4, 0x3001 },
- { 0x04A1, 0x3002 },
- { 0x04A2, 0x300C },
- { 0x04A3, 0x300D },
- { 0x04DE, 0x309B },
- { 0x04DF, 0x309C },
- { 0x04A7, 0x30A1 },
- { 0x04B1, 0x30A2 },
- { 0x04A8, 0x30A3 },
- { 0x04B2, 0x30A4 },
- { 0x04A9, 0x30A5 },
- { 0x04B3, 0x30A6 },
- { 0x04AA, 0x30A7 },
- { 0x04B4, 0x30A8 },
- { 0x04AB, 0x30A9 },
- { 0x04B5, 0x30AA },
- { 0x04B6, 0x30AB },
- { 0x04B7, 0x30AD },
- { 0x04B8, 0x30AF },
- { 0x04B9, 0x30B1 },
- { 0x04BA, 0x30B3 },
- { 0x04BB, 0x30B5 },
- { 0x04BC, 0x30B7 },
- { 0x04BD, 0x30B9 },
- { 0x04BE, 0x30BB },
- { 0x04BF, 0x30BD },
- { 0x04C0, 0x30BF },
- { 0x04C1, 0x30C1 },
- { 0x04AF, 0x30C3 },
- { 0x04C2, 0x30C4 },
- { 0x04C3, 0x30C6 },
- { 0x04C4, 0x30C8 },
- { 0x04C5, 0x30CA },
- { 0x04C6, 0x30CB },
- { 0x04C7, 0x30CC },
- { 0x04C8, 0x30CD },
- { 0x04C9, 0x30CE },
- { 0x04CA, 0x30CF },
- { 0x04CB, 0x30D2 },
- { 0x04CC, 0x30D5 },
- { 0x04CD, 0x30D8 },
- { 0x04CE, 0x30DB },
- { 0x04CF, 0x30DE },
- { 0x04D0, 0x30DF },
- { 0x04D1, 0x30E0 },
- { 0x04D2, 0x30E1 },
- { 0x04D3, 0x30E2 },
- { 0x04AC, 0x30E3 },
- { 0x04D4, 0x30E4 },
- { 0x04AD, 0x30E5 },
- { 0x04D5, 0x30E6 },
- { 0x04AE, 0x30E7 },
- { 0x04D6, 0x30E8 },
- { 0x04D7, 0x30E9 },
- { 0x04D8, 0x30EA },
- { 0x04D9, 0x30EB },
- { 0x04DA, 0x30EC },
- { 0x04DB, 0x30ED },
- { 0x04DC, 0x30EF },
- { 0x04A6, 0x30F2 },
- { 0x04DD, 0x30F3 },
- { 0x04A5, 0x30FB },
- { 0x04B0, 0x30FC },
- { 0x0EA1, 0x3131 },
- { 0x0EA2, 0x3132 },
- { 0x0EA3, 0x3133 },
- { 0x0EA4, 0x3134 },
- { 0x0EA5, 0x3135 },
- { 0x0EA6, 0x3136 },
- { 0x0EA7, 0x3137 },
- { 0x0EA8, 0x3138 },
- { 0x0EA9, 0x3139 },
- { 0x0EAA, 0x313A },
- { 0x0EAB, 0x313B },
- { 0x0EAC, 0x313C },
- { 0x0EAD, 0x313D },
- { 0x0EAE, 0x313E },
- { 0x0EAF, 0x313F },
- { 0x0EB0, 0x3140 },
- { 0x0EB1, 0x3141 },
- { 0x0EB2, 0x3142 },
- { 0x0EB3, 0x3143 },
- { 0x0EB4, 0x3144 },
- { 0x0EB5, 0x3145 },
- { 0x0EB6, 0x3146 },
- { 0x0EB7, 0x3147 },
- { 0x0EB8, 0x3148 },
- { 0x0EB9, 0x3149 },
- { 0x0EBA, 0x314A },
- { 0x0EBB, 0x314B },
- { 0x0EBC, 0x314C },
- { 0x0EBD, 0x314D },
- { 0x0EBE, 0x314E },
- { 0x0EBF, 0x314F },
- { 0x0EC0, 0x3150 },
- { 0x0EC1, 0x3151 },
- { 0x0EC2, 0x3152 },
- { 0x0EC3, 0x3153 },
- { 0x0EC4, 0x3154 },
- { 0x0EC5, 0x3155 },
- { 0x0EC6, 0x3156 },
- { 0x0EC7, 0x3157 },
- { 0x0EC8, 0x3158 },
- { 0x0EC9, 0x3159 },
- { 0x0ECA, 0x315A },
- { 0x0ECB, 0x315B },
- { 0x0ECC, 0x315C },
- { 0x0ECD, 0x315D },
- { 0x0ECE, 0x315E },
- { 0x0ECF, 0x315F },
- { 0x0ED0, 0x3160 },
- { 0x0ED1, 0x3161 },
- { 0x0ED2, 0x3162 },
- { 0x0ED3, 0x3163 },
- { 0x0EEF, 0x316D },
- { 0x0EF0, 0x3171 },
- { 0x0EF1, 0x3178 },
- { 0x0EF2, 0x317F },
- { 0x0EF4, 0x3184 },
- { 0x0EF5, 0x3186 },
- { 0x0EF6, 0x318D },
- { 0x0EF7, 0x318E }
-};
-
-KeySym KeyMappingX11::get_keysym_from_unicode(unsigned int p_unicode) {
- /* Latin 1 */
-
- if (p_unicode >= 0x20 && p_unicode <= 0x7e) {
- return p_unicode;
+ // Unicode (may be present).
+ if ((p_keysym & 0xFF000000) == 0x01000000) {
+ return p_keysym & 0x00FFFFFF;
}
- if (p_unicode >= 0xa0 && p_unicode <= 0xff) {
- return p_unicode;
+ const char32_t *c = xkeysym_unicode_map.getptr(p_keysym);
+ if (c) {
+ return *c;
}
-
- int middle, low = 0, high = _UNICODE_MAX - 1;
- do {
- middle = (high + low) / 2;
- if (_unicode_to_xkeysym[middle].keysym == p_unicode) {
- return _unicode_to_xkeysym[middle].keysym;
- }
- if (_unicode_to_xkeysym[middle].keysym <= p_unicode) {
- low = middle + 1;
- } else {
- high = middle - 1;
- }
- } while (high >= low);
-
- // if not found, let's hope X understands it as unicode
- return p_unicode | 0x01000000;
+ return 0;
}
diff --git a/platform/linuxbsd/x11/key_mapping_x11.h b/platform/linuxbsd/x11/key_mapping_x11.h
index 2b411e21d2..d4278a563c 100644
--- a/platform/linuxbsd/x11/key_mapping_x11.h
+++ b/platform/linuxbsd/x11/key_mapping_x11.h
@@ -44,12 +44,12 @@ class KeyMappingX11 {
KeyMappingX11() {}
public:
+ static void initialize();
+
static Key get_keycode(KeySym p_keysym);
static unsigned int get_xlibcode(Key p_keysym);
static Key get_scancode(unsigned int p_code);
- static KeySym get_keysym(Key p_code);
- static unsigned int get_unicode_from_keysym(KeySym p_keysym);
- static KeySym get_keysym_from_unicode(unsigned int p_unicode);
+ static char32_t get_unicode_from_keysym(KeySym p_keysym);
};
#endif // KEY_MAPPING_X11_H
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index 14e6e92bfa..cd46dab4f3 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -230,7 +230,7 @@ def configure(env: "Environment"):
env.Append(LIBS=["pthread", "z"])
if env["opengl3"]:
- env.Append(CPPDEFINES=["GLES_ENABLED", "GLES3_ENABLED"])
+ env.Append(CPPDEFINES=["GLES3_ENABLED"])
env.Append(LINKFLAGS=["-framework", "OpenGL"])
env.Append(LINKFLAGS=["-rpath", "@executable_path/../Frameworks", "-rpath", "@executable_path"])
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 4873db4b64..fb9bcdfe56 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -69,6 +69,7 @@ public:
bool raw = false;
Key keycode = Key::NONE;
Key physical_keycode = Key::NONE;
+ Key key_label = Key::NONE;
uint32_t unicode = 0;
};
@@ -201,8 +202,6 @@ private:
Point2i _get_native_screen_position(int p_screen) const;
static void _displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info);
- WindowID _get_focused_window_or_popup() const;
-
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
void _dispatch_input_event(const Ref<InputEvent> &p_event);
void _push_input(const Ref<InputEvent> &p_event);
@@ -229,6 +228,7 @@ public:
void get_key_modifier_state(unsigned int p_macos_state, Ref<InputEventWithModifiers> r_state) const;
void update_mouse_pos(WindowData &p_wd, NSPoint p_location_in_window);
void push_to_key_event_buffer(const KeyEvent &p_event);
+ void pop_last_key_event();
void update_im_text(const Point2i &p_selection, const String &p_text);
void set_last_focused_window(WindowID p_window);
bool mouse_process_popups(bool p_close = false);
@@ -237,6 +237,7 @@ public:
void set_is_resizing(bool p_is_resizing);
bool get_is_resizing() const;
void reparent_check(WindowID p_window);
+ WindowID _get_focused_window_or_popup() const;
void window_update(WindowID p_window);
void window_destroy(WindowID p_window);
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index d992467042..2832495693 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -434,7 +434,8 @@ void DisplayServerMacOS::_process_key_events() {
k->set_pressed(ke.pressed);
k->set_echo(ke.echo);
k->set_keycode(ke.keycode);
- k->set_physical_keycode((Key)ke.physical_keycode);
+ k->set_physical_keycode(ke.physical_keycode);
+ k->set_key_label(ke.key_label);
k->set_unicode(ke.unicode);
_push_input(k);
@@ -449,6 +450,7 @@ void DisplayServerMacOS::_process_key_events() {
k->set_echo(ke.echo);
k->set_keycode(Key::NONE);
k->set_physical_keycode(Key::NONE);
+ k->set_key_label(Key::NONE);
k->set_unicode(ke.unicode);
_push_input(k);
@@ -461,7 +463,8 @@ void DisplayServerMacOS::_process_key_events() {
k->set_pressed(ke.pressed);
k->set_echo(ke.echo);
k->set_keycode(ke.keycode);
- k->set_physical_keycode((Key)ke.physical_keycode);
+ k->set_physical_keycode(ke.physical_keycode);
+ k->set_key_label(ke.key_label);
if (i + 1 < key_event_pos && key_event_buffer[i + 1].keycode == Key::NONE) {
k->set_unicode(key_event_buffer[i + 1].unicode);
@@ -633,6 +636,7 @@ void DisplayServerMacOS::send_event(NSEvent *p_event) {
k->set_pressed(true);
k->set_keycode(Key::PERIOD);
k->set_physical_keycode(Key::PERIOD);
+ k->set_key_label(Key::PERIOD);
k->set_echo([p_event isARepeat]);
Input::get_singleton()->parse_input_event(k);
@@ -674,6 +678,12 @@ void DisplayServerMacOS::update_mouse_pos(DisplayServerMacOS::WindowData &p_wd,
Input::get_singleton()->set_mouse_position(p_wd.mouse_pos);
}
+void DisplayServerMacOS::pop_last_key_event() {
+ if (key_event_pos > 0) {
+ key_event_pos--;
+ }
+}
+
void DisplayServerMacOS::push_to_key_event_buffer(const DisplayServerMacOS::KeyEvent &p_event) {
if (key_event_pos >= key_event_buffer.size()) {
key_event_buffer.resize(1 + key_event_pos);
@@ -3142,7 +3152,9 @@ ObjectID DisplayServerMacOS::window_get_attached_instance_id(WindowID p_window)
void DisplayServerMacOS::gl_window_make_current(DisplayServer::WindowID p_window_id) {
#if defined(GLES3_ENABLED)
- gl_manager->window_make_current(p_window_id);
+ if (gl_manager) {
+ gl_manager->window_make_current(p_window_id);
+ }
#endif
}
@@ -3449,14 +3461,14 @@ String DisplayServerMacOS::keyboard_get_layout_name(int p_index) const {
}
Key DisplayServerMacOS::keyboard_get_keycode_from_physical(Key p_keycode) const {
- if (p_keycode == Key::PAUSE) {
+ if (p_keycode == Key::PAUSE || p_keycode == Key::NONE) {
return p_keycode;
}
Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK;
- unsigned int macos_keycode = KeyMappingMacOS::unmap_key((Key)keycode_no_mod);
- return (Key)(KeyMappingMacOS::remap_key(macos_keycode, 0) | modifiers);
+ unsigned int macos_keycode = KeyMappingMacOS::unmap_key(keycode_no_mod);
+ return (Key)(KeyMappingMacOS::remap_key(macos_keycode, 0, false) | modifiers);
}
void DisplayServerMacOS::process_events() {
@@ -3768,6 +3780,8 @@ bool DisplayServerMacOS::mouse_process_popups(bool p_close) {
}
DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
+ KeyMappingMacOS::initialize();
+
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
r_error = OK;
diff --git a/platform/macos/godot_application.h b/platform/macos/godot_application.h
index f41fc2646d..8749c8fbb0 100644
--- a/platform/macos/godot_application.h
+++ b/platform/macos/godot_application.h
@@ -35,6 +35,7 @@
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
+#import <IOKit/hidsystem/ev_keymap.h>
@interface GodotApplication : NSApplication
@end
diff --git a/platform/macos/godot_application.mm b/platform/macos/godot_application.mm
index 0c282930f4..e3a744caa2 100644
--- a/platform/macos/godot_application.mm
+++ b/platform/macos/godot_application.mm
@@ -34,7 +34,81 @@
@implementation GodotApplication
+- (void)mediaKeyEvent:(int)key state:(BOOL)state repeat:(BOOL)repeat {
+ Key keycode = Key::NONE;
+ switch (key) {
+ case NX_KEYTYPE_SOUND_UP: {
+ keycode = Key::VOLUMEUP;
+ } break;
+ case NX_KEYTYPE_SOUND_DOWN: {
+ keycode = Key::VOLUMEUP;
+ } break;
+ //NX_KEYTYPE_BRIGHTNESS_UP
+ //NX_KEYTYPE_BRIGHTNESS_DOWN
+ case NX_KEYTYPE_CAPS_LOCK: {
+ keycode = Key::CAPSLOCK;
+ } break;
+ case NX_KEYTYPE_HELP: {
+ keycode = Key::HELP;
+ } break;
+ case NX_POWER_KEY: {
+ keycode = Key::STANDBY;
+ } break;
+ case NX_KEYTYPE_MUTE: {
+ keycode = Key::VOLUMEMUTE;
+ } break;
+ //NX_KEYTYPE_CONTRAST_UP
+ //NX_KEYTYPE_CONTRAST_DOWN
+ //NX_KEYTYPE_LAUNCH_PANEL
+ //NX_KEYTYPE_EJECT
+ //NX_KEYTYPE_VIDMIRROR
+ //NX_KEYTYPE_FAST
+ //NX_KEYTYPE_REWIND
+ //NX_KEYTYPE_ILLUMINATION_UP
+ //NX_KEYTYPE_ILLUMINATION_DOWN
+ //NX_KEYTYPE_ILLUMINATION_TOGGLE
+ case NX_KEYTYPE_PLAY: {
+ keycode = Key::MEDIAPLAY;
+ } break;
+ case NX_KEYTYPE_NEXT: {
+ keycode = Key::MEDIANEXT;
+ } break;
+ case NX_KEYTYPE_PREVIOUS: {
+ keycode = Key::MEDIAPREVIOUS;
+ } break;
+ default: {
+ keycode = Key::NONE;
+ } break;
+ }
+
+ DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
+ if (ds && keycode != Key::NONE) {
+ DisplayServerMacOS::KeyEvent ke;
+
+ ke.window_id = ds->_get_focused_window_or_popup();
+ ke.macos_state = 0;
+ ke.pressed = state;
+ ke.echo = repeat;
+ ke.keycode = keycode;
+ ke.physical_keycode = keycode;
+ ke.key_label = keycode;
+ ke.unicode = 0;
+ ke.raw = true;
+
+ ds->push_to_key_event_buffer(ke);
+ }
+}
+
- (void)sendEvent:(NSEvent *)event {
+ if ([event type] == NSSystemDefined && [event subtype] == 8) {
+ int keyCode = (([event data1] & 0xFFFF0000) >> 16);
+ int keyFlags = ([event data1] & 0x0000FFFF);
+ int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
+ int keyRepeat = (keyFlags & 0x1);
+
+ [self mediaKeyEvent:keyCode state:keyState repeat:keyRepeat];
+ }
+
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (ds) {
if ([event type] == NSEventTypeLeftMouseDown || [event type] == NSEventTypeRightMouseDown || [event type] == NSEventTypeOtherMouseDown) {
diff --git a/platform/macos/godot_content_view.h b/platform/macos/godot_content_view.h
index e660285e49..0d18ac742a 100644
--- a/platform/macos/godot_content_view.h
+++ b/platform/macos/godot_content_view.h
@@ -64,6 +64,7 @@
bool mouse_down_control;
bool ignore_momentum_scroll;
bool last_pen_inverted;
+ bool ime_suppress_next_keyup;
id layer_delegate;
}
diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm
index 337aa59a5e..485f80a22e 100644
--- a/platform/macos/godot_content_view.mm
+++ b/platform/macos/godot_content_view.mm
@@ -185,6 +185,7 @@
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
if (wd.im_active) {
ime_input_event_in_progress = true;
+ ds->pop_last_key_event();
ds->update_im_text(Point2i(selectedRange.location, selectedRange.length), String::utf8([[marked_text mutableString] UTF8String]));
}
}
@@ -194,6 +195,9 @@
}
- (void)unmarkText {
+ if (ime_input_event_in_progress) {
+ ime_suppress_next_keyup = true;
+ }
ime_input_event_in_progress = false;
[[marked_text mutableString] setString:@""];
@@ -245,8 +249,6 @@
}
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
- NSEvent *event = [NSApp currentEvent];
-
NSString *characters;
if ([aString isKindOfClass:[NSAttributedString class]]) {
characters = [aString string];
@@ -284,13 +286,14 @@
DisplayServerMacOS::KeyEvent ke;
ke.window_id = window_id;
- ke.macos_state = [event modifierFlags];
+ ke.macos_state = 0;
ke.pressed = true;
ke.echo = false;
ke.raw = false; // IME input event.
ke.keycode = Key::NONE;
ke.physical_keycode = Key::NONE;
- ke.unicode = codepoint;
+ ke.key_label = Key::NONE;
+ ke.unicode = fix_unicode(codepoint);
ds->push_to_key_event_buffer(ke);
}
@@ -584,7 +587,7 @@
NSString *characters = [event characters];
NSUInteger length = [characters length];
- if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]))) {
+ if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true))) {
// Fallback unicode character handler used if IME is not active.
Char16String text;
text.resize([characters length] + 1);
@@ -602,10 +605,11 @@
ke.macos_state = [event modifierFlags];
ke.pressed = true;
ke.echo = [event isARepeat];
- ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]);
+ ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], false);
ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
+ ke.key_label = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true);
+ ke.unicode = fix_unicode(codepoint);
ke.raw = true;
- ke.unicode = codepoint;
ds->push_to_key_event_buffer(ke);
}
@@ -616,10 +620,11 @@
ke.macos_state = [event modifierFlags];
ke.pressed = true;
ke.echo = [event isARepeat];
- ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]);
+ ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], false);
ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
- ke.raw = false;
+ ke.key_label = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true);
ke.unicode = 0;
+ ke.raw = false;
ds->push_to_key_event_buffer(ke);
}
@@ -638,56 +643,54 @@
}
ignore_momentum_scroll = true;
- // Ignore all input if IME input is in progress
- if (!ime_input_event_in_progress) {
- DisplayServerMacOS::KeyEvent ke;
+ DisplayServerMacOS::KeyEvent ke;
- ke.window_id = window_id;
- ke.echo = false;
- ke.raw = true;
+ ke.window_id = window_id;
+ ke.echo = false;
+ ke.raw = true;
- int key = [event keyCode];
- int mod = [event modifierFlags];
+ int key = [event keyCode];
+ int mod = [event modifierFlags];
- if (key == 0x36 || key == 0x37) {
- if (mod & NSEventModifierFlagCommand) {
- mod &= ~NSEventModifierFlagCommand;
- ke.pressed = true;
- } else {
- ke.pressed = false;
- }
- } else if (key == 0x38 || key == 0x3c) {
- if (mod & NSEventModifierFlagShift) {
- mod &= ~NSEventModifierFlagShift;
- ke.pressed = true;
- } else {
- ke.pressed = false;
- }
- } else if (key == 0x3a || key == 0x3d) {
- if (mod & NSEventModifierFlagOption) {
- mod &= ~NSEventModifierFlagOption;
- ke.pressed = true;
- } else {
- ke.pressed = false;
- }
- } else if (key == 0x3b || key == 0x3e) {
- if (mod & NSEventModifierFlagControl) {
- mod &= ~NSEventModifierFlagControl;
- ke.pressed = true;
- } else {
- ke.pressed = false;
- }
+ if (key == 0x36 || key == 0x37) {
+ if (mod & NSEventModifierFlagCommand) {
+ mod &= ~NSEventModifierFlagCommand;
+ ke.pressed = true;
} else {
- return;
+ ke.pressed = false;
}
+ } else if (key == 0x38 || key == 0x3c) {
+ if (mod & NSEventModifierFlagShift) {
+ mod &= ~NSEventModifierFlagShift;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
+ } else if (key == 0x3a || key == 0x3d) {
+ if (mod & NSEventModifierFlagOption) {
+ mod &= ~NSEventModifierFlagOption;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
+ } else if (key == 0x3b || key == 0x3e) {
+ if (mod & NSEventModifierFlagControl) {
+ mod &= ~NSEventModifierFlagControl;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
+ } else {
+ return;
+ }
- ke.macos_state = mod;
- ke.keycode = KeyMappingMacOS::remap_key(key, mod);
- ke.physical_keycode = KeyMappingMacOS::translate_key(key);
- ke.unicode = 0;
+ ke.macos_state = mod;
+ ke.keycode = KeyMappingMacOS::remap_key(key, mod, false);
+ ke.physical_keycode = KeyMappingMacOS::translate_key(key);
+ ke.key_label = KeyMappingMacOS::remap_key(key, mod, true);
+ ke.unicode = 0;
- ds->push_to_key_event_buffer(ke);
- }
+ ds->push_to_key_event_buffer(ke);
}
- (void)keyUp:(NSEvent *)event {
@@ -696,51 +699,26 @@
return;
}
- DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
-
// Ignore all input if IME input is in progress.
- if (!ime_input_event_in_progress) {
- NSString *characters = [event characters];
- NSUInteger length = [characters length];
-
- // Fallback unicode character handler used if IME is not active.
- if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]))) {
- Char16String text;
- text.resize([characters length] + 1);
- [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
-
- String u32text;
- u32text.parse_utf16(text.ptr(), text.length());
-
- for (int i = 0; i < u32text.length(); i++) {
- const char32_t codepoint = u32text[i];
- DisplayServerMacOS::KeyEvent ke;
-
- ke.window_id = window_id;
- ke.macos_state = [event modifierFlags];
- ke.pressed = false;
- ke.echo = [event isARepeat];
- ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]);
- ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
- ke.raw = true;
- ke.unicode = codepoint;
+ if (ime_suppress_next_keyup) {
+ ime_suppress_next_keyup = false;
+ return;
+ }
- ds->push_to_key_event_buffer(ke);
- }
- } else {
- DisplayServerMacOS::KeyEvent ke;
+ if (!ime_input_event_in_progress) {
+ DisplayServerMacOS::KeyEvent ke;
- ke.window_id = window_id;
- ke.macos_state = [event modifierFlags];
- ke.pressed = false;
- ke.echo = [event isARepeat];
- ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]);
- ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
- ke.raw = true;
- ke.unicode = 0;
+ ke.window_id = window_id;
+ ke.macos_state = [event modifierFlags];
+ ke.pressed = false;
+ ke.echo = [event isARepeat];
+ ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], false);
+ ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
+ ke.key_label = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true);
+ ke.unicode = 0;
+ ke.raw = true;
- ds->push_to_key_event_buffer(ke);
- }
+ ds->push_to_key_event_buffer(ke);
}
}
diff --git a/platform/macos/key_mapping_macos.h b/platform/macos/key_mapping_macos.h
index 5128005627..1bda4eb406 100644
--- a/platform/macos/key_mapping_macos.h
+++ b/platform/macos/key_mapping_macos.h
@@ -36,13 +36,15 @@
class KeyMappingMacOS {
KeyMappingMacOS() {}
- static bool is_numpad_key(unsigned int key);
+ static bool is_numpad_key(unsigned int p_key);
public:
+ static void initialize();
+
// Mappings input.
- static Key translate_key(unsigned int key);
- static unsigned int unmap_key(Key key);
- static Key remap_key(unsigned int key, unsigned int state);
+ static Key translate_key(unsigned int p_key);
+ static unsigned int unmap_key(Key p_key);
+ static Key remap_key(unsigned int p_key, unsigned int p_state, bool p_unicode);
// Mapping for menu shortcuts.
static String keycode_get_native_string(Key p_keycode);
diff --git a/platform/macos/key_mapping_macos.mm b/platform/macos/key_mapping_macos.mm
index 478c84e81c..31b71ac1b8 100644
--- a/platform/macos/key_mapping_macos.mm
+++ b/platform/macos/key_mapping_macos.mm
@@ -33,277 +33,345 @@
#import <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h>
-bool KeyMappingMacOS::is_numpad_key(unsigned int key) {
- static const unsigned int table[] = {
- 0x41, /* kVK_ANSI_KeypadDecimal */
- 0x43, /* kVK_ANSI_KeypadMultiply */
- 0x45, /* kVK_ANSI_KeypadPlus */
- 0x47, /* kVK_ANSI_KeypadClear */
- 0x4b, /* kVK_ANSI_KeypadDivide */
- 0x4c, /* kVK_ANSI_KeypadEnter */
- 0x4e, /* kVK_ANSI_KeypadMinus */
- 0x51, /* kVK_ANSI_KeypadEquals */
- 0x52, /* kVK_ANSI_Keypad0 */
- 0x53, /* kVK_ANSI_Keypad1 */
- 0x54, /* kVK_ANSI_Keypad2 */
- 0x55, /* kVK_ANSI_Keypad3 */
- 0x56, /* kVK_ANSI_Keypad4 */
- 0x57, /* kVK_ANSI_Keypad5 */
- 0x58, /* kVK_ANSI_Keypad6 */
- 0x59, /* kVK_ANSI_Keypad7 */
- 0x5b, /* kVK_ANSI_Keypad8 */
- 0x5c, /* kVK_ANSI_Keypad9 */
- 0x5f, /* kVK_JIS_KeypadComma */
- 0x00
- };
- for (int i = 0; table[i] != 0; i++) {
- if (key == table[i]) {
- return true;
- }
+#include "core/templates/hash_map.h"
+#include "core/templates/hash_set.h"
+
+struct HashMapHasherKeys {
+ static _FORCE_INLINE_ uint32_t hash(const Key p_key) { return hash_fmix32(static_cast<uint32_t>(p_key)); }
+ static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
+ static _FORCE_INLINE_ uint32_t hash(const unsigned p_key) { return hash_fmix32(p_key); }
+};
+
+HashSet<unsigned int> numpad_keys;
+HashMap<unsigned int, Key, HashMapHasherKeys> keysym_map;
+HashMap<Key, unsigned int, HashMapHasherKeys> keysym_map_inv;
+HashMap<Key, char32_t, HashMapHasherKeys> keycode_map;
+
+void KeyMappingMacOS::initialize() {
+ numpad_keys.insert(0x41); //kVK_ANSI_KeypadDecimal
+ numpad_keys.insert(0x43); //kVK_ANSI_KeypadMultiply
+ numpad_keys.insert(0x45); //kVK_ANSI_KeypadPlus
+ numpad_keys.insert(0x47); //kVK_ANSI_KeypadClear
+ numpad_keys.insert(0x4b); //kVK_ANSI_KeypadDivide
+ numpad_keys.insert(0x4c); //kVK_ANSI_KeypadEnter
+ numpad_keys.insert(0x4e); //kVK_ANSI_KeypadMinus
+ numpad_keys.insert(0x51); //kVK_ANSI_KeypadEquals
+ numpad_keys.insert(0x52); //kVK_ANSI_Keypad0
+ numpad_keys.insert(0x53); //kVK_ANSI_Keypad1
+ numpad_keys.insert(0x54); //kVK_ANSI_Keypad2
+ numpad_keys.insert(0x55); //kVK_ANSI_Keypad3
+ numpad_keys.insert(0x56); //kVK_ANSI_Keypad4
+ numpad_keys.insert(0x57); //kVK_ANSI_Keypad5
+ numpad_keys.insert(0x58); //kVK_ANSI_Keypad6
+ numpad_keys.insert(0x59); //kVK_ANSI_Keypad7
+ numpad_keys.insert(0x5b); //kVK_ANSI_Keypad8
+ numpad_keys.insert(0x5c); //kVK_ANSI_Keypad9
+ numpad_keys.insert(0x5f); //kVK_JIS_KeypadComma
+
+ keysym_map[0x00] = Key::A;
+ keysym_map[0x01] = Key::S;
+ keysym_map[0x02] = Key::D;
+ keysym_map[0x03] = Key::F;
+ keysym_map[0x04] = Key::H;
+ keysym_map[0x05] = Key::G;
+ keysym_map[0x06] = Key::Z;
+ keysym_map[0x07] = Key::X;
+ keysym_map[0x08] = Key::C;
+ keysym_map[0x09] = Key::V;
+ keysym_map[0x0a] = Key::SECTION;
+ keysym_map[0x0b] = Key::B;
+ keysym_map[0x0c] = Key::Q;
+ keysym_map[0x0d] = Key::W;
+ keysym_map[0x0e] = Key::E;
+ keysym_map[0x0f] = Key::R;
+ keysym_map[0x10] = Key::Y;
+ keysym_map[0x11] = Key::T;
+ keysym_map[0x12] = Key::KEY_1;
+ keysym_map[0x13] = Key::KEY_2;
+ keysym_map[0x14] = Key::KEY_3;
+ keysym_map[0x15] = Key::KEY_4;
+ keysym_map[0x16] = Key::KEY_6;
+ keysym_map[0x17] = Key::KEY_5;
+ keysym_map[0x18] = Key::EQUAL;
+ keysym_map[0x19] = Key::KEY_9;
+ keysym_map[0x1a] = Key::KEY_7;
+ keysym_map[0x1b] = Key::MINUS;
+ keysym_map[0x1c] = Key::KEY_8;
+ keysym_map[0x1d] = Key::KEY_0;
+ keysym_map[0x1e] = Key::BRACERIGHT;
+ keysym_map[0x1f] = Key::O;
+ keysym_map[0x20] = Key::U;
+ keysym_map[0x21] = Key::BRACELEFT;
+ keysym_map[0x22] = Key::I;
+ keysym_map[0x23] = Key::P;
+ keysym_map[0x24] = Key::ENTER;
+ keysym_map[0x25] = Key::L;
+ keysym_map[0x26] = Key::J;
+ keysym_map[0x27] = Key::APOSTROPHE;
+ keysym_map[0x28] = Key::K;
+ keysym_map[0x29] = Key::SEMICOLON;
+ keysym_map[0x2a] = Key::BACKSLASH;
+ keysym_map[0x2b] = Key::COMMA;
+ keysym_map[0x2c] = Key::SLASH;
+ keysym_map[0x2d] = Key::N;
+ keysym_map[0x2e] = Key::M;
+ keysym_map[0x2f] = Key::PERIOD;
+ keysym_map[0x30] = Key::TAB;
+ keysym_map[0x31] = Key::SPACE;
+ keysym_map[0x32] = Key::QUOTELEFT;
+ keysym_map[0x33] = Key::BACKSPACE;
+ keysym_map[0x35] = Key::ESCAPE;
+ keysym_map[0x36] = Key::META;
+ keysym_map[0x37] = Key::META;
+ keysym_map[0x38] = Key::SHIFT;
+ keysym_map[0x39] = Key::CAPSLOCK;
+ keysym_map[0x3a] = Key::ALT;
+ keysym_map[0x3b] = Key::CTRL;
+ keysym_map[0x3c] = Key::SHIFT;
+ keysym_map[0x3d] = Key::ALT;
+ keysym_map[0x3e] = Key::CTRL;
+ keysym_map[0x40] = Key::F17;
+ keysym_map[0x41] = Key::KP_PERIOD;
+ keysym_map[0x43] = Key::KP_MULTIPLY;
+ keysym_map[0x45] = Key::KP_ADD;
+ keysym_map[0x47] = Key::NUMLOCK;
+ keysym_map[0x48] = Key::VOLUMEUP;
+ keysym_map[0x49] = Key::VOLUMEDOWN;
+ keysym_map[0x4a] = Key::VOLUMEMUTE;
+ keysym_map[0x4b] = Key::KP_DIVIDE;
+ keysym_map[0x4c] = Key::KP_ENTER;
+ keysym_map[0x4e] = Key::KP_SUBTRACT;
+ keysym_map[0x4f] = Key::F18;
+ keysym_map[0x50] = Key::F19;
+ keysym_map[0x51] = Key::EQUAL;
+ keysym_map[0x52] = Key::KP_0;
+ keysym_map[0x53] = Key::KP_1;
+ keysym_map[0x54] = Key::KP_2;
+ keysym_map[0x55] = Key::KP_3;
+ keysym_map[0x56] = Key::KP_4;
+ keysym_map[0x57] = Key::KP_5;
+ keysym_map[0x58] = Key::KP_6;
+ keysym_map[0x59] = Key::KP_7;
+ keysym_map[0x5a] = Key::F20;
+ keysym_map[0x5b] = Key::KP_8;
+ keysym_map[0x5c] = Key::KP_9;
+ keysym_map[0x5d] = Key::YEN;
+ keysym_map[0x5e] = Key::UNDERSCORE;
+ keysym_map[0x5f] = Key::COMMA;
+ keysym_map[0x60] = Key::F5;
+ keysym_map[0x61] = Key::F6;
+ keysym_map[0x62] = Key::F7;
+ keysym_map[0x63] = Key::F3;
+ keysym_map[0x64] = Key::F8;
+ keysym_map[0x65] = Key::F9;
+ keysym_map[0x66] = Key::JIS_EISU;
+ keysym_map[0x67] = Key::F11;
+ keysym_map[0x68] = Key::JIS_KANA;
+ keysym_map[0x69] = Key::F13;
+ keysym_map[0x6a] = Key::F16;
+ keysym_map[0x6b] = Key::F14;
+ keysym_map[0x6d] = Key::F10;
+ keysym_map[0x6e] = Key::MENU;
+ keysym_map[0x6f] = Key::F12;
+ keysym_map[0x71] = Key::F15;
+ keysym_map[0x72] = Key::INSERT;
+ keysym_map[0x73] = Key::HOME;
+ keysym_map[0x74] = Key::PAGEUP;
+ keysym_map[0x75] = Key::KEY_DELETE;
+ keysym_map[0x76] = Key::F4;
+ keysym_map[0x77] = Key::END;
+ keysym_map[0x78] = Key::F2;
+ keysym_map[0x79] = Key::PAGEDOWN;
+ keysym_map[0x7a] = Key::F1;
+ keysym_map[0x7b] = Key::LEFT;
+ keysym_map[0x7c] = Key::RIGHT;
+ keysym_map[0x7d] = Key::DOWN;
+ keysym_map[0x7e] = Key::UP;
+
+ for (const KeyValue<unsigned int, Key> &E : keysym_map) {
+ keysym_map_inv[E.value] = E.key;
}
- return false;
+
+ keycode_map[Key::ESCAPE] = 0x001B;
+ keycode_map[Key::TAB] = 0x0009;
+ keycode_map[Key::BACKTAB] = 0x007F;
+ keycode_map[Key::BACKSPACE] = 0x0008;
+ keycode_map[Key::ENTER] = 0x000D;
+ keycode_map[Key::INSERT] = NSInsertFunctionKey;
+ keycode_map[Key::KEY_DELETE] = 0x007F;
+ keycode_map[Key::PAUSE] = NSPauseFunctionKey;
+ keycode_map[Key::PRINT] = NSPrintScreenFunctionKey;
+ keycode_map[Key::SYSREQ] = NSSysReqFunctionKey;
+ keycode_map[Key::CLEAR] = NSClearLineFunctionKey;
+ keycode_map[Key::HOME] = 0x2196;
+ keycode_map[Key::END] = 0x2198;
+ keycode_map[Key::LEFT] = 0x001C;
+ keycode_map[Key::UP] = 0x001E;
+ keycode_map[Key::RIGHT] = 0x001D;
+ keycode_map[Key::DOWN] = 0x001F;
+ keycode_map[Key::PAGEUP] = 0x21DE;
+ keycode_map[Key::PAGEDOWN] = 0x21DF;
+ keycode_map[Key::NUMLOCK] = NSClearLineFunctionKey;
+ keycode_map[Key::SCROLLLOCK] = NSScrollLockFunctionKey;
+ keycode_map[Key::F1] = NSF1FunctionKey;
+ keycode_map[Key::F2] = NSF2FunctionKey;
+ keycode_map[Key::F3] = NSF3FunctionKey;
+ keycode_map[Key::F4] = NSF4FunctionKey;
+ keycode_map[Key::F5] = NSF5FunctionKey;
+ keycode_map[Key::F6] = NSF6FunctionKey;
+ keycode_map[Key::F7] = NSF7FunctionKey;
+ keycode_map[Key::F8] = NSF8FunctionKey;
+ keycode_map[Key::F9] = NSF9FunctionKey;
+ keycode_map[Key::F10] = NSF10FunctionKey;
+ keycode_map[Key::F11] = NSF11FunctionKey;
+ keycode_map[Key::F12] = NSF12FunctionKey;
+ keycode_map[Key::F13] = NSF13FunctionKey;
+ keycode_map[Key::F14] = NSF14FunctionKey;
+ keycode_map[Key::F15] = NSF15FunctionKey;
+ keycode_map[Key::F16] = NSF16FunctionKey;
+ keycode_map[Key::F17] = NSF17FunctionKey;
+ keycode_map[Key::F18] = NSF18FunctionKey;
+ keycode_map[Key::F19] = NSF19FunctionKey;
+ keycode_map[Key::F20] = NSF20FunctionKey;
+ keycode_map[Key::F21] = NSF21FunctionKey;
+ keycode_map[Key::F22] = NSF22FunctionKey;
+ keycode_map[Key::F23] = NSF23FunctionKey;
+ keycode_map[Key::F24] = NSF24FunctionKey;
+ keycode_map[Key::F25] = NSF25FunctionKey;
+ keycode_map[Key::F26] = NSF26FunctionKey;
+ keycode_map[Key::F27] = NSF27FunctionKey;
+ keycode_map[Key::F28] = NSF28FunctionKey;
+ keycode_map[Key::F29] = NSF29FunctionKey;
+ keycode_map[Key::F30] = NSF30FunctionKey;
+ keycode_map[Key::F31] = NSF31FunctionKey;
+ keycode_map[Key::F32] = NSF32FunctionKey;
+ keycode_map[Key::F33] = NSF33FunctionKey;
+ keycode_map[Key::F34] = NSF34FunctionKey;
+ keycode_map[Key::F35] = NSF35FunctionKey;
+ keycode_map[Key::MENU] = NSMenuFunctionKey;
+ keycode_map[Key::HELP] = NSHelpFunctionKey;
+ keycode_map[Key::STOP] = NSStopFunctionKey;
+ keycode_map[Key::LAUNCH0] = NSUserFunctionKey;
+ keycode_map[Key::SPACE] = 0x0020;
+ keycode_map[Key::EXCLAM] = '!';
+ keycode_map[Key::QUOTEDBL] = '\"';
+ keycode_map[Key::NUMBERSIGN] = '#';
+ keycode_map[Key::DOLLAR] = '$';
+ keycode_map[Key::PERCENT] = '\%';
+ keycode_map[Key::AMPERSAND] = '&';
+ keycode_map[Key::APOSTROPHE] = '\'';
+ keycode_map[Key::PARENLEFT] = '(';
+ keycode_map[Key::PARENRIGHT] = ')';
+ keycode_map[Key::ASTERISK] = '*';
+ keycode_map[Key::PLUS] = '+';
+ keycode_map[Key::COMMA] = ',';
+ keycode_map[Key::MINUS] = '-';
+ keycode_map[Key::PERIOD] = '.';
+ keycode_map[Key::SLASH] = '/';
+ keycode_map[Key::KEY_0] = '0';
+ keycode_map[Key::KEY_1] = '1';
+ keycode_map[Key::KEY_2] = '2';
+ keycode_map[Key::KEY_3] = '3';
+ keycode_map[Key::KEY_4] = '4';
+ keycode_map[Key::KEY_5] = '5';
+ keycode_map[Key::KEY_6] = '6';
+ keycode_map[Key::KEY_7] = '7';
+ keycode_map[Key::KEY_8] = '8';
+ keycode_map[Key::KEY_9] = '9';
+ keycode_map[Key::COLON] = ':';
+ keycode_map[Key::SEMICOLON] = ';';
+ keycode_map[Key::LESS] = '<';
+ keycode_map[Key::EQUAL] = '=';
+ keycode_map[Key::GREATER] = '>';
+ keycode_map[Key::QUESTION] = '?';
+ keycode_map[Key::AT] = '@';
+ keycode_map[Key::A] = 'a';
+ keycode_map[Key::B] = 'b';
+ keycode_map[Key::C] = 'c';
+ keycode_map[Key::D] = 'd';
+ keycode_map[Key::E] = 'e';
+ keycode_map[Key::F] = 'f';
+ keycode_map[Key::G] = 'g';
+ keycode_map[Key::H] = 'h';
+ keycode_map[Key::I] = 'i';
+ keycode_map[Key::J] = 'j';
+ keycode_map[Key::K] = 'k';
+ keycode_map[Key::L] = 'l';
+ keycode_map[Key::M] = 'm';
+ keycode_map[Key::N] = 'n';
+ keycode_map[Key::O] = 'o';
+ keycode_map[Key::P] = 'p';
+ keycode_map[Key::Q] = 'q';
+ keycode_map[Key::R] = 'r';
+ keycode_map[Key::S] = 's';
+ keycode_map[Key::T] = 't';
+ keycode_map[Key::U] = 'u';
+ keycode_map[Key::V] = 'v';
+ keycode_map[Key::W] = 'w';
+ keycode_map[Key::X] = 'x';
+ keycode_map[Key::Y] = 'y';
+ keycode_map[Key::Z] = 'z';
+ keycode_map[Key::BRACKETLEFT] = '[';
+ keycode_map[Key::BACKSLASH] = '\\';
+ keycode_map[Key::BRACKETRIGHT] = ']';
+ keycode_map[Key::ASCIICIRCUM] = '^';
+ keycode_map[Key::UNDERSCORE] = '_';
+ keycode_map[Key::QUOTELEFT] = '`';
+ keycode_map[Key::BRACELEFT] = '{';
+ keycode_map[Key::BAR] = '|';
+ keycode_map[Key::BRACERIGHT] = '}';
+ keycode_map[Key::ASCIITILDE] = '~';
}
-// Keyboard symbol translation table.
-static const Key _macos_to_godot_table[128] = {
- /* 00 */ Key::A,
- /* 01 */ Key::S,
- /* 02 */ Key::D,
- /* 03 */ Key::F,
- /* 04 */ Key::H,
- /* 05 */ Key::G,
- /* 06 */ Key::Z,
- /* 07 */ Key::X,
- /* 08 */ Key::C,
- /* 09 */ Key::V,
- /* 0a */ Key::SECTION, /* ISO Section */
- /* 0b */ Key::B,
- /* 0c */ Key::Q,
- /* 0d */ Key::W,
- /* 0e */ Key::E,
- /* 0f */ Key::R,
- /* 10 */ Key::Y,
- /* 11 */ Key::T,
- /* 12 */ Key::KEY_1,
- /* 13 */ Key::KEY_2,
- /* 14 */ Key::KEY_3,
- /* 15 */ Key::KEY_4,
- /* 16 */ Key::KEY_6,
- /* 17 */ Key::KEY_5,
- /* 18 */ Key::EQUAL,
- /* 19 */ Key::KEY_9,
- /* 1a */ Key::KEY_7,
- /* 1b */ Key::MINUS,
- /* 1c */ Key::KEY_8,
- /* 1d */ Key::KEY_0,
- /* 1e */ Key::BRACERIGHT,
- /* 1f */ Key::O,
- /* 20 */ Key::U,
- /* 21 */ Key::BRACELEFT,
- /* 22 */ Key::I,
- /* 23 */ Key::P,
- /* 24 */ Key::ENTER,
- /* 25 */ Key::L,
- /* 26 */ Key::J,
- /* 27 */ Key::APOSTROPHE,
- /* 28 */ Key::K,
- /* 29 */ Key::SEMICOLON,
- /* 2a */ Key::BACKSLASH,
- /* 2b */ Key::COMMA,
- /* 2c */ Key::SLASH,
- /* 2d */ Key::N,
- /* 2e */ Key::M,
- /* 2f */ Key::PERIOD,
- /* 30 */ Key::TAB,
- /* 31 */ Key::SPACE,
- /* 32 */ Key::QUOTELEFT,
- /* 33 */ Key::BACKSPACE,
- /* 34 */ Key::UNKNOWN,
- /* 35 */ Key::ESCAPE,
- /* 36 */ Key::META,
- /* 37 */ Key::META,
- /* 38 */ Key::SHIFT,
- /* 39 */ Key::CAPSLOCK,
- /* 3a */ Key::ALT,
- /* 3b */ Key::CTRL,
- /* 3c */ Key::SHIFT,
- /* 3d */ Key::ALT,
- /* 3e */ Key::CTRL,
- /* 3f */ Key::UNKNOWN, /* Function */
- /* 40 */ Key::F17,
- /* 41 */ Key::KP_PERIOD,
- /* 42 */ Key::UNKNOWN,
- /* 43 */ Key::KP_MULTIPLY,
- /* 44 */ Key::UNKNOWN,
- /* 45 */ Key::KP_ADD,
- /* 46 */ Key::UNKNOWN,
- /* 47 */ Key::NUMLOCK, /* Really KeypadClear... */
- /* 48 */ Key::VOLUMEUP, /* VolumeUp */
- /* 49 */ Key::VOLUMEDOWN, /* VolumeDown */
- /* 4a */ Key::VOLUMEMUTE, /* Mute */
- /* 4b */ Key::KP_DIVIDE,
- /* 4c */ Key::KP_ENTER,
- /* 4d */ Key::UNKNOWN,
- /* 4e */ Key::KP_SUBTRACT,
- /* 4f */ Key::F18,
- /* 50 */ Key::F19,
- /* 51 */ Key::EQUAL, /* KeypadEqual */
- /* 52 */ Key::KP_0,
- /* 53 */ Key::KP_1,
- /* 54 */ Key::KP_2,
- /* 55 */ Key::KP_3,
- /* 56 */ Key::KP_4,
- /* 57 */ Key::KP_5,
- /* 58 */ Key::KP_6,
- /* 59 */ Key::KP_7,
- /* 5a */ Key::F20,
- /* 5b */ Key::KP_8,
- /* 5c */ Key::KP_9,
- /* 5d */ Key::YEN, /* JIS Yen */
- /* 5e */ Key::UNDERSCORE, /* JIS Underscore */
- /* 5f */ Key::COMMA, /* JIS KeypadComma */
- /* 60 */ Key::F5,
- /* 61 */ Key::F6,
- /* 62 */ Key::F7,
- /* 63 */ Key::F3,
- /* 64 */ Key::F8,
- /* 65 */ Key::F9,
- /* 66 */ Key::UNKNOWN, /* JIS Eisu */
- /* 67 */ Key::F11,
- /* 68 */ Key::UNKNOWN, /* JIS Kana */
- /* 69 */ Key::F13,
- /* 6a */ Key::F16,
- /* 6b */ Key::F14,
- /* 6c */ Key::UNKNOWN,
- /* 6d */ Key::F10,
- /* 6e */ Key::MENU,
- /* 6f */ Key::F12,
- /* 70 */ Key::UNKNOWN,
- /* 71 */ Key::F15,
- /* 72 */ Key::INSERT, /* Really Help... */
- /* 73 */ Key::HOME,
- /* 74 */ Key::PAGEUP,
- /* 75 */ Key::KEY_DELETE,
- /* 76 */ Key::F4,
- /* 77 */ Key::END,
- /* 78 */ Key::F2,
- /* 79 */ Key::PAGEDOWN,
- /* 7a */ Key::F1,
- /* 7b */ Key::LEFT,
- /* 7c */ Key::RIGHT,
- /* 7d */ Key::DOWN,
- /* 7e */ Key::UP,
- /* 7f */ Key::UNKNOWN,
-};
+bool KeyMappingMacOS::is_numpad_key(unsigned int p_key) {
+ return numpad_keys.has(p_key);
+}
// Translates a OS X keycode to a Godot keycode.
-Key KeyMappingMacOS::translate_key(unsigned int key) {
- if (key >= 128) {
- return Key::UNKNOWN;
+Key KeyMappingMacOS::translate_key(unsigned int p_key) {
+ const Key *key = keysym_map.getptr(p_key);
+ if (key) {
+ return *key;
}
-
- return _macos_to_godot_table[key];
+ return Key::NONE;
}
// Translates a Godot keycode back to a macOS keycode.
-unsigned int KeyMappingMacOS::unmap_key(Key key) {
- for (int i = 0; i <= 126; i++) {
- if (_macos_to_godot_table[i] == key) {
- return i;
- }
+unsigned int KeyMappingMacOS::unmap_key(Key p_key) {
+ const unsigned int *key = keysym_map_inv.getptr(p_key);
+ if (key) {
+ return *key;
}
return 127;
}
-struct _KeyCodeMap {
- UniChar kchar;
- Key kcode;
-};
-
-static const _KeyCodeMap _keycodes[55] = {
- { '`', Key::QUOTELEFT },
- { '~', Key::ASCIITILDE },
- { '0', Key::KEY_0 },
- { '1', Key::KEY_1 },
- { '2', Key::KEY_2 },
- { '3', Key::KEY_3 },
- { '4', Key::KEY_4 },
- { '5', Key::KEY_5 },
- { '6', Key::KEY_6 },
- { '7', Key::KEY_7 },
- { '8', Key::KEY_8 },
- { '9', Key::KEY_9 },
- { '-', Key::MINUS },
- { '_', Key::UNDERSCORE },
- { '=', Key::EQUAL },
- { '+', Key::PLUS },
- { 'q', Key::Q },
- { 'w', Key::W },
- { 'e', Key::E },
- { 'r', Key::R },
- { 't', Key::T },
- { 'y', Key::Y },
- { 'u', Key::U },
- { 'i', Key::I },
- { 'o', Key::O },
- { 'p', Key::P },
- { '[', Key::BRACELEFT },
- { ']', Key::BRACERIGHT },
- { '{', Key::BRACELEFT },
- { '}', Key::BRACERIGHT },
- { 'a', Key::A },
- { 's', Key::S },
- { 'd', Key::D },
- { 'f', Key::F },
- { 'g', Key::G },
- { 'h', Key::H },
- { 'j', Key::J },
- { 'k', Key::K },
- { 'l', Key::L },
- { ';', Key::SEMICOLON },
- { ':', Key::COLON },
- { '\'', Key::APOSTROPHE },
- { '\"', Key::QUOTEDBL },
- { '\\', Key::BACKSLASH },
- { '#', Key::NUMBERSIGN },
- { 'z', Key::Z },
- { 'x', Key::X },
- { 'c', Key::C },
- { 'v', Key::V },
- { 'b', Key::B },
- { 'n', Key::N },
- { 'm', Key::M },
- { ',', Key::COMMA },
- { '.', Key::PERIOD },
- { '/', Key::SLASH }
-};
-
// Remap key according to current keyboard layout.
-Key KeyMappingMacOS::remap_key(unsigned int key, unsigned int state) {
- if (is_numpad_key(key)) {
- return translate_key(key);
+Key KeyMappingMacOS::remap_key(unsigned int p_key, unsigned int p_state, bool p_unicode) {
+ if (is_numpad_key(p_key)) {
+ return translate_key(p_key);
}
TISInputSourceRef current_keyboard = TISCopyCurrentKeyboardInputSource();
if (!current_keyboard) {
- return translate_key(key);
+ return translate_key(p_key);
}
CFDataRef layout_data = (CFDataRef)TISGetInputSourceProperty(current_keyboard, kTISPropertyUnicodeKeyLayoutData);
if (!layout_data) {
- return translate_key(key);
+ return translate_key(p_key);
}
const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout *)CFDataGetBytePtr(layout_data);
+ String keysym;
UInt32 keys_down = 0;
- UniChar chars[4];
- UniCharCount real_length;
+ UniChar chars[256] = {};
+ UniCharCount real_length = 0;
OSStatus err = UCKeyTranslate(keyboard_layout,
- key,
+ p_key,
kUCKeyActionDisplay,
- (state >> 8) & 0xFF,
+ (p_unicode) ? 0 : (p_state >> 8) & 0xFF,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
&keys_down,
@@ -312,165 +380,26 @@ Key KeyMappingMacOS::remap_key(unsigned int key, unsigned int state) {
chars);
if (err != noErr) {
- return translate_key(key);
+ return translate_key(p_key);
}
- for (unsigned int i = 0; i < 55; i++) {
- if (_keycodes[i].kchar == chars[0]) {
- return _keycodes[i].kcode;
- }
+ keysym = String::utf16((char16_t *)chars, real_length);
+ if (keysym.is_empty()) {
+ return translate_key(p_key);
}
- return translate_key(key);
-}
-
-struct _KeyCodeText {
- Key code;
- char32_t text;
-};
-static const _KeyCodeText _native_keycodes[] = {
- /* clang-format off */
- {Key::ESCAPE ,0x001B},
- {Key::TAB ,0x0009},
- {Key::BACKTAB ,0x007F},
- {Key::BACKSPACE ,0x0008},
- {Key::ENTER ,0x000D},
- {Key::INSERT ,NSInsertFunctionKey},
- {Key::KEY_DELETE ,0x007F},
- {Key::PAUSE ,NSPauseFunctionKey},
- {Key::PRINT ,NSPrintScreenFunctionKey},
- {Key::SYSREQ ,NSSysReqFunctionKey},
- {Key::CLEAR ,NSClearLineFunctionKey},
- {Key::HOME ,0x2196},
- {Key::END ,0x2198},
- {Key::LEFT ,0x001C},
- {Key::UP ,0x001E},
- {Key::RIGHT ,0x001D},
- {Key::DOWN ,0x001F},
- {Key::PAGEUP ,0x21DE},
- {Key::PAGEDOWN ,0x21DF},
- {Key::NUMLOCK ,NSClearLineFunctionKey},
- {Key::SCROLLLOCK ,NSScrollLockFunctionKey},
- {Key::F1 ,NSF1FunctionKey},
- {Key::F2 ,NSF2FunctionKey},
- {Key::F3 ,NSF3FunctionKey},
- {Key::F4 ,NSF4FunctionKey},
- {Key::F5 ,NSF5FunctionKey},
- {Key::F6 ,NSF6FunctionKey},
- {Key::F7 ,NSF7FunctionKey},
- {Key::F8 ,NSF8FunctionKey},
- {Key::F9 ,NSF9FunctionKey},
- {Key::F10 ,NSF10FunctionKey},
- {Key::F11 ,NSF11FunctionKey},
- {Key::F12 ,NSF12FunctionKey},
- {Key::F13 ,NSF13FunctionKey},
- {Key::F14 ,NSF14FunctionKey},
- {Key::F15 ,NSF15FunctionKey},
- {Key::F16 ,NSF16FunctionKey},
- {Key::F17 ,NSF17FunctionKey},
- {Key::F18 ,NSF18FunctionKey},
- {Key::F19 ,NSF19FunctionKey},
- {Key::F20 ,NSF20FunctionKey},
- {Key::F21 ,NSF21FunctionKey},
- {Key::F22 ,NSF22FunctionKey},
- {Key::F23 ,NSF23FunctionKey},
- {Key::F24 ,NSF24FunctionKey},
- {Key::F25 ,NSF25FunctionKey},
- {Key::F26 ,NSF26FunctionKey},
- {Key::F27 ,NSF27FunctionKey},
- {Key::F28 ,NSF28FunctionKey},
- {Key::F29 ,NSF29FunctionKey},
- {Key::F30 ,NSF30FunctionKey},
- {Key::F31 ,NSF31FunctionKey},
- {Key::F32 ,NSF32FunctionKey},
- {Key::F33 ,NSF33FunctionKey},
- {Key::F34 ,NSF34FunctionKey},
- {Key::F35 ,NSF35FunctionKey},
- {Key::MENU ,NSMenuFunctionKey},
- {Key::HELP ,NSHelpFunctionKey},
- {Key::STOP ,NSStopFunctionKey},
- {Key::LAUNCH0 ,NSUserFunctionKey},
- {Key::SPACE ,0x0020},
- {Key::EXCLAM ,'!'},
- {Key::QUOTEDBL ,'\"'},
- {Key::NUMBERSIGN ,'#'},
- {Key::DOLLAR ,'$'},
- {Key::PERCENT ,'\%'},
- {Key::AMPERSAND ,'&'},
- {Key::APOSTROPHE ,'\''},
- {Key::PARENLEFT ,'('},
- {Key::PARENRIGHT ,')'},
- {Key::ASTERISK ,'*'},
- {Key::PLUS ,'+'},
- {Key::COMMA ,','},
- {Key::MINUS ,'-'},
- {Key::PERIOD ,'.'},
- {Key::SLASH ,'/'},
- {Key::KEY_0 ,'0'},
- {Key::KEY_1 ,'1'},
- {Key::KEY_2 ,'2'},
- {Key::KEY_3 ,'3'},
- {Key::KEY_4 ,'4'},
- {Key::KEY_5 ,'5'},
- {Key::KEY_6 ,'6'},
- {Key::KEY_7 ,'7'},
- {Key::KEY_8 ,'8'},
- {Key::KEY_9 ,'9'},
- {Key::COLON ,':'},
- {Key::SEMICOLON ,';'},
- {Key::LESS ,'<'},
- {Key::EQUAL ,'='},
- {Key::GREATER ,'>'},
- {Key::QUESTION ,'?'},
- {Key::AT ,'@'},
- {Key::A ,'a'},
- {Key::B ,'b'},
- {Key::C ,'c'},
- {Key::D ,'d'},
- {Key::E ,'e'},
- {Key::F ,'f'},
- {Key::G ,'g'},
- {Key::H ,'h'},
- {Key::I ,'i'},
- {Key::J ,'j'},
- {Key::K ,'k'},
- {Key::L ,'l'},
- {Key::M ,'m'},
- {Key::N ,'n'},
- {Key::O ,'o'},
- {Key::P ,'p'},
- {Key::Q ,'q'},
- {Key::R ,'r'},
- {Key::S ,'s'},
- {Key::T ,'t'},
- {Key::U ,'u'},
- {Key::V ,'v'},
- {Key::W ,'w'},
- {Key::X ,'x'},
- {Key::Y ,'y'},
- {Key::Z ,'z'},
- {Key::BRACKETLEFT ,'['},
- {Key::BACKSLASH ,'\\'},
- {Key::BRACKETRIGHT ,']'},
- {Key::ASCIICIRCUM ,'^'},
- {Key::UNDERSCORE ,'_'},
- {Key::QUOTELEFT ,'`'},
- {Key::BRACELEFT ,'{'},
- {Key::BAR ,'|'},
- {Key::BRACERIGHT ,'}'},
- {Key::ASCIITILDE ,'~'},
- {Key::NONE ,0x0000}
- /* clang-format on */
-};
+ char32_t c = keysym[0];
+ if (p_unicode) {
+ return fix_key_label(c, translate_key(p_key));
+ } else {
+ return fix_keycode(c, translate_key(p_key));
+ }
+}
String KeyMappingMacOS::keycode_get_native_string(Key p_keycode) {
- const _KeyCodeText *kct = &_native_keycodes[0];
-
- while (kct->text) {
- if (kct->code == p_keycode) {
- return String::chr(kct->text);
- }
- kct++;
+ const char32_t *key = keycode_map.getptr(p_keycode);
+ if (key) {
+ return String::chr(*key);
}
return String();
}
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index fdb9d107a7..d71fd60543 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -121,18 +121,25 @@ void DisplayServerWeb::key_callback(int p_pressed, int p_repeat, int p_modifiers
// Resume audio context after input in case autoplay was denied.
OS_Web::get_singleton()->resume_audio();
+ char32_t c = 0x00;
+ String unicode = String::utf8(key_event.key);
+ if (unicode.length() == 1) {
+ c = unicode[0];
+ }
+
+ Key keycode = dom_code2godot_scancode(key_event.code, key_event.key, false);
+ Key scancode = dom_code2godot_scancode(key_event.code, key_event.key, true);
+
Ref<InputEventKey> ev;
ev.instantiate();
ev->set_echo(p_repeat);
- ev->set_keycode(dom_code2godot_scancode(key_event.code, key_event.key, false));
- ev->set_physical_keycode(dom_code2godot_scancode(key_event.code, key_event.key, true));
+ ev->set_keycode(fix_keycode(c, keycode));
+ ev->set_physical_keycode(scancode);
+ ev->set_key_label(fix_key_label(c, keycode));
+ ev->set_unicode(fix_unicode(c));
ev->set_pressed(p_pressed);
dom2godot_mod(ev, p_modifiers);
- String unicode = String::utf8(key_event.key);
- if (unicode.length() == 1) {
- ev->set_unicode(unicode[0]);
- }
Input::get_singleton()->parse_input_event(ev);
// Make sure to flush all events so we can call restricted APIs inside the event.
diff --git a/platform/web/dom_keys.inc b/platform/web/dom_keys.inc
index 5f8d921bfb..e63bd7c69f 100644
--- a/platform/web/dom_keys.inc
+++ b/platform/web/dom_keys.inc
@@ -32,9 +32,9 @@
// See https://w3c.github.io/uievents-code/#code-value-tables
Key dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], bool p_physical) {
-#define DOM2GODOT(p_str, p_godot_code) \
- if (memcmp((const void *)p_str, (void *)p_code, strlen(p_str) + 1) == 0) { \
- return Key::p_godot_code; \
+#define DOM2GODOT(p_str, p_godot_code) \
+ if (memcmp((const void *)p_str, (void *)(p_physical ? p_key : p_code), strlen(p_str) + 1) == 0) { \
+ return Key::p_godot_code; \
}
// Numpad section.
@@ -70,35 +70,6 @@ Key dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], b
DOM2GODOT("NumpadStar", KP_MULTIPLY); // or ASTERISK ?
DOM2GODOT("NumpadSubtract", KP_SUBTRACT);
- // Printable ASCII.
- if (!p_physical) {
- uint8_t b0 = (uint8_t)p_key[0];
- uint8_t b1 = (uint8_t)p_key[1];
- uint8_t b2 = (uint8_t)p_key[2];
- if (b1 == 0 && b0 > 0x1F && b0 < 0x7F) { // ASCII.
- if (b0 > 0x60 && b0 < 0x7B) { // Lowercase ASCII.
- b0 -= 32;
- }
- return (Key)b0;
- }
-
-#define _U_2BYTES_MASK 0xE0
-#define _U_2BYTES 0xC0
- // Latin-1 codes.
- if (b2 == 0 && (b0 & _U_2BYTES_MASK) == _U_2BYTES) { // 2-bytes utf8, only known latin.
- uint32_t key = ((b0 & ~_U_2BYTES_MASK) << 6) | (b1 & 0x3F);
- if (key >= 0xA0 && key <= 0xDF) {
- return (Key)key;
- }
- if (key >= 0xE0 && key <= 0xFF) { // Lowercase known latin.
- key -= 0x20;
- return (Key)key;
- }
- }
-#undef _U_2BYTES_MASK
-#undef _U_2BYTES
- }
-
// Alphanumeric section.
DOM2GODOT("Backquote", QUOTELEFT);
DOM2GODOT("Backslash", BACKSLASH);
@@ -162,8 +133,8 @@ Key dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], b
DOM2GODOT("ControlLeft", CTRL);
DOM2GODOT("ControlRight", CTRL);
DOM2GODOT("Enter", ENTER);
- DOM2GODOT("MetaLeft", SUPER_L);
- DOM2GODOT("MetaRight", SUPER_R);
+ DOM2GODOT("MetaLeft", META);
+ DOM2GODOT("MetaRight", META);
DOM2GODOT("ShiftLeft", SHIFT);
DOM2GODOT("ShiftRight", SHIFT);
DOM2GODOT("Space", SPACE);
@@ -227,6 +198,21 @@ Key dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], b
DOM2GODOT("AudioVolumeMute", VOLUMEMUTE);
DOM2GODOT("AudioVolumeUp", VOLUMEUP);
//DOM2GODOT("WakeUp", UNKNOWN);
- return Key::UNKNOWN;
+
+ // Printable ASCII.
+ uint8_t b0 = (uint8_t)p_key[0];
+ uint8_t b1 = (uint8_t)p_key[1];
+ if (b0 >= 0x20 && b0 < 0x7F) { // ASCII.
+ if (b0 > 0x60 && b0 < 0x7B) { // Lowercase ASCII.
+ b0 -= 32;
+ }
+ return (Key)b0;
+ } else if (b0 == 0xC2 && b1 == 0xA5) {
+ return Key::YEN;
+ } else if (b0 == 0xC2 && b1 == 0xA7) {
+ return Key::SECTION;
+ }
+
+ return Key::NONE;
#undef DOM2GODOT
}
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 9a732c489d..521bf85b27 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1610,6 +1610,58 @@ bool DisplayServerWindows::can_any_window_draw() const {
return false;
}
+Vector2i DisplayServerWindows::ime_get_selection() const {
+ _THREAD_SAFE_METHOD_
+
+ DisplayServer::WindowID window_id = _get_focused_window_or_popup();
+ const WindowData &wd = windows[window_id];
+ if (!wd.ime_active) {
+ return Vector2i();
+ }
+
+ int cursor = ImmGetCompositionStringW(wd.im_himc, GCS_CURSORPOS, nullptr, 0);
+
+ int32_t length = ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, nullptr, 0);
+ wchar_t *string = reinterpret_cast<wchar_t *>(memalloc(length));
+ ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, string, length);
+
+ int32_t utf32_cursor = 0;
+ for (int32_t i = 0; i < length / sizeof(wchar_t); i++) {
+ if ((string[i] & 0xfffffc00) == 0xd800) {
+ i++;
+ }
+ if (i < cursor) {
+ utf32_cursor++;
+ } else {
+ break;
+ }
+ }
+
+ memdelete(string);
+
+ return Vector2i(utf32_cursor, 0);
+}
+
+String DisplayServerWindows::ime_get_text() const {
+ _THREAD_SAFE_METHOD_
+
+ DisplayServer::WindowID window_id = _get_focused_window_or_popup();
+ const WindowData &wd = windows[window_id];
+ if (!wd.ime_active) {
+ return String();
+ }
+
+ String ret;
+ int32_t length = ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, nullptr, 0);
+ wchar_t *string = reinterpret_cast<wchar_t *>(memalloc(length));
+ ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, string, length);
+ ret.parse_utf16((char16_t *)string, length / sizeof(wchar_t));
+
+ memdelete(string);
+
+ return ret;
+}
+
void DisplayServerWindows::window_set_ime_active(const bool p_active, WindowID p_window) {
_THREAD_SAFE_METHOD_
@@ -1617,11 +1669,12 @@ void DisplayServerWindows::window_set_ime_active(const bool p_active, WindowID p
WindowData &wd = windows[p_window];
if (p_active) {
+ wd.ime_active = true;
ImmAssociateContext(wd.hWnd, wd.im_himc);
-
window_set_ime_position(wd.im_position, p_window);
} else {
ImmAssociateContext(wd.hWnd, (HIMC)0);
+ wd.ime_active = false;
}
}
@@ -1639,7 +1692,7 @@ void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowI
}
COMPOSITIONFORM cps;
- cps.dwStyle = CFS_FORCE_POSITION;
+ cps.dwStyle = CFS_POINT;
cps.ptCurrentPos.x = wd.im_position.x;
cps.ptCurrentPos.y = wd.im_position.y;
ImmSetCompositionWindow(himc, &cps);
@@ -3353,10 +3406,18 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
windows[window_id].focus_timer_id = 0U;
}
} break;
- case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYUP:
+ if (windows[window_id].ime_suppress_next_keyup) {
+ windows[window_id].ime_suppress_next_keyup = false;
+ break;
+ }
+ [[fallthrough]];
+ case WM_SYSKEYDOWN:
case WM_KEYDOWN: {
+ if (windows[window_id].ime_in_progress) {
+ break;
+ }
if (wParam == VK_SHIFT) {
shift_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN);
}
@@ -3379,6 +3440,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
[[fallthrough]];
}
case WM_CHAR: {
+ if (windows[window_id].ime_in_progress) {
+ break;
+ }
ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
// Make sure we don't include modifiers for the modifier key itself.
@@ -3402,9 +3466,43 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
key_event_buffer[key_event_pos++] = ke;
} break;
+ case WM_IME_COMPOSITION: {
+ CANDIDATEFORM cf;
+ cf.dwIndex = 0;
+ cf.dwStyle = CFS_EXCLUDE;
+ cf.ptCurrentPos.x = windows[window_id].im_position.x;
+ cf.ptCurrentPos.y = windows[window_id].im_position.y;
+ cf.rcArea.left = windows[window_id].im_position.x;
+ cf.rcArea.right = windows[window_id].im_position.x;
+ cf.rcArea.top = windows[window_id].im_position.y;
+ cf.rcArea.bottom = windows[window_id].im_position.y;
+ ImmSetCandidateWindow(windows[window_id].im_himc, &cf);
+ if (windows[window_id].ime_active) {
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
+ }
+ } break;
case WM_INPUTLANGCHANGEREQUEST: {
// FIXME: Do something?
} break;
+ case WM_IME_STARTCOMPOSITION: {
+ if (windows[window_id].ime_active) {
+ windows[window_id].ime_in_progress = true;
+ if (key_event_pos > 0) {
+ key_event_pos--;
+ }
+ }
+ return 0;
+ } break;
+ case WM_IME_ENDCOMPOSITION: {
+ if (windows[window_id].ime_active) {
+ windows[window_id].ime_in_progress = false;
+ windows[window_id].ime_suppress_next_keyup = true;
+ }
+ return 0;
+ } break;
+ case WM_IME_NOTIFY: {
+ return 0;
+ } break;
case WM_TOUCH: {
BOOL bHandled = FALSE;
UINT cInputs = LOWORD(wParam);
@@ -3557,24 +3655,36 @@ void DisplayServerWindows::_process_key_events() {
Ref<InputEventKey> k;
k.instantiate();
+ Key keycode = KeyMappingWindows::get_keysym(MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK));
+ Key key_label = keycode;
+ Key physical_keycode = KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24));
+
+ static BYTE keyboard_state[256];
+ memset(keyboard_state, 0, 256);
+ wchar_t chars[256] = {};
+ UINT extended_code = MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX);
+ if (!(ke.lParam & (1 << 24)) && ToUnicodeEx(extended_code, (ke.lParam >> 16) & 0xFF, keyboard_state, chars, 255, 0, GetKeyboardLayout(0)) > 0) {
+ String keysym = String::utf16((char16_t *)chars, 255);
+ if (!keysym.is_empty()) {
+ key_label = fix_key_label(keysym[0], keycode);
+ }
+ }
+
k->set_window_id(ke.window_id);
k->set_shift_pressed(ke.shift);
k->set_alt_pressed(ke.alt);
k->set_ctrl_pressed(ke.control);
k->set_meta_pressed(ke.meta);
k->set_pressed(true);
- k->set_keycode((Key)KeyMappingWindows::get_keysym(MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK)));
- k->set_physical_keycode((Key)(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24))));
- k->set_unicode(unicode);
+ k->set_keycode(keycode);
+ k->set_physical_keycode(physical_keycode);
+ k->set_key_label(key_label);
+ k->set_unicode(fix_unicode(unicode));
if (k->get_unicode() && gr_mem) {
k->set_alt_pressed(false);
k->set_ctrl_pressed(false);
}
- if (k->get_unicode() < 32) {
- k->set_unicode(0);
- }
-
Input::get_singleton()->parse_input_event(k);
} else {
// Do nothing.
@@ -3593,14 +3703,28 @@ void DisplayServerWindows::_process_key_events() {
k->set_pressed(ke.uMsg == WM_KEYDOWN);
+ Key keycode = KeyMappingWindows::get_keysym(ke.wParam);
if ((ke.lParam & (1 << 24)) && (ke.wParam == VK_RETURN)) {
// Special case for Numpad Enter key.
- k->set_keycode(Key::KP_ENTER);
- } else {
- k->set_keycode((Key)KeyMappingWindows::get_keysym(ke.wParam));
+ keycode = Key::KP_ENTER;
+ }
+ Key key_label = keycode;
+ Key physical_keycode = KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24));
+
+ static BYTE keyboard_state[256];
+ memset(keyboard_state, 0, 256);
+ wchar_t chars[256] = {};
+ UINT extended_code = MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX);
+ if (!(ke.lParam & (1 << 24)) && ToUnicodeEx(extended_code, (ke.lParam >> 16) & 0xFF, keyboard_state, chars, 255, 0, GetKeyboardLayout(0)) > 0) {
+ String keysym = String::utf16((char16_t *)chars, 255);
+ if (!keysym.is_empty()) {
+ key_label = fix_key_label(keysym[0], keycode);
+ }
}
- k->set_physical_keycode((Key)(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24))));
+ k->set_keycode(keycode);
+ k->set_physical_keycode(physical_keycode);
+ k->set_key_label(key_label);
if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) {
char32_t unicode = key_event_buffer[i + 1].wParam;
@@ -3621,17 +3745,13 @@ void DisplayServerWindows::_process_key_events() {
} else {
prev_wck = 0;
}
- k->set_unicode(unicode);
+ k->set_unicode(fix_unicode(unicode));
}
if (k->get_unicode() && gr_mem) {
k->set_alt_pressed(false);
k->set_ctrl_pressed(false);
}
- if (k->get_unicode() < 32) {
- k->set_unicode(0);
- }
-
k->set_echo((ke.uMsg == WM_KEYDOWN && (ke.lParam & (1 << 30))));
Input::get_singleton()->parse_input_event(k);
@@ -3842,7 +3962,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
// IME.
wd.im_himc = ImmGetContext(wd.hWnd);
- ImmReleaseContext(wd.hWnd, wd.im_himc);
+ ImmAssociateContext(wd.hWnd, (HIMC)0);
wd.im_position = Vector2();
@@ -3936,6 +4056,8 @@ void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) {
}
DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
+ KeyMappingWindows::initialize();
+
drop_events = false;
key_event_pos = 0;
@@ -4043,7 +4165,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
wc.lpszClassName = L"Engine";
if (!RegisterClassExW(&wc)) {
- MessageBox(nullptr, "Failed To Register The Window Class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
+ MessageBoxW(nullptr, L"Failed To Register The Window Class.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
r_error = ERR_UNAVAILABLE;
return;
}
@@ -4122,7 +4244,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
// from making the system unresponsive.
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
DWORD index = 0;
- HANDLE handle = AvSetMmThreadCharacteristics("Games", &index);
+ HANDLE handle = AvSetMmThreadCharacteristicsW(L"Games", &index);
if (handle) {
AvSetMmThreadPriority(handle, AVRT_PRIORITY_CRITICAL);
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index ce4b94af59..0d2137d048 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -405,6 +405,9 @@ class DisplayServerWindows : public DisplayServer {
// IME
HIMC im_himc;
Vector2 im_position;
+ bool ime_active = false;
+ bool ime_in_progress = false;
+ bool ime_suppress_next_keyup = false;
bool layered_window = false;
@@ -592,6 +595,9 @@ public:
virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual Point2i ime_get_selection() const override;
+ virtual String ime_get_text() const override;
+
virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index 183958cf40..7ae26e6cf4 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -101,10 +101,12 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x28DE, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
+ static GUID IID_XSWirelessGamepad = { MAKELONG(0x045E, 0x0B13), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
if (memcmp(p_guid, &IID_ValveStreamingGamepad, sizeof(*p_guid)) == 0 ||
memcmp(p_guid, &IID_X360WiredGamepad, sizeof(*p_guid)) == 0 ||
- memcmp(p_guid, &IID_X360WirelessGamepad, sizeof(*p_guid)) == 0)
+ memcmp(p_guid, &IID_X360WirelessGamepad, sizeof(*p_guid)) == 0 ||
+ memcmp(p_guid, &IID_XSWirelessGamepad, sizeof(*p_guid)) == 0)
return true;
PRAWINPUTDEVICELIST dev_list = nullptr;
diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp
index 86471f188f..d43f74126d 100644
--- a/platform/windows/key_mapping_windows.cpp
+++ b/platform/windows/key_mapping_windows.cpp
@@ -30,490 +30,386 @@
#include "key_mapping_windows.h"
-#include <stdio.h>
+#include "core/templates/hash_map.h"
// This provides translation from Windows virtual key codes to Godot and back.
// See WinUser.h and the below for documentation:
// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
-struct _WinTranslatePair {
- Key keysym;
- unsigned int keycode;
+struct HashMapHasherKeys {
+ static _FORCE_INLINE_ uint32_t hash(const Key p_key) { return hash_fmix32(static_cast<uint32_t>(p_key)); }
+ static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
+ static _FORCE_INLINE_ uint32_t hash(const unsigned p_key) { return hash_fmix32(p_key); }
};
-static _WinTranslatePair _vk_to_keycode[] = {
+HashMap<unsigned int, Key, HashMapHasherKeys> vk_map;
+HashMap<unsigned int, Key, HashMapHasherKeys> scansym_map;
+HashMap<Key, unsigned int, HashMapHasherKeys> scansym_map_inv;
+HashMap<unsigned int, Key, HashMapHasherKeys> scansym_map_ext;
+
+void KeyMappingWindows::initialize() {
// VK_LBUTTON (0x01)
// VK_RBUTTON (0x02)
// VK_CANCEL (0x03)
// VK_MBUTTON (0x04)
// VK_XBUTTON1 (0x05)
- // VK_XBUTTON2 (0x06)
- // We have no mappings for the above, as we only map keyboard buttons here.
-
+ // VK_XBUTTON2 (0x06), We have no mappings for the above;as we only map keyboard buttons here.
// 0x07 is undefined.
-
- { Key::BACKSPACE, VK_BACK }, // (0x08)
- { Key::TAB, VK_TAB }, // (0x09)
-
+ vk_map[VK_BACK] = Key::BACKSPACE; // (0x08)
+ vk_map[VK_TAB] = Key::TAB; // (0x09)
// 0x0A-0B are reserved.
-
- { Key::CLEAR, VK_CLEAR }, // (0x0C)
- { Key::ENTER, VK_RETURN }, // (0x0D)
-
+ vk_map[VK_CLEAR] = Key::CLEAR; // (0x0C)
+ vk_map[VK_RETURN] = Key::ENTER; // (0x0D)
// 0x0E-0F are undefined.
-
- { Key::SHIFT, VK_SHIFT }, // (0x10)
- { Key::CTRL, VK_CONTROL }, // (0x11)
- { Key::ALT, VK_MENU }, // (0x12)
- { Key::PAUSE, VK_PAUSE }, // (0x13)
- { Key::CAPSLOCK, VK_CAPITAL }, // (0x14)
-
- // 0x15-1A are IME keys. We have no mapping.
-
- { Key::ESCAPE, VK_ESCAPE }, // (0x1B)
-
- // 0x1C-1F are IME keys. We have no mapping.
-
- { Key::SPACE, VK_SPACE }, // (0x20)
- { Key::PAGEUP, VK_PRIOR }, // (0x21)
- { Key::PAGEDOWN, VK_NEXT }, // (0x22)
- { Key::END, VK_END }, // (0x23)
- { Key::HOME, VK_HOME }, // (0x24)
- { Key::LEFT, VK_LEFT }, // (0x25)
- { Key::UP, VK_UP }, // (0x26)
- { Key::RIGHT, VK_RIGHT }, // (0x27)
- { Key::DOWN, VK_DOWN }, // (0x28)
-
- // VK_SELECT (0x29)
- // Old select key, e.g. on Digital Equipment Corporation keyboards.
- // Old and uncommon, we have no mapping.
-
- { Key::PRINT, VK_PRINT }, // (0x2A)
- // Old IBM key, modern keyboards use VK_SNAPSHOT. Map to VK_SNAPSHOT.
-
- // VK_EXECUTE (0x2B)
- // Old and uncommon, we have no mapping.
-
- { Key::PRINT, VK_SNAPSHOT }, // (0x2C)
- { Key::INSERT, VK_INSERT }, // (0x2D)
- { Key::KEY_DELETE, VK_DELETE }, // (0x2E)
-
- { Key::HELP, VK_HELP }, // (0x2F)
- // Old and uncommon, but we have a mapping.
-
- { Key::KEY_0, (0x30) }, // 0 key.
- { Key::KEY_1, (0x31) }, // 1 key.
- { Key::KEY_2, (0x32) }, // 2 key.
- { Key::KEY_3, (0x33) }, // 3 key.
- { Key::KEY_4, (0x34) }, // 4 key.
- { Key::KEY_5, (0x35) }, // 5 key.
- { Key::KEY_6, (0x36) }, // 6 key.
- { Key::KEY_7, (0x37) }, // 7 key.
- { Key::KEY_8, (0x38) }, // 8 key.
- { Key::KEY_9, (0x39) }, // 9 key.
+ vk_map[VK_SHIFT] = Key::SHIFT; // (0x10)
+ vk_map[VK_CONTROL] = Key::CTRL; // (0x11)
+ vk_map[VK_MENU] = Key::ALT; // (0x12)
+ vk_map[VK_PAUSE] = Key::PAUSE; // (0x13)
+ vk_map[VK_CAPITAL] = Key::CAPSLOCK; // (0x14)
+ // 0x15-1A are IME keys.
+ vk_map[VK_ESCAPE] = Key::ESCAPE; // (0x1B)
+ // 0x1C-1F are IME keys.
+ vk_map[VK_SPACE] = Key::SPACE; // (0x20)
+ vk_map[VK_PRIOR] = Key::PAGEUP; // (0x21)
+ vk_map[VK_NEXT] = Key::PAGEDOWN; // (0x22)
+ vk_map[VK_END] = Key::END; // (0x23)
+ vk_map[VK_HOME] = Key::HOME; // (0x24)
+ vk_map[VK_LEFT] = Key::LEFT; // (0x25)
+ vk_map[VK_UP] = Key::UP; // (0x26)
+ vk_map[VK_RIGHT] = Key::RIGHT; // (0x27)
+ vk_map[VK_DOWN] = Key::DOWN; // (0x28)
+ // VK_SELECT (0x29), Old select key; e.g. on Digital Equipment Corporation keyboards.
+ vk_map[VK_PRINT] = Key::PRINT; // (0x2A), Old IBM key; modern keyboards use VK_SNAPSHOT.
+ // VK_EXECUTE (0x2B), Old and uncommon.
+ vk_map[VK_SNAPSHOT] = Key::PRINT; // (0x2C)
+ vk_map[VK_INSERT] = Key::INSERT; // (0x2D)
+ vk_map[VK_DELETE] = Key::KEY_DELETE; // (0x2E)
+ vk_map[VK_HELP] = Key::HELP; // (0x2F)
+ vk_map[0x30] = Key::KEY_0; // 0 key.
+ vk_map[0x31] = Key::KEY_1; // 1 key.
+ vk_map[0x32] = Key::KEY_2; // 2 key.
+ vk_map[0x33] = Key::KEY_3; // 3 key.
+ vk_map[0x34] = Key::KEY_4; // 4 key.
+ vk_map[0x35] = Key::KEY_5; // 5 key.
+ vk_map[0x36] = Key::KEY_6; // 6 key.
+ vk_map[0x37] = Key::KEY_7; // 7 key.
+ vk_map[0x38] = Key::KEY_8; // 8 key.
+ vk_map[0x39] = Key::KEY_9; // 9 key.
// 0x3A-40 are undefined.
- { Key::A, (0x41) }, // A key.
- { Key::B, (0x42) }, // B key.
- { Key::C, (0x43) }, // C key.
- { Key::D, (0x44) }, // D key.
- { Key::E, (0x45) }, // E key.
- { Key::F, (0x46) }, // F key.
- { Key::G, (0x47) }, // G key.
- { Key::H, (0x48) }, // H key.
- { Key::I, (0x49) }, // I key
- { Key::J, (0x4A) }, // J key.
- { Key::K, (0x4B) }, // K key.
- { Key::L, (0x4C) }, // L key.
- { Key::M, (0x4D) }, // M key.
- { Key::N, (0x4E) }, // N key.
- { Key::O, (0x4F) }, // O key.
- { Key::P, (0x50) }, // P key.
- { Key::Q, (0x51) }, // Q key.
- { Key::R, (0x52) }, // R key.
- { Key::S, (0x53) }, // S key.
- { Key::T, (0x54) }, // T key.
- { Key::U, (0x55) }, // U key.
- { Key::V, (0x56) }, // V key.
- { Key::W, (0x57) }, // W key.
- { Key::X, (0x58) }, // X key.
- { Key::Y, (0x59) }, // Y key.
- { Key::Z, (0x5A) }, // Z key.
-
- { (Key)KeyModifierMask::META, VK_LWIN }, // (0x5B)
- { (Key)KeyModifierMask::META, VK_RWIN }, // (0x5C)
- { Key::MENU, VK_APPS }, // (0x5D)
+ vk_map[0x41] = Key::A; // A key.
+ vk_map[0x42] = Key::B; // B key.
+ vk_map[0x43] = Key::C; // C key.
+ vk_map[0x44] = Key::D; // D key.
+ vk_map[0x45] = Key::E; // E key.
+ vk_map[0x46] = Key::F; // F key.
+ vk_map[0x47] = Key::G; // G key.
+ vk_map[0x48] = Key::H; // H key.
+ vk_map[0x49] = Key::I; // I key
+ vk_map[0x4A] = Key::J; // J key.
+ vk_map[0x4B] = Key::K; // K key.
+ vk_map[0x4C] = Key::L; // L key.
+ vk_map[0x4D] = Key::M; // M key.
+ vk_map[0x4E] = Key::N; // N key.
+ vk_map[0x4F] = Key::O; // O key.
+ vk_map[0x50] = Key::P; // P key.
+ vk_map[0x51] = Key::Q; // Q key.
+ vk_map[0x52] = Key::R; // R key.
+ vk_map[0x53] = Key::S; // S key.
+ vk_map[0x54] = Key::T; // T key.
+ vk_map[0x55] = Key::U; // U key.
+ vk_map[0x56] = Key::V; // V key.
+ vk_map[0x57] = Key::W; // W key.
+ vk_map[0x58] = Key::X; // X key.
+ vk_map[0x59] = Key::Y; // Y key.
+ vk_map[0x5A] = Key::Z; // Z key.
+ vk_map[VK_LWIN] = (Key)Key::META; // (0x5B)
+ vk_map[VK_RWIN] = (Key)Key::META; // (0x5C)
+ vk_map[VK_APPS] = Key::MENU; // (0x5D)
// 0x5E is reserved.
- { Key::STANDBY, VK_SLEEP }, // (0x5F)
- { Key::KP_0, VK_NUMPAD0 }, // (0x60)
- { Key::KP_1, VK_NUMPAD1 }, // (0x61)
- { Key::KP_2, VK_NUMPAD2 }, // (0x62)
- { Key::KP_3, VK_NUMPAD3 }, // (0x63)
- { Key::KP_4, VK_NUMPAD4 }, // (0x64)
- { Key::KP_5, VK_NUMPAD5 }, // (0x65)
- { Key::KP_6, VK_NUMPAD6 }, // (0x66)
- { Key::KP_7, VK_NUMPAD7 }, // (0x67)
- { Key::KP_8, VK_NUMPAD8 }, // (0x68)
- { Key::KP_9, VK_NUMPAD9 }, // (0x69)
- { Key::KP_MULTIPLY, VK_MULTIPLY }, // (0x6A)
- { Key::KP_ADD, VK_ADD }, // (0x6B)
- { Key::KP_PERIOD, VK_SEPARATOR }, // (0x6C)
- // VK_SEPERATOR (key 0x6C) is not found on US keyboards.
- // It is used on some Brazilian and Far East keyboards.
- // We don't have a direct mapping, map to period.
- { Key::KP_SUBTRACT, VK_SUBTRACT }, // (0x6D)
- { Key::KP_PERIOD, VK_DECIMAL }, // (0x6E)
- { Key::KP_DIVIDE, VK_DIVIDE }, // (0x6F)
- { Key::F1, VK_F1 }, // (0x70)
- { Key::F2, VK_F2 }, // (0x71)
- { Key::F3, VK_F3 }, // (0x72)
- { Key::F4, VK_F4 }, // (0x73)
- { Key::F5, VK_F5 }, // (0x74)
- { Key::F6, VK_F6 }, // (0x75)
- { Key::F7, VK_F7 }, // (0x76)
- { Key::F8, VK_F8 }, // (0x77)
- { Key::F9, VK_F9 }, // (0x78)
- { Key::F10, VK_F10 }, // (0x79)
- { Key::F11, VK_F11 }, // (0x7A)
- { Key::F12, VK_F12 }, // (0x7B)
- { Key::F13, VK_F13 }, // (0x7C)
- { Key::F14, VK_F14 }, // (0x7D)
- { Key::F15, VK_F15 }, // (0x7E)
- { Key::F16, VK_F16 }, // (0x7F)
- { Key::F17, VK_F17 }, // (0x80)
- { Key::F18, VK_F18 }, // (0x81)
- { Key::F19, VK_F19 }, // (0x82)
- { Key::F20, VK_F20 }, // (0x83)
- { Key::F21, VK_F21 }, // (0x84)
- { Key::F22, VK_F22 }, // (0x85)
- { Key::F23, VK_F23 }, // (0x86)
- { Key::F24, VK_F24 }, // (0x87)
+ vk_map[VK_SLEEP] = Key::STANDBY; // (0x5F)
+ vk_map[VK_NUMPAD0] = Key::KP_0; // (0x60)
+ vk_map[VK_NUMPAD1] = Key::KP_1; // (0x61)
+ vk_map[VK_NUMPAD2] = Key::KP_2; // (0x62)
+ vk_map[VK_NUMPAD3] = Key::KP_3; // (0x63)
+ vk_map[VK_NUMPAD4] = Key::KP_4; // (0x64)
+ vk_map[VK_NUMPAD5] = Key::KP_5; // (0x65)
+ vk_map[VK_NUMPAD6] = Key::KP_6; // (0x66)
+ vk_map[VK_NUMPAD7] = Key::KP_7; // (0x67)
+ vk_map[VK_NUMPAD8] = Key::KP_8; // (0x68)
+ vk_map[VK_NUMPAD9] = Key::KP_9; // (0x69)
+ vk_map[VK_MULTIPLY] = Key::KP_MULTIPLY; // (0x6A)
+ vk_map[VK_ADD] = Key::KP_ADD; // (0x6B)
+ vk_map[VK_SEPARATOR] = Key::KP_PERIOD; // (0x6C)
+ vk_map[VK_SUBTRACT] = Key::KP_SUBTRACT; // (0x6D)
+ vk_map[VK_DECIMAL] = Key::KP_PERIOD; // (0x6E)
+ vk_map[VK_DIVIDE] = Key::KP_DIVIDE; // (0x6F)
+ vk_map[VK_F1] = Key::F1; // (0x70)
+ vk_map[VK_F2] = Key::F2; // (0x71)
+ vk_map[VK_F3] = Key::F3; // (0x72)
+ vk_map[VK_F4] = Key::F4; // (0x73)
+ vk_map[VK_F5] = Key::F5; // (0x74)
+ vk_map[VK_F6] = Key::F6; // (0x75)
+ vk_map[VK_F7] = Key::F7; // (0x76)
+ vk_map[VK_F8] = Key::F8; // (0x77)
+ vk_map[VK_F9] = Key::F9; // (0x78)
+ vk_map[VK_F10] = Key::F10; // (0x79)
+ vk_map[VK_F11] = Key::F11; // (0x7A)
+ vk_map[VK_F12] = Key::F12; // (0x7B)
+ vk_map[VK_F13] = Key::F13; // (0x7C)
+ vk_map[VK_F14] = Key::F14; // (0x7D)
+ vk_map[VK_F15] = Key::F15; // (0x7E)
+ vk_map[VK_F16] = Key::F16; // (0x7F)
+ vk_map[VK_F17] = Key::F17; // (0x80)
+ vk_map[VK_F18] = Key::F18; // (0x81)
+ vk_map[VK_F19] = Key::F19; // (0x82)
+ vk_map[VK_F20] = Key::F20; // (0x83)
+ vk_map[VK_F21] = Key::F21; // (0x84)
+ vk_map[VK_F22] = Key::F22; // (0x85)
+ vk_map[VK_F23] = Key::F23; // (0x86)
+ vk_map[VK_F24] = Key::F24; // (0x87)
// 0x88-8F are reserved for UI navigation.
- { Key::NUMLOCK, VK_NUMLOCK }, // (0x90)
- { Key::SCROLLLOCK, VK_SCROLL }, // (0x91)
-
- { Key::EQUAL, VK_OEM_NEC_EQUAL }, // (0x92)
- // OEM NEC PC-9800 numpad '=' key.
-
- // 0x93-96 are OEM specific (e.g. used by Fujitsu/OASYS), we have no mappings.
+ vk_map[VK_NUMLOCK] = Key::NUMLOCK; // (0x90)
+ vk_map[VK_SCROLL] = Key::SCROLLLOCK; // (0x91)
+ vk_map[VK_OEM_NEC_EQUAL] = Key::EQUAL; // (0x92), OEM NEC PC-9800 numpad '=' key.
+ // 0x93-96 are OEM specific (e.g. used by Fujitsu/OASYS);
// 0x97-9F are unassigned.
-
- { Key::SHIFT, VK_LSHIFT }, // (0xA0)
- { Key::SHIFT, VK_RSHIFT }, // (0xA1)
- { Key::CTRL, VK_LCONTROL }, // (0xA2)
- { Key::CTRL, VK_RCONTROL }, // (0xA3)
- { Key::MENU, VK_LMENU }, // (0xA4)
- { Key::MENU, VK_RMENU }, // (0xA5)
-
- { Key::BACK, VK_BROWSER_BACK }, // (0xA6)
- { Key::FORWARD, VK_BROWSER_FORWARD }, // (0xA7)
- { Key::REFRESH, VK_BROWSER_REFRESH }, // (0xA8)
- { Key::STOP, VK_BROWSER_STOP }, // (0xA9)
- { Key::SEARCH, VK_BROWSER_SEARCH }, // (0xAA)
- { Key::FAVORITES, VK_BROWSER_FAVORITES }, // (0xAB)
- { Key::HOMEPAGE, VK_BROWSER_HOME }, // (0xAC)
- { Key::VOLUMEMUTE, VK_VOLUME_MUTE }, // (0xAD)
- { Key::VOLUMEDOWN, VK_VOLUME_DOWN }, // (0xAE)
- { Key::VOLUMEUP, VK_VOLUME_UP }, // (0xAF)
- { Key::MEDIANEXT, VK_MEDIA_NEXT_TRACK }, // (0xB0)
- { Key::MEDIAPREVIOUS, VK_MEDIA_PREV_TRACK }, // (0xB1)
- { Key::MEDIASTOP, VK_MEDIA_STOP }, // (0xB2)
-
- { Key::MEDIAPLAY, VK_MEDIA_PLAY_PAUSE }, // (0xB3)
- // Media button play/pause toggle.
- // Map to media play (there is no other 'play' mapping on Windows).
-
- { Key::LAUNCHMAIL, VK_LAUNCH_MAIL }, // (0xB4)
- { Key::LAUNCHMEDIA, VK_LAUNCH_MEDIA_SELECT }, // (0xB5)
- { Key::LAUNCH0, VK_LAUNCH_APP1 }, // (0xB6)
- { Key::LAUNCH1, VK_LAUNCH_APP2 }, // (0xB7)
-
+ vk_map[VK_LSHIFT] = Key::SHIFT; // (0xA0)
+ vk_map[VK_RSHIFT] = Key::SHIFT; // (0xA1)
+ vk_map[VK_LCONTROL] = Key::CTRL; // (0xA2)
+ vk_map[VK_RCONTROL] = Key::CTRL; // (0xA3)
+ vk_map[VK_LMENU] = Key::MENU; // (0xA4)
+ vk_map[VK_RMENU] = Key::MENU; // (0xA5)
+ vk_map[VK_BROWSER_BACK] = Key::BACK; // (0xA6)
+ vk_map[VK_BROWSER_FORWARD] = Key::FORWARD; // (0xA7)
+ vk_map[VK_BROWSER_REFRESH] = Key::REFRESH; // (0xA8)
+ vk_map[VK_BROWSER_STOP] = Key::STOP; // (0xA9)
+ vk_map[VK_BROWSER_SEARCH] = Key::SEARCH; // (0xAA)
+ vk_map[VK_BROWSER_FAVORITES] = Key::FAVORITES; // (0xAB)
+ vk_map[VK_BROWSER_HOME] = Key::HOMEPAGE; // (0xAC)
+ vk_map[VK_VOLUME_MUTE] = Key::VOLUMEMUTE; // (0xAD)
+ vk_map[VK_VOLUME_DOWN] = Key::VOLUMEDOWN; // (0xAE)
+ vk_map[VK_VOLUME_UP] = Key::VOLUMEUP; // (0xAF)
+ vk_map[VK_MEDIA_NEXT_TRACK] = Key::MEDIANEXT; // (0xB0)
+ vk_map[VK_MEDIA_PREV_TRACK] = Key::MEDIAPREVIOUS; // (0xB1)
+ vk_map[VK_MEDIA_STOP] = Key::MEDIASTOP; // (0xB2)
+ vk_map[VK_MEDIA_PLAY_PAUSE] = Key::MEDIAPLAY; // (0xB3), Media button play/pause toggle.
+ vk_map[VK_LAUNCH_MAIL] = Key::LAUNCHMAIL; // (0xB4)
+ vk_map[VK_LAUNCH_MEDIA_SELECT] = Key::LAUNCHMEDIA; // (0xB5)
+ vk_map[VK_LAUNCH_APP1] = Key::LAUNCH0; // (0xB6)
+ vk_map[VK_LAUNCH_APP2] = Key::LAUNCH1; // (0xB7)
// 0xB8-B9 are reserved.
-
- { Key::SEMICOLON, VK_OEM_1 }, // (0xBA)
- // Misc. character, can vary by keyboard/region.
- // Windows 2000/XP: For US standard keyboards, the ';:' key.
-
- { Key::EQUAL, VK_OEM_PLUS }, // (0xBB)
- // Windows 2000/XP: For any country/region, the '+' key.
- { Key::COMMA, VK_OEM_COMMA }, // (0xBC)
- // Windows 2000/XP: For any country/region, the ',' key.
- { Key::MINUS, VK_OEM_MINUS }, // (0xBD)
- // Windows 2000/XP: For any country/region, the '-' key.
- { Key::PERIOD, VK_OEM_PERIOD }, // (0xBE)
- // Windows 2000/XP: For any country/region, the '.' key.
-
- { Key::SLASH, VK_OEM_2 }, // (0xBF)
- // Windows 2000/XP: For US standard keyboards, the '/?' key.
-
- { Key::QUOTELEFT, VK_OEM_3 }, // (0xC0)
- // Windows 2000/XP: For US standard keyboards, the '`~' key.
-
+ vk_map[VK_OEM_1] = Key::SEMICOLON; // (0xBA), Misc. character;can vary by keyboard/region. For US standard keyboards;the ';:' key.
+ vk_map[VK_OEM_PLUS] = Key::EQUAL; // (0xBB)
+ vk_map[VK_OEM_COMMA] = Key::COMMA; // (0xBC)
+ vk_map[VK_OEM_MINUS] = Key::MINUS; // (0xBD)
+ vk_map[VK_OEM_PERIOD] = Key::PERIOD; // (0xBE)
+ vk_map[VK_OEM_2] = Key::SLASH; // (0xBF), For US standard keyboards;the '/?' key.
+ vk_map[VK_OEM_3] = Key::QUOTELEFT; // (0xC0), For US standard keyboards;the '`~' key.
// 0xC1-D7 are reserved. 0xD8-DA are unassigned.
- // TODO: 0xC3-DA may be used for old gamepads? Maybe we want to support this? See WinUser.h.
-
- { Key::BRACKETLEFT, VK_OEM_4 }, // (0xDB)
- // Misc. character, can vary by keyboard/region.
- // Windows 2000/XP: For US standard keyboards, the '[{' key.
-
- { Key::BACKSLASH, VK_OEM_5 }, // (0xDC)
- // Misc. character, can vary by keyboard/region.
- // Windows 2000/XP: For US standard keyboards, the '\|' key.
-
- { Key::BRACKETRIGHT, VK_OEM_6 }, // (0xDD)
- // Misc. character, can vary by keyboard/region.
- // Windows 2000/XP: For US standard keyboards, the ']}' key.
-
- { Key::APOSTROPHE, VK_OEM_7 }, // (0xDE)
- // Misc. character, can vary by keyboard/region.
- // Windows 2000/XP: For US standard keyboards, single quote/double quote.
-
+ // 0xC3-DA may be used for old gamepads? Maybe we want to support this? See WinUser.h.
+ vk_map[VK_OEM_4] = Key::BRACKETLEFT; // (0xDB), For US standard keyboards;the '[{' key.
+ vk_map[VK_OEM_5] = Key::BACKSLASH; // (0xDC), For US standard keyboards;the '\|' key.
+ vk_map[VK_OEM_6] = Key::BRACKETRIGHT; // (0xDD), For US standard keyboards;the ']}' key.
+ vk_map[VK_OEM_7] = Key::APOSTROPHE; // (0xDE), For US standard keyboards;single quote/double quote.
// VK_OEM_8 (0xDF)
- // Misc. character, can vary by keyboard/region. We have no mapping.
-
- // 0xE0 is reserved. 0xE1 is OEM specific, we have no mapping.
-
- // VK_OEM_102 (0xE2)
- // Either angle bracket or backslash key on the RT 102-key keyboard.
- // Old and uncommon, we have no mapping.
-
- { Key::HELP, VK_ICO_HELP }, // (0xE3)
- // OEM (ICO) help key. Map to help.
-
- // 0xE4 is OEM (e.g. ICO) specific, we have no mapping.
-
- // VK_PROCESSKEY (0xE5)
- // For IME, we have no mapping.
-
- { Key::CLEAR, VK_ICO_CLEAR }, // (0xE6)
- // OEM (ICO) clear key. Map to clear.
-
- // VK_PACKET (0xE7)
- // Used to pass Unicode characters as if they were keystrokes.
- // See Win32 API docs. We have no mapping.
-
- // 0xE8 is unassigned, 0xE9-F5 are OEM (Nokia/Ericsson) specific, we have no mappings.
-
- { Key::ESCAPE, VK_ATTN }, // (0xF6)
- // Old IBM 'ATTN' key used on midrange computers, e.g. AS/400, map to Escape.
-
- { Key::TAB, VK_CRSEL }, // (0xF7)
- // Old IBM 3270 'CrSel' (cursor select) key, used to select data fields, map to Tab.
-
- // VK_EXSEL (0xF7)
- // Old IBM 3270 extended selection key. No mapping.
-
- // VK_EREOF (0xF8)
- // Old IBM 3270 erase to end of field key. No mapping.
-
- { Key::MEDIAPLAY, VK_PLAY }, // (0xFA)
- // Old IBM 3270 'Play' key. Map to media play.
-
- // VK_ZOOM (0xFB)
- // Old IBM 3290 'Zoom' key. No mapping.
-
- // VK_NONAME (0xFC)
- // Reserved. No mapping.
-
- // VK_PA1 (0xFD)
- // Old IBM 3270 PA1 key. No mapping.
-
- { Key::CLEAR, VK_OEM_CLEAR }, // (0xFE)
- // OEM specific clear key. Unclear how it differs from normal clear. Map to clear.
-
- { Key::UNKNOWN, 0 }
-};
+ // 0xE0 is reserved. 0xE1 is OEM specific.
+ vk_map[VK_OEM_102] = Key::BAR; // (0xE2), Either angle bracket or backslash key on the RT 102-key keyboard.
+ vk_map[VK_ICO_HELP] = Key::HELP; // (0xE3)
+ // 0xE4 is OEM (e.g. ICO) specific.
+ // VK_PROCESSKEY (0xE5), For IME.
+ vk_map[VK_ICO_CLEAR] = Key::CLEAR; // (0xE6)
+ // VK_PACKET (0xE7), Used to pass Unicode characters as if they were keystrokes.
+ // 0xE8 is unassigned.
+ // 0xE9-F5 are OEM (Nokia/Ericsson) specific.
+ vk_map[VK_ATTN] = Key::ESCAPE; // (0xF6), Old IBM 'ATTN' key used on midrange computers ;e.g. AS/400.
+ vk_map[VK_CRSEL] = Key::TAB; // (0xF7), Old IBM 3270 'CrSel' (cursor select) key; used to select data fields.
+ // VK_EXSEL (0xF7), Old IBM 3270 extended selection key.
+ // VK_EREOF (0xF8), Old IBM 3270 erase to end of field key.
+ vk_map[VK_PLAY] = Key::MEDIAPLAY; // (0xFA), Old IBM 3270 'Play' key.
+ // VK_ZOOM (0xFB), Old IBM 3290 'Zoom' key.
+ // VK_NONAME (0xFC), Reserved.
+ // VK_PA1 (0xFD), Old IBM 3270 PA1 key.
+ vk_map[VK_OEM_CLEAR] = Key::CLEAR; // (0xFE), OEM specific clear key. Unclear how it differs from normal clear.
+
+ scansym_map[0x00] = Key::PAUSE;
+ scansym_map[0x01] = Key::ESCAPE;
+ scansym_map[0x02] = Key::KEY_1;
+ scansym_map[0x03] = Key::KEY_2;
+ scansym_map[0x04] = Key::KEY_3;
+ scansym_map[0x05] = Key::KEY_4;
+ scansym_map[0x06] = Key::KEY_5;
+ scansym_map[0x07] = Key::KEY_6;
+ scansym_map[0x08] = Key::KEY_7;
+ scansym_map[0x09] = Key::KEY_8;
+ scansym_map[0x0A] = Key::KEY_9;
+ scansym_map[0x0B] = Key::KEY_0;
+ scansym_map[0x0C] = Key::MINUS;
+ scansym_map[0x0D] = Key::EQUAL;
+ scansym_map[0x0E] = Key::BACKSPACE;
+ scansym_map[0x0F] = Key::TAB;
+ scansym_map[0x10] = Key::Q;
+ scansym_map[0x11] = Key::W;
+ scansym_map[0x12] = Key::E;
+ scansym_map[0x13] = Key::R;
+ scansym_map[0x14] = Key::T;
+ scansym_map[0x15] = Key::Y;
+ scansym_map[0x16] = Key::U;
+ scansym_map[0x17] = Key::I;
+ scansym_map[0x18] = Key::O;
+ scansym_map[0x19] = Key::P;
+ scansym_map[0x1A] = Key::BRACELEFT;
+ scansym_map[0x1B] = Key::BRACERIGHT;
+ scansym_map[0x1C] = Key::ENTER;
+ scansym_map[0x1D] = Key::CTRL;
+ scansym_map[0x1E] = Key::A;
+ scansym_map[0x1F] = Key::S;
+ scansym_map[0x20] = Key::D;
+ scansym_map[0x21] = Key::F;
+ scansym_map[0x22] = Key::G;
+ scansym_map[0x23] = Key::H;
+ scansym_map[0x24] = Key::J;
+ scansym_map[0x25] = Key::K;
+ scansym_map[0x26] = Key::L;
+ scansym_map[0x27] = Key::SEMICOLON;
+ scansym_map[0x28] = Key::APOSTROPHE;
+ scansym_map[0x29] = Key::QUOTELEFT;
+ scansym_map[0x2A] = Key::SHIFT;
+ scansym_map[0x2B] = Key::BACKSLASH;
+ scansym_map[0x2C] = Key::Z;
+ scansym_map[0x2D] = Key::X;
+ scansym_map[0x2E] = Key::C;
+ scansym_map[0x2F] = Key::V;
+ scansym_map[0x30] = Key::B;
+ scansym_map[0x31] = Key::N;
+ scansym_map[0x32] = Key::M;
+ scansym_map[0x33] = Key::COMMA;
+ scansym_map[0x34] = Key::PERIOD;
+ scansym_map[0x35] = Key::SLASH;
+ scansym_map[0x36] = Key::SHIFT;
+ scansym_map[0x37] = Key::KP_MULTIPLY;
+ scansym_map[0x38] = Key::ALT;
+ scansym_map[0x39] = Key::SPACE;
+ scansym_map[0x3A] = Key::CAPSLOCK;
+ scansym_map[0x3B] = Key::F1;
+ scansym_map[0x3C] = Key::F2;
+ scansym_map[0x3D] = Key::F3;
+ scansym_map[0x3E] = Key::F4;
+ scansym_map[0x3F] = Key::F5;
+ scansym_map[0x40] = Key::F6;
+ scansym_map[0x41] = Key::F7;
+ scansym_map[0x42] = Key::F8;
+ scansym_map[0x43] = Key::F9;
+ scansym_map[0x44] = Key::F10;
+ scansym_map[0x45] = Key::NUMLOCK;
+ scansym_map[0x46] = Key::SCROLLLOCK;
+ scansym_map[0x47] = Key::KP_7;
+ scansym_map[0x48] = Key::KP_8;
+ scansym_map[0x49] = Key::KP_9;
+ scansym_map[0x4A] = Key::KP_SUBTRACT;
+ scansym_map[0x4B] = Key::KP_4;
+ scansym_map[0x4C] = Key::KP_5;
+ scansym_map[0x4D] = Key::KP_6;
+ scansym_map[0x4E] = Key::KP_ADD;
+ scansym_map[0x4F] = Key::KP_1;
+ scansym_map[0x50] = Key::KP_2;
+ scansym_map[0x51] = Key::KP_3;
+ scansym_map[0x52] = Key::KP_0;
+ scansym_map[0x53] = Key::KP_PERIOD;
+ scansym_map[0x57] = Key::SECTION;
+ scansym_map[0x57] = Key::F11;
+ scansym_map[0x58] = Key::F12;
+ scansym_map[0x5B] = Key::META;
+ scansym_map[0x5C] = Key::META;
+ scansym_map[0x5D] = Key::MENU;
+ scansym_map[0x64] = Key::F13;
+ scansym_map[0x65] = Key::F14;
+ scansym_map[0x66] = Key::F15;
+ scansym_map[0x67] = Key::F16;
+ scansym_map[0x68] = Key::F17;
+ scansym_map[0x69] = Key::F18;
+ scansym_map[0x6A] = Key::F19;
+ scansym_map[0x6B] = Key::F20;
+ scansym_map[0x6C] = Key::F21;
+ scansym_map[0x6D] = Key::F22;
+ scansym_map[0x6E] = Key::F23;
+ // scansym_map[0x71] = Key::JIS_KANA;
+ // scansym_map[0x72] = Key::JIS_EISU;
+ scansym_map[0x76] = Key::F24;
+
+ for (const KeyValue<unsigned int, Key> &E : scansym_map) {
+ scansym_map_inv[E.value] = E.key;
+ }
-static _WinTranslatePair _scancode_to_keycode[] = {
- { Key::ESCAPE, 0x01 },
- { Key::KEY_1, 0x02 },
- { Key::KEY_2, 0x03 },
- { Key::KEY_3, 0x04 },
- { Key::KEY_4, 0x05 },
- { Key::KEY_5, 0x06 },
- { Key::KEY_6, 0x07 },
- { Key::KEY_7, 0x08 },
- { Key::KEY_8, 0x09 },
- { Key::KEY_9, 0x0A },
- { Key::KEY_0, 0x0B },
- { Key::MINUS, 0x0C },
- { Key::EQUAL, 0x0D },
- { Key::BACKSPACE, 0x0E },
- { Key::TAB, 0x0F },
- { Key::Q, 0x10 },
- { Key::W, 0x11 },
- { Key::E, 0x12 },
- { Key::R, 0x13 },
- { Key::T, 0x14 },
- { Key::Y, 0x15 },
- { Key::U, 0x16 },
- { Key::I, 0x17 },
- { Key::O, 0x18 },
- { Key::P, 0x19 },
- { Key::BRACELEFT, 0x1A },
- { Key::BRACERIGHT, 0x1B },
- { Key::ENTER, 0x1C },
- { Key::CTRL, 0x1D },
- { Key::A, 0x1E },
- { Key::S, 0x1F },
- { Key::D, 0x20 },
- { Key::F, 0x21 },
- { Key::G, 0x22 },
- { Key::H, 0x23 },
- { Key::J, 0x24 },
- { Key::K, 0x25 },
- { Key::L, 0x26 },
- { Key::SEMICOLON, 0x27 },
- { Key::APOSTROPHE, 0x28 },
- { Key::QUOTELEFT, 0x29 },
- { Key::SHIFT, 0x2A },
- { Key::BACKSLASH, 0x2B },
- { Key::Z, 0x2C },
- { Key::X, 0x2D },
- { Key::C, 0x2E },
- { Key::V, 0x2F },
- { Key::B, 0x30 },
- { Key::N, 0x31 },
- { Key::M, 0x32 },
- { Key::COMMA, 0x33 },
- { Key::PERIOD, 0x34 },
- { Key::SLASH, 0x35 },
- { Key::SHIFT, 0x36 },
- { Key::PRINT, 0x37 },
- { Key::ALT, 0x38 },
- { Key::SPACE, 0x39 },
- { Key::CAPSLOCK, 0x3A },
- { Key::F1, 0x3B },
- { Key::F2, 0x3C },
- { Key::F3, 0x3D },
- { Key::F4, 0x3E },
- { Key::F5, 0x3F },
- { Key::F6, 0x40 },
- { Key::F7, 0x41 },
- { Key::F8, 0x42 },
- { Key::F9, 0x43 },
- { Key::F10, 0x44 },
- { Key::NUMLOCK, 0x45 },
- { Key::SCROLLLOCK, 0x46 },
- { Key::HOME, 0x47 },
- { Key::UP, 0x48 },
- { Key::PAGEUP, 0x49 },
- { Key::KP_SUBTRACT, 0x4A },
- { Key::LEFT, 0x4B },
- { Key::KP_5, 0x4C },
- { Key::RIGHT, 0x4D },
- { Key::KP_ADD, 0x4E },
- { Key::END, 0x4F },
- { Key::DOWN, 0x50 },
- { Key::PAGEDOWN, 0x51 },
- { Key::INSERT, 0x52 },
- { Key::KEY_DELETE, 0x53 },
- { Key::F11, 0x57 },
- { Key::F12, 0x58 },
- { Key::META, 0x5B },
- { Key::META, 0x5C },
- { Key::MENU, 0x5D },
- { Key::F13, 0x64 },
- { Key::F14, 0x65 },
- { Key::F15, 0x66 },
- { Key::F16, 0x67 },
- { Key::F17, 0x68 },
- { Key::F18, 0x69 },
- { Key::F19, 0x6A },
- { Key::F20, 0x6B },
- { Key::F21, 0x6C },
- { Key::F22, 0x6D },
- { Key::F23, 0x6E },
- { Key::F24, 0x76 },
- { Key::UNKNOWN, 0 }
-};
+ scansym_map_ext[0x09] = Key::MENU;
+ scansym_map_ext[0x10] = Key::MEDIAPREVIOUS;
+ scansym_map_ext[0x19] = Key::MEDIANEXT;
+ scansym_map_ext[0x1C] = Key::KP_ENTER;
+ scansym_map_ext[0x20] = Key::VOLUMEMUTE;
+ scansym_map_ext[0x21] = Key::LAUNCH1;
+ scansym_map_ext[0x22] = Key::MEDIAPLAY;
+ scansym_map_ext[0x24] = Key::MEDIASTOP;
+ scansym_map_ext[0x2E] = Key::VOLUMEDOWN;
+ scansym_map_ext[0x30] = Key::VOLUMEUP;
+ scansym_map_ext[0x32] = Key::HOMEPAGE;
+ scansym_map_ext[0x35] = Key::KP_DIVIDE;
+ scansym_map_ext[0x37] = Key::PRINT;
+ scansym_map_ext[0x3A] = Key::KP_ADD;
+ scansym_map_ext[0x45] = Key::NUMLOCK;
+ scansym_map_ext[0x47] = Key::HOME;
+ scansym_map_ext[0x48] = Key::UP;
+ scansym_map_ext[0x49] = Key::PAGEUP;
+ scansym_map_ext[0x4A] = Key::KP_SUBTRACT;
+ scansym_map_ext[0x4B] = Key::LEFT;
+ scansym_map_ext[0x4C] = Key::KP_5;
+ scansym_map_ext[0x4D] = Key::RIGHT;
+ scansym_map_ext[0x4E] = Key::KP_ADD;
+ scansym_map_ext[0x4F] = Key::END;
+ scansym_map_ext[0x50] = Key::DOWN;
+ scansym_map_ext[0x51] = Key::PAGEDOWN;
+ scansym_map_ext[0x52] = Key::INSERT;
+ scansym_map_ext[0x53] = Key::KEY_DELETE;
+ scansym_map_ext[0x5D] = Key::MENU;
+ scansym_map_ext[0x5F] = Key::STANDBY;
+ scansym_map_ext[0x65] = Key::SEARCH;
+ scansym_map_ext[0x66] = Key::FAVORITES;
+ scansym_map_ext[0x67] = Key::REFRESH;
+ scansym_map_ext[0x68] = Key::STOP;
+ scansym_map_ext[0x69] = Key::FORWARD;
+ scansym_map_ext[0x6A] = Key::BACK;
+ scansym_map_ext[0x6B] = Key::LAUNCH0;
+ scansym_map_ext[0x6C] = Key::LAUNCHMAIL;
+ scansym_map_ext[0x6D] = Key::LAUNCHMEDIA;
+ scansym_map_ext[0x78] = Key::MEDIARECORD;
+}
Key KeyMappingWindows::get_keysym(unsigned int p_code) {
- for (int i = 0; _vk_to_keycode[i].keysym != Key::UNKNOWN; i++) {
- if (_vk_to_keycode[i].keycode == p_code) {
- return _vk_to_keycode[i].keysym;
- }
+ const Key *key = vk_map.getptr(p_code);
+ if (key) {
+ return *key;
}
-
return Key::UNKNOWN;
}
unsigned int KeyMappingWindows::get_scancode(Key p_keycode) {
- for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) {
- if (_scancode_to_keycode[i].keysym == p_keycode) {
- return _scancode_to_keycode[i].keycode;
- }
+ const unsigned int *key = scansym_map_inv.getptr(p_keycode);
+ if (key) {
+ return *key;
}
-
return 0;
}
Key KeyMappingWindows::get_scansym(unsigned int p_code, bool p_extended) {
- Key keycode = Key::UNKNOWN;
- for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) {
- if (_scancode_to_keycode[i].keycode == p_code) {
- keycode = _scancode_to_keycode[i].keysym;
- break;
- }
- }
-
if (p_extended) {
- switch (keycode) {
- case Key::ENTER: {
- keycode = Key::KP_ENTER;
- } break;
- case Key::SLASH: {
- keycode = Key::KP_DIVIDE;
- } break;
- case Key::CAPSLOCK: {
- keycode = Key::KP_ADD;
- } break;
- default:
- break;
- }
- } else {
- switch (keycode) {
- case Key::NUMLOCK: {
- keycode = Key::PAUSE;
- } break;
- case Key::HOME: {
- keycode = Key::KP_7;
- } break;
- case Key::UP: {
- keycode = Key::KP_8;
- } break;
- case Key::PAGEUP: {
- keycode = Key::KP_9;
- } break;
- case Key::LEFT: {
- keycode = Key::KP_4;
- } break;
- case Key::RIGHT: {
- keycode = Key::KP_6;
- } break;
- case Key::END: {
- keycode = Key::KP_1;
- } break;
- case Key::DOWN: {
- keycode = Key::KP_2;
- } break;
- case Key::PAGEDOWN: {
- keycode = Key::KP_3;
- } break;
- case Key::INSERT: {
- keycode = Key::KP_0;
- } break;
- case Key::KEY_DELETE: {
- keycode = Key::KP_PERIOD;
- } break;
- case Key::PRINT: {
- keycode = Key::KP_MULTIPLY;
- } break;
- default:
- break;
+ const Key *key = scansym_map_ext.getptr(p_code);
+ if (key) {
+ return *key;
}
}
-
- return keycode;
+ const Key *key = scansym_map.getptr(p_code);
+ if (key) {
+ return *key;
+ }
+ return Key::NONE;
}
bool KeyMappingWindows::is_extended_key(unsigned int p_code) {
diff --git a/platform/windows/key_mapping_windows.h b/platform/windows/key_mapping_windows.h
index ef5bec2b76..a98aa7ed68 100644
--- a/platform/windows/key_mapping_windows.h
+++ b/platform/windows/key_mapping_windows.h
@@ -41,6 +41,8 @@ class KeyMappingWindows {
KeyMappingWindows() {}
public:
+ static void initialize();
+
static Key get_keysym(unsigned int p_code);
static unsigned int get_scancode(Key p_keycode);
static Key get_scansym(unsigned int p_code, bool p_extended);
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index c4de3a124b..7b681eac7a 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -391,10 +391,8 @@ bool AudioStreamPlayer2D::get_stream_paused() const {
}
Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() {
- if (!stream_playbacks.is_empty()) {
- return stream_playbacks[stream_playbacks.size() - 1];
- }
- return nullptr;
+ ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback().");
+ return stream_playbacks[stream_playbacks.size() - 1];
}
void AudioStreamPlayer2D::set_max_polyphony(int p_max_polyphony) {
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 05d28e8a0e..8c5aab4c80 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -2568,7 +2568,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
}
}
}
- ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighbouring tile of %s", p_path[i + 1], p_path[i]));
+ ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighboring tile of %s", p_path[i + 1], p_path[i]));
neighbor_list.push_back(found_bit);
}
@@ -3220,7 +3220,7 @@ Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
ret = ret.floor();
}
- // Compute the tile offset, and if we might the output for a neighbour top tile
+ // Compute the tile offset, and if we might the output for a neighbor top tile
Vector2 in_tile_pos = raw_pos - ret;
bool in_top_left_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(-0.5, 1.0 / overlapping_ratio - 1)) <= 0;
bool in_top_right_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(0.5, 1.0 / overlapping_ratio - 1)) > 0;
@@ -3284,7 +3284,7 @@ Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const {
ret = ret.floor();
}
- // Compute the tile offset, and if we might the output for a neighbour top tile
+ // Compute the tile offset, and if we might the output for a neighbor top tile
Vector2 in_tile_pos = raw_pos - ret;
bool in_top_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, -0.5)) > 0;
bool in_bottom_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, 0.5)) <= 0;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 574f5363d4..7ed18d2d41 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -784,10 +784,8 @@ bool AudioStreamPlayer3D::get_stream_paused() const {
}
Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() {
- if (!stream_playbacks.is_empty()) {
- return stream_playbacks[stream_playbacks.size() - 1];
- }
- return nullptr;
+ ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback().");
+ return stream_playbacks[stream_playbacks.size() - 1];
}
void AudioStreamPlayer3D::set_max_polyphony(int p_max_polyphony) {
@@ -841,7 +839,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioStreamPlayer3D::_set_playing);
ClassDB::bind_method(D_METHOD("_is_active"), &AudioStreamPlayer3D::_is_active);
- ClassDB::bind_method(D_METHOD("set_max_distance", "metres"), &AudioStreamPlayer3D::set_max_distance);
+ ClassDB::bind_method(D_METHOD("set_max_distance", "meters"), &AudioStreamPlayer3D::set_max_distance);
ClassDB::bind_method(D_METHOD("get_max_distance"), &AudioStreamPlayer3D::get_max_distance);
ClassDB::bind_method(D_METHOD("set_area_mask", "mask"), &AudioStreamPlayer3D::set_area_mask);
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 26ada1da5a..19d1b83cab 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -43,6 +43,11 @@ void CollisionObject3D::_notification(int p_what) {
}
_update_debug_shapes();
}
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ set_notify_local_transform(true); // Used for warnings and only in editor.
+ }
+#endif
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -78,6 +83,14 @@ void CollisionObject3D::_notification(int p_what) {
_update_pickable();
} break;
+#ifdef TOOLS_ENABLED
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_configuration_warnings();
+ }
+ } break;
+#endif
+
case NOTIFICATION_TRANSFORM_CHANGED: {
if (only_update_transform_changes) {
return;
@@ -724,6 +737,11 @@ PackedStringArray CollisionObject3D::get_configuration_warnings() const {
warnings.push_back(RTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape."));
}
+ Vector3 scale = get_transform().get_basis().get_scale();
+ if (!(Math::is_zero_approx(scale.x - scale.y) && Math::is_zero_approx(scale.y - scale.z))) {
+ warnings.push_back(RTR("With a non-uniform scale this node will probably not function as expected.\nPlease make its scale uniform (i.e. the same on all axes), and change the size in children collision shapes instead."));
+ }
+
return warnings;
}
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index 5fb8970085..53a61c1368 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -104,6 +104,11 @@ void CollisionPolygon3D::_notification(int p_what) {
if (parent) {
_update_in_shape_owner(true);
}
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_configuration_warnings();
+ }
+#endif
} break;
case NOTIFICATION_UNPARENTED: {
@@ -171,13 +176,18 @@ PackedStringArray CollisionPolygon3D::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- warnings.push_back(RTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
+ warnings.push_back(RTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node.\nPlease only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (polygon.is_empty()) {
warnings.push_back(RTR("An empty CollisionPolygon3D has no effect on collision."));
}
+ Vector3 scale = get_transform().get_basis().get_scale();
+ if (!(Math::is_zero_approx(scale.x - scale.y) && Math::is_zero_approx(scale.y - scale.z))) {
+ warnings.push_back(RTR("A non-uniformly scaled CollisionPolygon3D node will probably not function as expected.\nPlease make its scale uniform (i.e. the same on all axes), and change its polygon's vertices instead."));
+ }
+
return warnings;
}
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 1709a17bce..dbd50cfd19 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -99,6 +99,11 @@ void CollisionShape3D::_notification(int p_what) {
if (parent) {
_update_in_shape_owner(true);
}
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_configuration_warnings();
+ }
+#endif
} break;
case NOTIFICATION_UNPARENTED: {
@@ -134,6 +139,11 @@ PackedStringArray CollisionShape3D::get_configuration_warnings() const {
}
}
+ Vector3 scale = get_transform().get_basis().get_scale();
+ if (!(Math::is_zero_approx(scale.x - scale.y) && Math::is_zero_approx(scale.y - scale.z))) {
+ warnings.push_back(RTR("A non-uniformly scaled CollisionShape3D node will probably not function as expected.\nPlease make its scale uniform (i.e. the same on all axes), and change the size of its shape resource instead."));
+ }
+
return warnings;
}
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index f308ad0999..fb74cffc94 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1545,6 +1545,8 @@ void LightmapGI::_bind_methods() {
BIND_ENUM_CONSTANT(GENERATE_PROBES_SUBDIV_32);
BIND_ENUM_CONSTANT(BAKE_ERROR_OK);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SCENE_ROOT);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_FOREIGN_DATA);
BIND_ENUM_CONSTANT(BAKE_ERROR_NO_LIGHTMAPPER);
BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SAVE_PATH);
BIND_ENUM_CONSTANT(BAKE_ERROR_NO_MESHES);
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index 1294571cc0..40ff9e4cad 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -124,6 +124,8 @@ public:
enum BakeError {
BAKE_ERROR_OK,
+ BAKE_ERROR_NO_SCENE_ROOT,
+ BAKE_ERROR_FOREIGN_DATA,
BAKE_ERROR_NO_LIGHTMAPPER,
BAKE_ERROR_NO_SAVE_PATH,
BAKE_ERROR_NO_MESHES,
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 106efbc596..f4ab09cd9b 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -977,12 +977,11 @@ TypedArray<Node3D> RigidBody3D::get_colliding_bodies() const {
}
PackedStringArray RigidBody3D::get_configuration_warnings() const {
- Transform3D t = get_transform();
+ PackedStringArray warnings = CollisionObject3D::get_configuration_warnings();
- PackedStringArray warnings = Node::get_configuration_warnings();
-
- if (ABS(t.basis.get_column(0).length() - 1.0) > 0.05 || ABS(t.basis.get_column(1).length() - 1.0) > 0.05 || ABS(t.basis.get_column(2).length() - 1.0) > 0.05) {
- warnings.push_back(RTR("Size changes to RigidBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ Vector3 scale = get_transform().get_basis().get_scale();
+ if (ABS(scale.x - 1.0) > 0.05 || ABS(scale.y - 1.0) > 0.05 || ABS(scale.z - 1.0) > 0.05) {
+ warnings.push_back(RTR("Scale changes to RigidBody3D will be overridden by the physics engine when running.\nPlease change the size in children collision shapes instead."));
}
return warnings;
@@ -1347,7 +1346,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
motion = motion.slide(up_direction);
result.travel = Vector3();
} else {
- // Travel is too high to be safely cancelled, we take it into account.
+ // Travel is too high to be safely canceled, we take it into account.
result.travel = result.travel.slide(up_direction);
motion = motion.normalized() * result.travel.length();
}
@@ -1355,7 +1354,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
// Determines if you are on the ground, and limits the possibility of climbing on the walls because of the approximations.
_snap_on_floor(true, false);
} else {
- // If the movement is not cancelled we only keep the remaining.
+ // If the movement is not canceled we only keep the remaining.
motion = result.remainder;
}
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index e8b51ceb92..e7e3084037 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -302,14 +302,6 @@ void SoftBody3D::_notification(int p_what) {
_prepare_physics_server();
}
} break;
-
-#ifdef TOOLS_ENABLED
- case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
- }
- } break;
-#endif
}
}
@@ -391,11 +383,6 @@ PackedStringArray SoftBody3D::get_configuration_warnings() const {
warnings.push_back(RTR("This body will be ignored until you set a mesh."));
}
- Transform3D t = get_transform();
- if ((ABS(t.basis.get_column(0).length() - 1.0) > 0.05 || ABS(t.basis.get_column(1).length() - 1.0) > 0.05 || ABS(t.basis.get_column(2).length() - 1.0) > 0.05)) {
- warnings.push_back(RTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
- }
-
return warnings;
}
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 2c79e5fe06..02f1e9f9a6 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -212,7 +212,7 @@ StringName AnimationNodeStateMachinePlayback::get_current_node() const {
return current;
}
-StringName AnimationNodeStateMachinePlayback::get_blend_from_node() const {
+StringName AnimationNodeStateMachinePlayback::get_fading_from_node() const {
return fading_from;
}
@@ -411,9 +411,11 @@ double AnimationNodeStateMachinePlayback::_process(AnimationNodeStateMachine *p_
// can't travel, then teleport
if (p_state_machine->states.has(travel_request)) {
path.clear();
- current = travel_request;
- play_start = true;
- reset_request = reset_request_on_teleport;
+ if (current != travel_request || reset_request_on_teleport) {
+ current = travel_request;
+ play_start = true;
+ reset_request = reset_request_on_teleport;
+ }
} else {
StringName node = travel_request;
travel_request = StringName();
@@ -703,6 +705,7 @@ void AnimationNodeStateMachinePlayback::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachinePlayback::get_current_node);
ClassDB::bind_method(D_METHOD("get_current_play_position"), &AnimationNodeStateMachinePlayback::get_current_play_pos);
ClassDB::bind_method(D_METHOD("get_current_length"), &AnimationNodeStateMachinePlayback::get_current_length);
+ ClassDB::bind_method(D_METHOD("get_fading_from_node"), &AnimationNodeStateMachinePlayback::get_fading_from_node);
ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachinePlayback::get_travel_path);
}
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index 8183d2025a..1b4e010a06 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -159,7 +159,7 @@ public:
void stop();
bool is_playing() const;
StringName get_current_node() const;
- StringName get_blend_from_node() const;
+ StringName get_fading_from_node() const;
Vector<StringName> get_travel_path() const;
float get_current_play_pos() const;
float get_current_length() const;
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index dd00897422..077a5696bb 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -754,7 +754,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
if (has_reset_anim) {
int rt = reset_anim->find_track(path, track_type);
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
- track_bezier->init_value = reset_anim->track_get_key_value(rt, 0);
+ track_bezier->init_value = (reset_anim->track_get_key_value(rt, 0).operator Array())[0];
}
}
} break;
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 42f76068e7..d40fc10441 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -308,10 +308,8 @@ void AudioStreamPlayer::_bus_layout_changed() {
}
Ref<AudioStreamPlayback> AudioStreamPlayer::get_stream_playback() {
- if (!stream_playbacks.is_empty()) {
- return stream_playbacks[stream_playbacks.size() - 1];
- }
- return nullptr;
+ ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback().");
+ return stream_playbacks[stream_playbacks.size() - 1];
}
void AudioStreamPlayer::_bind_methods() {
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 2c5248f088..da29bc823f 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -475,7 +475,7 @@ ColorPicker::PickerShapeType ColorPicker::_get_actual_shape() const {
void ColorPicker::_reset_theme() {
Ref<StyleBoxFlat> style_box_flat(memnew(StyleBoxFlat));
- style_box_flat->set_default_margin(SIDE_TOP, 16 * get_theme_default_base_scale());
+ style_box_flat->set_content_margin(SIDE_TOP, 16 * get_theme_default_base_scale());
style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp());
for (int i = 0; i < SLIDER_COUNT; i++) {
sliders[i]->add_theme_icon_override("grabber", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker")));
@@ -894,7 +894,7 @@ void ColorPicker::set_colorize_sliders(bool p_colorize_sliders) {
alpha_slider->add_theme_style_override("slider", style_box_empty);
} else {
Ref<StyleBoxFlat> style_box_flat(memnew(StyleBoxFlat));
- style_box_flat->set_default_margin(SIDE_TOP, 16 * get_theme_default_base_scale());
+ style_box_flat->set_content_margin(SIDE_TOP, 16 * get_theme_default_base_scale());
style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp());
if (!slider_theme_modified) {
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 4365db2ea2..dfe9ea3b08 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -136,7 +136,7 @@ void AcceptDialog::_cancel_pressed() {
call_deferred(SNAME("hide"));
- emit_signal(SNAME("cancelled"));
+ emit_signal(SNAME("canceled"));
cancel_pressed();
@@ -372,7 +372,7 @@ void AcceptDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_ok_button_text"), &AcceptDialog::get_ok_button_text);
ADD_SIGNAL(MethodInfo("confirmed"));
- ADD_SIGNAL(MethodInfo("cancelled"));
+ ADD_SIGNAL(MethodInfo("canceled"));
ADD_SIGNAL(MethodInfo("custom_action", PropertyInfo(Variant::STRING_NAME, "action")));
ADD_PROPERTY(PropertyInfo(Variant::STRING, "ok_button_text"), "set_ok_button_text", "get_ok_button_text");
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index e5bb64b225..e2a5b0c8a3 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -952,9 +952,9 @@ void LineEdit::_notification(int p_what) {
// Prevent carets from disappearing at theme scales below 1.0 (if the caret width is 1).
const int caret_width = theme_cache.caret_width * MAX(1, theme_cache.base_scale);
- if (ime_text.length() == 0) {
+ if (ime_text.is_empty() || ime_selection.y == 0) {
// Normal caret.
- CaretInfo caret = TS->shaped_text_get_carets(text_rid, caret_column);
+ CaretInfo caret = TS->shaped_text_get_carets(text_rid, ime_text.is_empty() ? caret_column : caret_column + ime_selection.x);
if (using_placeholder || (caret.l_caret == Rect2() && caret.t_caret == Rect2())) {
// No carets, add one at the start.
int h = theme_cache.font->get_height(theme_cache.font_size);
@@ -980,6 +980,7 @@ void LineEdit::_notification(int p_what) {
}
} break;
}
+
RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.l_caret, caret_color);
} else {
if (caret.l_caret != Rect2() && caret.l_dir == TextServer::DIRECTION_AUTO) {
@@ -1009,7 +1010,8 @@ void LineEdit::_notification(int p_what) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.t_caret, caret_color);
}
- } else {
+ }
+ if (!ime_text.is_empty()) {
{
// IME intermediate text range.
Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column, caret_column + ime_text.length());
@@ -1030,20 +1032,22 @@ void LineEdit::_notification(int p_what) {
}
{
// IME caret.
- Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column + ime_selection.x, caret_column + ime_selection.x + ime_selection.y);
- for (int i = 0; i < sel.size(); i++) {
- Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height);
- if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) {
- continue;
- }
- if (rect.position.x < x_ofs) {
- rect.size.x -= (x_ofs - rect.position.x);
- rect.position.x = x_ofs;
- } else if (rect.position.x + rect.size.x > ofs_max) {
- rect.size.x = ofs_max - rect.position.x;
+ if (ime_selection.y > 0) {
+ Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column + ime_selection.x, caret_column + ime_selection.x + ime_selection.y);
+ for (int i = 0; i < sel.size(); i++) {
+ Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height);
+ if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) {
+ continue;
+ }
+ if (rect.position.x < x_ofs) {
+ rect.size.x -= (x_ofs - rect.position.x);
+ rect.position.x = x_ofs;
+ } else if (rect.position.x + rect.size.x > ofs_max) {
+ rect.size.x = ofs_max - rect.position.x;
+ }
+ rect.size.y = caret_width * 3;
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, caret_color);
}
- rect.size.y = caret_width * 3;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, caret_color);
}
}
}
@@ -1052,7 +1056,8 @@ void LineEdit::_notification(int p_what) {
if (has_focus()) {
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
- DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + Point2(using_placeholder ? 0 : x_ofs, y_ofs + TS->shaped_text_get_size(text_rid).y), get_viewport()->get_window_id());
+ Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2);
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + pos, get_viewport()->get_window_id());
}
}
} break;
@@ -1071,8 +1076,8 @@ void LineEdit::_notification(int p_what) {
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
- Point2 column = Point2(get_caret_column(), 1) * get_minimum_size().height;
- DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + column, get_viewport()->get_window_id());
+ Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2);
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + pos, get_viewport()->get_window_id());
}
show_virtual_keyboard();
@@ -1103,6 +1108,11 @@ void LineEdit::_notification(int p_what) {
if (has_focus()) {
ime_text = DisplayServer::get_singleton()->ime_get_text();
ime_selection = DisplayServer::get_singleton()->ime_get_selection();
+
+ if (!ime_text.is_empty()) {
+ selection_delete();
+ }
+
_shape();
set_caret_column(caret_column); // Update scroll_offset
@@ -2576,7 +2586,7 @@ LineEdit::LineEdit(const String &p_placeholder) {
set_placeholder(p_placeholder);
- set_editable(true); // Initialise to opposite first, so we get past the early-out in set_editable.
+ set_editable(true); // Initialize to opposite first, so we get past the early-out in set_editable.
}
LineEdit::~LineEdit() {
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 224e405d41..5b27983851 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -214,10 +214,10 @@ void MenuBar::_update_submenu(const String &p_menu_name, PopupMenu *p_child) {
PopupMenu *pm = Object::cast_to<PopupMenu>(n);
ERR_FAIL_COND_MSG(!pm, "Item subnode is not a PopupMenu: " + p_child->get_item_submenu(i) + ".");
- DisplayServer::get_singleton()->global_menu_add_submenu_item(p_menu_name, p_child->get_item_text(i), p_menu_name + "/" + itos(i));
+ DisplayServer::get_singleton()->global_menu_add_submenu_item(p_menu_name, atr(p_child->get_item_text(i)), p_menu_name + "/" + itos(i));
_update_submenu(p_menu_name + "/" + itos(i), pm);
} else {
- int index = DisplayServer::get_singleton()->global_menu_add_item(p_menu_name, p_child->get_item_text(i), callable_mp(p_child, &PopupMenu::activate_item), Callable(), i);
+ int index = DisplayServer::get_singleton()->global_menu_add_item(p_menu_name, atr(p_child->get_item_text(i)), callable_mp(p_child, &PopupMenu::activate_item), Callable(), i);
if (p_child->is_item_checkable(i)) {
DisplayServer::get_singleton()->global_menu_set_item_checkable(p_menu_name, index, true);
@@ -290,7 +290,7 @@ void MenuBar::_update_menu() {
if (menu_cache[i].hidden) {
continue;
}
- String menu_name = String(popups[i]->get_meta("_menu_name", popups[i]->get_name()));
+ String menu_name = atr(String(popups[i]->get_meta("_menu_name", popups[i]->get_name())));
index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", menu_name, root_name + "/" + itos(i), index);
if (menu_cache[i].disabled) {
@@ -525,7 +525,7 @@ void MenuBar::shape(Menu &p_menu) {
} else {
p_menu.text_buf->set_direction((TextServer::Direction)text_direction);
}
- p_menu.text_buf->add_string(p_menu.name, theme_cache.font, theme_cache.font_size, language);
+ p_menu.text_buf->add_string(atr(p_menu.name), theme_cache.font, theme_cache.font_size, language);
}
void MenuBar::_refresh_menu_names() {
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 4e8a44dd63..ddc11d97b9 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -594,17 +594,17 @@ void PopupMenu::_draw_items() {
int content_left = content_center - content_size / 2;
int content_right = content_center + content_size / 2;
if (content_left > item_ofs.x) {
- int sep_h = theme_cache.labeled_separator_left->get_center_size().height + theme_cache.labeled_separator_left->get_minimum_size().height;
+ int sep_h = theme_cache.labeled_separator_left->get_minimum_size().height;
int sep_ofs = Math::floor((h - sep_h) / 2.0);
theme_cache.labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, content_left - item_ofs.x), sep_h)));
}
if (content_right < display_width) {
- int sep_h = theme_cache.labeled_separator_right->get_center_size().height + theme_cache.labeled_separator_right->get_minimum_size().height;
+ int sep_h = theme_cache.labeled_separator_right->get_minimum_size().height;
int sep_ofs = Math::floor((h - sep_h) / 2.0);
theme_cache.labeled_separator_right->draw(ci, Rect2(Point2(content_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - content_right), sep_h)));
}
} else {
- int sep_h = theme_cache.separator_style->get_center_size().height + theme_cache.separator_style->get_minimum_size().height;
+ int sep_h = theme_cache.separator_style->get_minimum_size().height;
int sep_ofs = Math::floor((h - sep_h) / 2.0);
theme_cache.separator_style->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h)));
}
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index e617b2ca77..b8faf22a59 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -433,7 +433,7 @@ void ScrollBar::_notification(int p_what) {
double ScrollBar::get_grabber_min_size() const {
Ref<StyleBox> grabber = theme_cache.grabber_style;
- Size2 gminsize = grabber->get_minimum_size() + grabber->get_center_size();
+ Size2 gminsize = grabber->get_minimum_size();
return (orientation == VERTICAL) ? gminsize.height : gminsize.width;
}
@@ -500,7 +500,7 @@ Size2 ScrollBar::get_minimum_size() const {
Size2 minsize;
if (orientation == VERTICAL) {
- minsize.width = MAX(incr->get_size().width, (bg->get_minimum_size() + bg->get_center_size()).width);
+ minsize.width = MAX(incr->get_size().width, bg->get_minimum_size().width);
minsize.height += incr->get_size().height;
minsize.height += decr->get_size().height;
minsize.height += bg->get_minimum_size().height;
@@ -508,7 +508,7 @@ Size2 ScrollBar::get_minimum_size() const {
}
if (orientation == HORIZONTAL) {
- minsize.height = MAX(incr->get_size().height, (bg->get_center_size() + bg->get_minimum_size()).height);
+ minsize.height = MAX(incr->get_size().height, bg->get_minimum_size().height);
minsize.width += incr->get_size().width;
minsize.width += decr->get_size().width;
minsize.width += bg->get_minimum_size().width;
diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp
index 45185de698..b0879c1931 100644
--- a/scene/gui/separator.cpp
+++ b/scene/gui/separator.cpp
@@ -51,7 +51,7 @@ void Separator::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
Size2i size = get_size();
- Size2i ssize = theme_cache.separator_style->get_minimum_size() + theme_cache.separator_style->get_center_size();
+ Size2i ssize = theme_cache.separator_style->get_minimum_size();
if (orientation == VERTICAL) {
theme_cache.separator_style->draw(get_canvas_item(), Rect2((size.x - ssize.x) / 2, 0, ssize.x, size.y));
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 040559dab8..292a4cfea2 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -33,7 +33,7 @@
#include "core/os/keyboard.h"
Size2 Slider::get_minimum_size() const {
- Size2i ss = theme_cache.slider_style->get_minimum_size() + theme_cache.slider_style->get_center_size();
+ Size2i ss = theme_cache.slider_style->get_minimum_size();
Size2i rs = theme_cache.grabber_icon->get_size();
if (orientation == HORIZONTAL) {
@@ -212,7 +212,7 @@ void Slider::_notification(int p_what) {
}
if (orientation == VERTICAL) {
- int widget_width = style->get_minimum_size().width + style->get_center_size().width;
+ int widget_width = style->get_minimum_size().width;
double areasize = size.height - grabber->get_size().height;
style->draw(ci, Rect2i(Point2i(size.width / 2 - widget_width / 2, 0), Size2i(widget_width, size.height)));
grabber_area->draw(ci, Rect2i(Point2i((size.width - widget_width) / 2, size.height - areasize * ratio - grabber->get_size().height / 2), Size2i(widget_width, areasize * ratio + grabber->get_size().height / 2)));
@@ -229,7 +229,7 @@ void Slider::_notification(int p_what) {
}
grabber->draw(ci, Point2i(size.width / 2 - grabber->get_size().width / 2 + get_theme_constant(SNAME("grabber_offset")), size.height - ratio * areasize - grabber->get_size().height));
} else {
- int widget_height = style->get_minimum_size().height + style->get_center_size().height;
+ int widget_height = style->get_minimum_size().height;
double areasize = size.width - grabber->get_size().width;
style->draw(ci, Rect2i(Point2i(0, (size.height - widget_height) / 2), Size2i(size.width, widget_height)));
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 8ffaa9e81f..56bd5c872a 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1319,11 +1319,12 @@ void TextEdit::_notification(int p_what) {
if (!clipped && get_caret_line(c) == line && carets_wrap_index[c] == line_wrap_index) {
carets.write[c].draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index);
- if (ime_text.length() == 0) {
+ if (ime_text.is_empty() || ime_selection.y == 0) {
+ // Normal caret.
CaretInfo ts_caret;
- if (str.length() != 0) {
+ if (!str.is_empty() || !ime_text.is_empty()) {
// Get carets.
- ts_caret = TS->shaped_text_get_carets(rid, get_caret_column(c));
+ ts_caret = TS->shaped_text_get_carets(rid, ime_text.is_empty() ? get_caret_column(c) : get_caret_column(c) + ime_selection.x);
} else {
// No carets, add one at the start.
int h = font->get_height(font_size);
@@ -1426,7 +1427,8 @@ void TextEdit::_notification(int p_what) {
}
}
}
- } else {
+ }
+ if (!ime_text.is_empty()) {
{
// IME Intermediate text range.
Vector<Vector2> sel = TS->shaped_text_get_selection(rid, get_caret_column(c), get_caret_column(c) + ime_text.length());
@@ -1546,6 +1548,10 @@ void TextEdit::_notification(int p_what) {
ime_text = DisplayServer::get_singleton()->ime_get_text();
ime_selection = DisplayServer::get_singleton()->ime_get_selection();
+ if (!ime_text.is_empty()) {
+ delete_selection();
+ }
+
for (int i = 0; i < carets.size(); i++) {
String t;
if (get_caret_column(i) >= 0) {
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 426acc4996..2ec2f39409 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -274,7 +274,7 @@ private:
void _update_placeholder();
- /* Initialise to opposite first, so we get past the early-out in set_editable. */
+ /* Initialize to opposite first, so we get past the early-out in set_editable. */
bool editable = false;
TextDirection text_direction = TEXT_DIRECTION_AUTO;
diff --git a/scene/main/multiplayer_api.cpp b/scene/main/multiplayer_api.cpp
index e36cbc4414..c54e61580f 100644
--- a/scene/main/multiplayer_api.cpp
+++ b/scene/main/multiplayer_api.cpp
@@ -135,7 +135,7 @@ Error MultiplayerAPI::encode_and_compress_variant(const Variant &p_variant, uint
return err;
}
if (r_buffer) {
- // The first byte is not used by the marshalling, so store the type
+ // The first byte is not used by the marshaling, so store the type
// so we know how to decompress and decode this variant.
r_buffer[0] = p_variant.get_type();
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index def91c424c..0b1f8f101c 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2947,6 +2947,7 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE);
BIND_CONSTANT(NOTIFICATION_DISABLED);
BIND_CONSTANT(NOTIFICATION_ENABLED);
+ BIND_CONSTANT(NOTIFICATION_NODE_RECACHE_REQUESTED);
BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE);
BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE);
diff --git a/scene/main/node.h b/scene/main/node.h
index dbdcca6170..493578bc5b 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -270,6 +270,7 @@ public:
NOTIFICATION_POST_ENTER_TREE = 27,
NOTIFICATION_DISABLED = 28,
NOTIFICATION_ENABLED = 29,
+ NOTIFICATION_NODE_RECACHE_REQUESTED = 30,
//keep these linked to node
NOTIFICATION_WM_MOUSE_ENTER = 1002,
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 4baedc8c14..2c6599d849 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -227,7 +227,7 @@ void Window::_validate_property(PropertyInfo &p_property) const {
p_property.usage = PROPERTY_USAGE_NONE;
}
- if (p_property.name == "current_screen" && initial_position != WINDOW_INITIAL_POSITION_CENTER_SCREEN) {
+ if (p_property.name == "current_screen" && initial_position != WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN) {
p_property.usage = PROPERTY_USAGE_NONE;
}
@@ -482,7 +482,11 @@ void Window::_make_window() {
Rect2i window_rect;
if (initial_position == WINDOW_INITIAL_POSITION_ABSOLUTE) {
window_rect = Rect2i(position, size);
- } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_SCREEN) {
+ } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN) {
+ window_rect = Rect2i(DisplayServer::get_singleton()->screen_get_position(DisplayServer::SCREEN_PRIMARY) + (DisplayServer::get_singleton()->screen_get_size(DisplayServer::SCREEN_PRIMARY) - size) / 2, size);
+ } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN) {
+ window_rect = Rect2i(DisplayServer::get_singleton()->screen_get_position(DisplayServer::SCREEN_OF_MAIN_WINDOW) + (DisplayServer::get_singleton()->screen_get_size(DisplayServer::SCREEN_OF_MAIN_WINDOW) - size) / 2, size);
+ } else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN) {
window_rect = Rect2i(DisplayServer::get_singleton()->screen_get_position(current_screen) + (DisplayServer::get_singleton()->screen_get_size(current_screen) - size) / 2, size);
}
window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, window_rect);
@@ -2246,18 +2250,14 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("popup_centered", "minsize"), &Window::popup_centered, DEFVAL(Size2i()));
ClassDB::bind_method(D_METHOD("popup_centered_clamped", "minsize", "fallback_ratio"), &Window::popup_centered_clamped, DEFVAL(Size2i()), DEFVAL(0.75));
- ADD_PROPERTY(PropertyInfo(Variant::INT, "initial_position", PROPERTY_HINT_ENUM, "Absolute,Screen Center"), "set_initial_position", "get_initial_position");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "initial_position", PROPERTY_HINT_ENUM, "Absolute,Primary Screen Center,Main Window Screen Center,Other Screen Center"), "set_initial_position", "get_initial_position");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen"), "set_mode", "get_mode");
// Keep the enum values in sync with the `DisplayServer::SCREEN_` enum.
- String screen_hints = "Primary Monitor:-2,Main Window Monitor:-1";
- for (int i = 0; i < 64; i++) {
- screen_hints += ",Monitor " + itos(i + 1) + ":" + itos(i);
- }
- ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_ENUM, screen_hints), "set_current_screen", "get_current_screen");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_current_screen", "get_current_screen");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "mouse_passthrough_polygon"), "set_mouse_passthrough_polygon", "get_mouse_passthrough_polygon");
@@ -2340,7 +2340,9 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_RTL);
BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_ABSOLUTE);
- BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_SCREEN);
+ BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN);
+ BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN);
+ BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN);
}
Window::Window() {
diff --git a/scene/main/window.h b/scene/main/window.h
index d819ca7c60..e9c217f973 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -90,14 +90,16 @@ public:
enum WindowInitialPosition {
WINDOW_INITIAL_POSITION_ABSOLUTE,
- WINDOW_INITIAL_POSITION_CENTER_SCREEN,
+ WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN,
+ WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN,
+ WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN,
};
private:
DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID;
String title;
- mutable int current_screen = DisplayServer::SCREEN_PRIMARY;
+ mutable int current_screen = 0;
mutable Vector2i position;
mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE);
mutable Size2i min_size;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index d56b94b6fe..7bebf1cfd3 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -140,6 +140,7 @@
#include "scene/main/viewport.h"
#include "scene/main/window.h"
#include "scene/resources/animation_library.h"
+#include "scene/resources/audio_stream_polyphonic.h"
#include "scene/resources/audio_stream_wav.h"
#include "scene/resources/bit_map.h"
#include "scene/resources/bone_map.h"
@@ -907,6 +908,8 @@ void register_scene_types() {
#endif
GDREGISTER_ABSTRACT_CLASS(VideoStream);
GDREGISTER_CLASS(AudioStreamWAV);
+ GDREGISTER_CLASS(AudioStreamPolyphonic);
+ GDREGISTER_ABSTRACT_CLASS(AudioStreamPlaybackPolyphonic);
OS::get_singleton()->yield(); // may take time to init
diff --git a/scene/resources/audio_stream_polyphonic.cpp b/scene/resources/audio_stream_polyphonic.cpp
new file mode 100644
index 0000000000..f7299b0789
--- /dev/null
+++ b/scene/resources/audio_stream_polyphonic.cpp
@@ -0,0 +1,274 @@
+/**************************************************************************/
+/* audio_stream_polyphonic.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "audio_stream_polyphonic.h"
+#include "scene/main/scene_tree.h"
+
+Ref<AudioStreamPlayback> AudioStreamPolyphonic::instantiate_playback() {
+ Ref<AudioStreamPlaybackPolyphonic> playback;
+ playback.instantiate();
+ playback->streams.resize(polyphony);
+ return playback;
+}
+
+String AudioStreamPolyphonic::get_stream_name() const {
+ return "AudioStreamPolyphonic";
+}
+
+bool AudioStreamPolyphonic::is_monophonic() const {
+ return true; // This avoids stream players to instantiate more than one of these.
+}
+
+void AudioStreamPolyphonic::set_polyphony(int p_voices) {
+ ERR_FAIL_COND(p_voices < 0 || p_voices > 128);
+ polyphony = p_voices;
+}
+int AudioStreamPolyphonic::get_polyphony() const {
+ return polyphony;
+}
+
+void AudioStreamPolyphonic::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_polyphony", "voices"), &AudioStreamPolyphonic::set_polyphony);
+ ClassDB::bind_method(D_METHOD("get_polyphony"), &AudioStreamPolyphonic::get_polyphony);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "polyphony", PROPERTY_HINT_RANGE, "1,128,1"), "set_polyphony", "get_polyphony");
+}
+
+AudioStreamPolyphonic::AudioStreamPolyphonic() {
+}
+
+////////////////////////
+
+void AudioStreamPlaybackPolyphonic::start(double p_from_pos) {
+ if (active) {
+ stop();
+ }
+
+ active = true;
+}
+
+void AudioStreamPlaybackPolyphonic::stop() {
+ if (!active) {
+ return;
+ }
+
+ bool locked = false;
+ for (Stream &s : streams) {
+ if (s.active.is_set()) {
+ // Need locking because something may still be mixing.
+ locked = true;
+ AudioServer::get_singleton()->lock();
+ }
+ s.active.clear();
+ s.finish_request.clear();
+ s.stream_playback.unref();
+ s.stream.unref();
+ }
+ if (locked) {
+ AudioServer::get_singleton()->unlock();
+ }
+
+ active = false;
+}
+
+bool AudioStreamPlaybackPolyphonic::is_playing() const {
+ return active;
+}
+
+int AudioStreamPlaybackPolyphonic::get_loop_count() const {
+ return 0;
+}
+
+double AudioStreamPlaybackPolyphonic::get_playback_position() const {
+ return 0;
+}
+void AudioStreamPlaybackPolyphonic::seek(double p_time) {
+ // Ignored.
+}
+
+void AudioStreamPlaybackPolyphonic::tag_used_streams() {
+ for (Stream &s : streams) {
+ if (s.active.is_set()) {
+ s.stream_playback->tag_used_streams();
+ }
+ }
+}
+
+int AudioStreamPlaybackPolyphonic::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+ if (!active) {
+ return 0;
+ }
+
+ // Pre-clear buffer.
+ for (int i = 0; i < p_frames; i++) {
+ p_buffer[i] = AudioFrame(0, 0);
+ }
+
+ for (Stream &s : streams) {
+ if (!s.active.is_set()) {
+ continue;
+ }
+
+ float volume_db = s.volume_db; // Copy because it can be overridden at any time.
+ float next_volume = Math::db_to_linear(volume_db);
+ s.prev_volume_db = volume_db;
+
+ if (s.finish_request.is_set()) {
+ if (s.pending_play.is_set()) {
+ // Did not get the chance to play, was finalized too soon.
+ s.active.clear();
+ continue;
+ }
+ next_volume = 0;
+ }
+
+ if (s.pending_play.is_set()) {
+ s.stream_playback->start(s.play_offset);
+ s.pending_play.clear();
+ }
+ float prev_volume = Math::db_to_linear(s.prev_volume_db);
+
+ float volume_inc = (next_volume - prev_volume) / float(p_frames);
+
+ int todo = p_frames;
+ int offset = 0;
+ float volume = prev_volume;
+
+ bool stream_done = false;
+
+ while (todo) {
+ int to_mix = MIN(todo, int(INTERNAL_BUFFER_LEN));
+ int mixed = s.stream_playback->mix(internal_buffer, s.pitch_scale, to_mix);
+
+ for (int i = 0; i < to_mix; i++) {
+ p_buffer[offset + i] += internal_buffer[i] * volume;
+ volume += volume_inc;
+ }
+
+ if (mixed < to_mix) {
+ // Stream is done.
+ s.active.clear();
+ stream_done = true;
+ break;
+ }
+
+ todo -= to_mix;
+ offset += to_mix;
+ }
+
+ if (stream_done) {
+ continue;
+ }
+
+ if (s.finish_request.is_set()) {
+ s.active.clear();
+ }
+ }
+
+ return p_frames;
+}
+
+AudioStreamPlaybackPolyphonic::ID AudioStreamPlaybackPolyphonic::play_stream(const Ref<AudioStream> &p_stream, float p_from_offset, float p_volume_db, float p_pitch_scale) {
+ ERR_FAIL_COND_V(p_stream.is_null(), INVALID_ID);
+ for (uint32_t i = 0; i < streams.size(); i++) {
+ if (!streams[i].active.is_set()) {
+ // Can use this stream, as it's not active.
+ streams[i].stream = p_stream;
+ streams[i].stream_playback = streams[i].stream->instantiate_playback();
+ streams[i].play_offset = p_from_offset;
+ streams[i].volume_db = p_volume_db;
+ streams[i].prev_volume_db = p_volume_db;
+ streams[i].pitch_scale = p_pitch_scale;
+ streams[i].id = id_counter++;
+ streams[i].finish_request.clear();
+ streams[i].pending_play.set();
+ streams[i].active.set();
+ return (ID(i) << INDEX_SHIFT) | ID(streams[i].id);
+ }
+ }
+
+ return INVALID_ID;
+}
+
+AudioStreamPlaybackPolyphonic::Stream *AudioStreamPlaybackPolyphonic::_find_stream(int64_t p_id) {
+ uint32_t index = p_id >> INDEX_SHIFT;
+ if (index >= streams.size()) {
+ return nullptr;
+ }
+ if (!streams[index].active.is_set()) {
+ return nullptr; // Not active, no longer exists.
+ }
+ int64_t id = p_id & ID_MASK;
+ if (streams[index].id != id) {
+ return nullptr;
+ }
+ return &streams[index];
+}
+
+void AudioStreamPlaybackPolyphonic::set_stream_volume(ID p_stream_id, float p_volume_db) {
+ Stream *s = _find_stream(p_stream_id);
+ if (!s) {
+ return;
+ }
+ s->volume_db = p_volume_db;
+}
+
+void AudioStreamPlaybackPolyphonic::set_stream_pitch_scale(ID p_stream_id, float p_pitch_scale) {
+ Stream *s = _find_stream(p_stream_id);
+ if (!s) {
+ return;
+ }
+ s->pitch_scale = p_pitch_scale;
+}
+
+bool AudioStreamPlaybackPolyphonic::is_stream_playing(ID p_stream_id) const {
+ return const_cast<AudioStreamPlaybackPolyphonic *>(this)->_find_stream(p_stream_id) != nullptr;
+}
+
+void AudioStreamPlaybackPolyphonic::stop_stream(ID p_stream_id) {
+ Stream *s = _find_stream(p_stream_id);
+ if (!s) {
+ return;
+ }
+ s->finish_request.set();
+}
+
+void AudioStreamPlaybackPolyphonic::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("play_stream", "stream", "from_offset", "volume_db", "pitch_scale"), &AudioStreamPlaybackPolyphonic::play_stream, DEFVAL(0), DEFVAL(0), DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("set_stream_volume", "stream", "volume_db"), &AudioStreamPlaybackPolyphonic::set_stream_volume);
+ ClassDB::bind_method(D_METHOD("set_stream_pitch_scale", "stream", "pitch_scale"), &AudioStreamPlaybackPolyphonic::set_stream_pitch_scale);
+ ClassDB::bind_method(D_METHOD("is_stream_playing", "stream"), &AudioStreamPlaybackPolyphonic::is_stream_playing);
+ ClassDB::bind_method(D_METHOD("stop_stream", "stream"), &AudioStreamPlaybackPolyphonic::stop_stream);
+
+ BIND_CONSTANT(INVALID_ID);
+}
+
+AudioStreamPlaybackPolyphonic::AudioStreamPlaybackPolyphonic() {
+}
diff --git a/scene/resources/audio_stream_polyphonic.h b/scene/resources/audio_stream_polyphonic.h
new file mode 100644
index 0000000000..e414401b6f
--- /dev/null
+++ b/scene/resources/audio_stream_polyphonic.h
@@ -0,0 +1,119 @@
+/**************************************************************************/
+/* audio_stream_polyphonic.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef AUDIO_STREAM_POLYPHONIC_H
+#define AUDIO_STREAM_POLYPHONIC_H
+
+#include "core/templates/local_vector.h"
+#include "servers/audio/audio_stream.h"
+
+class AudioStreamPolyphonic : public AudioStream {
+ GDCLASS(AudioStreamPolyphonic, AudioStream)
+ int polyphony = 32;
+
+ static void _bind_methods();
+
+public:
+ virtual Ref<AudioStreamPlayback> instantiate_playback() override;
+ virtual String get_stream_name() const override;
+ virtual bool is_monophonic() const override;
+
+ void set_polyphony(int p_voices);
+ int get_polyphony() const;
+
+ AudioStreamPolyphonic();
+};
+
+class AudioStreamPlaybackPolyphonic : public AudioStreamPlayback {
+ GDCLASS(AudioStreamPlaybackPolyphonic, AudioStreamPlayback)
+
+ enum {
+ INTERNAL_BUFFER_LEN = 128,
+ ID_MASK = 0xFFFFFFFF,
+ INDEX_SHIFT = 32
+ };
+ struct Stream {
+ SafeFlag active;
+ SafeFlag pending_play;
+ SafeFlag finish_request;
+ float play_offset = 0;
+ float pitch_scale = 1.0;
+ Ref<AudioStream> stream;
+ Ref<AudioStreamPlayback> stream_playback;
+ float prev_volume_db = 0;
+ float volume_db = 0;
+ uint32_t id = 0;
+
+ Stream() :
+ active(false), pending_play(false), finish_request(false) {}
+ };
+
+ LocalVector<Stream> streams;
+ AudioFrame internal_buffer[INTERNAL_BUFFER_LEN];
+
+ bool active = false;
+ uint32_t id_counter = 1;
+
+ _FORCE_INLINE_ Stream *_find_stream(int64_t p_id);
+
+ friend class AudioStreamPolyphonic;
+
+protected:
+ static void _bind_methods();
+
+public:
+ typedef int64_t ID;
+ enum {
+ INVALID_ID = -1
+ };
+
+ virtual void start(double p_from_pos = 0.0) override;
+ virtual void stop() override;
+ virtual bool is_playing() const override;
+
+ virtual int get_loop_count() const override; //times it looped
+
+ virtual double get_playback_position() const override;
+ virtual void seek(double p_time) override;
+
+ virtual void tag_used_streams() override;
+
+ virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
+
+ ID play_stream(const Ref<AudioStream> &p_stream, float p_from_offset = 0, float p_volume_db = 0, float p_pitch_scale = 1.0);
+ void set_stream_volume(ID p_stream_id, float p_volume_db);
+ void set_stream_pitch_scale(ID p_stream_id, float p_pitch_scale);
+ bool is_stream_playing(ID p_stream_id) const;
+ void stop_stream(ID p_stream_id);
+
+ AudioStreamPlaybackPolyphonic();
+};
+
+#endif // AUDIO_STREAM_POLYPHONIC_H
diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp
index b5e302cce5..61df56523d 100644
--- a/scene/resources/camera_attributes.cpp
+++ b/scene/resources/camera_attributes.cpp
@@ -286,10 +286,10 @@ void CameraAttributesPractical::_bind_methods() {
ADD_GROUP("DOF Blur", "dof_blur_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "-1,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "-1,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount");
ADD_GROUP("Auto Exposure", "auto_exposure_");
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 4d3eec6333..7a865691d9 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -53,7 +53,7 @@ static const int default_corner_radius = 3;
static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = default_margin, float p_margin_top = default_margin, float p_margin_right = default_margin, float p_margin_bottom = default_margin, int p_corner_radius = default_corner_radius, bool p_draw_center = true, int p_border_width = 0) {
Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
style->set_bg_color(p_color);
- style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
+ style->set_content_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
style->set_corner_radius_all(p_corner_radius);
style->set_anti_aliased(true);
@@ -67,10 +67,10 @@ static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left =
}
static Ref<StyleBoxFlat> sb_expand(Ref<StyleBoxFlat> p_sbox, float p_left, float p_top, float p_right, float p_bottom) {
- p_sbox->set_expand_margin_size(SIDE_LEFT, p_left * scale);
- p_sbox->set_expand_margin_size(SIDE_TOP, p_top * scale);
- p_sbox->set_expand_margin_size(SIDE_RIGHT, p_right * scale);
- p_sbox->set_expand_margin_size(SIDE_BOTTOM, p_bottom * scale);
+ p_sbox->set_expand_margin(SIDE_LEFT, p_left * scale);
+ p_sbox->set_expand_margin(SIDE_TOP, p_top * scale);
+ p_sbox->set_expand_margin(SIDE_RIGHT, p_right * scale);
+ p_sbox->set_expand_margin(SIDE_BOTTOM, p_bottom * scale);
return p_sbox;
}
@@ -93,7 +93,7 @@ static Ref<ImageTexture> generate_icon(int p_index) {
static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
Ref<StyleBox> style(memnew(StyleBoxEmpty));
- style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
+ style->set_content_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale);
return style;
}
@@ -148,7 +148,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
const Ref<StyleBoxFlat> button_disabled = make_flat_stylebox(style_disabled_color);
Ref<StyleBoxFlat> focus = make_flat_stylebox(style_focus_color, default_margin, default_margin, default_margin, default_margin, default_corner_radius, false, 2);
// Make the focus outline appear to be flush with the buttons it's focusing.
- focus->set_expand_margin_size_all(2 * scale);
+ focus->set_expand_margin_all(2 * scale);
theme->set_stylebox("normal", "Button", button_normal);
theme->set_stylebox("hover", "Button", button_hover);
@@ -279,9 +279,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// CheckBox
Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty);
- cbx_empty->set_default_margin_all(4 * scale);
+ cbx_empty->set_content_margin_all(4 * scale);
Ref<StyleBox> cbx_focus = focus;
- cbx_focus->set_default_margin_all(4 * scale);
+ cbx_focus->set_content_margin_all(4 * scale);
theme->set_stylebox("normal", "CheckBox", cbx_empty);
theme->set_stylebox("pressed", "CheckBox", cbx_empty);
@@ -317,7 +317,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// CheckButton
Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty);
- cb_empty->set_default_margin_individual(6 * scale, 4 * scale, 6 * scale, 4 * scale);
+ cb_empty->set_content_margin_individual(6 * scale, 4 * scale, 6 * scale, 4 * scale);
theme->set_stylebox("normal", "CheckButton", cb_empty);
theme->set_stylebox("pressed", "CheckButton", cb_empty);
@@ -634,10 +634,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
Ref<StyleBoxLine> separator_horizontal = memnew(StyleBoxLine);
separator_horizontal->set_thickness(Math::round(scale));
separator_horizontal->set_color(style_separator_color);
- separator_horizontal->set_default_margin_individual(default_margin, 0, default_margin, 0);
+ separator_horizontal->set_content_margin_individual(default_margin, 0, default_margin, 0);
Ref<StyleBoxLine> separator_vertical = separator_horizontal->duplicate();
separator_vertical->set_vertical(true);
- separator_vertical->set_default_margin_individual(0, default_margin, 0, default_margin);
+ separator_vertical->set_content_margin_individual(0, default_margin, 0, default_margin);
// Always display a border for PopupMenus so they can be distinguished from their background.
Ref<StyleBoxFlat> style_popup_panel = make_flat_stylebox(style_popup_color);
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index db7385428b..9c3a2ffb87 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -188,7 +188,7 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
if (shader.is_valid()) {
const StringName *sn = remap_cache.getptr(p_name);
if (sn) {
- // Only return a parameter if it was previosly set.
+ // Only return a parameter if it was previously set.
r_ret = get_shader_parameter(*sn);
return true;
}
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index cedf4319f8..991e060e94 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -189,6 +189,7 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
if (primitive == PRIMITIVE_TRIANGLES) {
for (int j = 0; j < ic; j++) {
int index = ir[j];
+ ERR_FAIL_COND_V(index >= vc, Ref<TriangleMesh>());
facesw[widx++] = vr[index];
}
} else { // PRIMITIVE_TRIANGLE_STRIP
@@ -1121,17 +1122,6 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
}
int idx = sname.substr(8, sl - 8).to_int();
- // This is a bit of a hack to ensure compatibility with older material
- // overrides that start indexing at 1.
- // We assume that idx 0 is always read first, if its not, this won't work.
- if (idx == 0) {
- surface_index_0 = true;
- }
- if (!surface_index_0) {
- // This means the file was created when the indexing started at 1, so decrease by one.
- idx--;
- }
-
String what = sname.get_slicec('/', 1);
if (what == "material") {
surface_set_material(idx, p_value);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index c24186a109..e497a628aa 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -1046,6 +1046,25 @@ Ref<SceneState> SceneState::get_base_scene_state() const {
return Ref<SceneState>();
}
+void SceneState::update_instance_resource(String p_path, Ref<PackedScene> p_packed_scene) {
+ ERR_FAIL_COND(p_packed_scene.is_null());
+
+ for (const NodeData &nd : nodes) {
+ if (nd.instance >= 0) {
+ if (!(nd.instance & FLAG_INSTANCE_IS_PLACEHOLDER)) {
+ int instance_id = nd.instance & FLAG_MASK;
+ Ref<PackedScene> original_packed_scene = variants[instance_id];
+ if (original_packed_scene.is_valid()) {
+ if (original_packed_scene->get_path() == p_path) {
+ variants.remove_at(instance_id);
+ variants.insert(instance_id, p_packed_scene);
+ }
+ }
+ }
+ }
+ }
+}
+
int SceneState::find_node_by_path(const NodePath &p_node) const {
ERR_FAIL_COND_V_MSG(node_path_cache.size() == 0, -1, "This operation requires the node cache to have been built.");
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index ef7363dd44..5c53ffdb45 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -150,6 +150,8 @@ public:
Ref<SceneState> get_base_scene_state() const;
+ void update_instance_resource(String p_path, Ref<PackedScene> p_packed_scene);
+
//unbuild API
int get_node_count() const;
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index 85106883f9..3bbd0a0b5e 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -325,7 +325,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
}
const Point &np = points[least_cost_point];
- //open the neighbours for search
+ //open the neighbors for search
for (const int &E : np.connections) {
Point &p = points.write[E];
@@ -339,7 +339,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
p.distance = distance;
}
} else {
- //add to open neighbours
+ //add to open neighbors
p.prev = least_cost_point;
p.distance = distance;
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 6390850b24..4f16986392 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -34,76 +34,65 @@
#include <limits.h>
-float StyleBox::get_style_margin(Side p_side) const {
- float ret = 0;
- GDVIRTUAL_REQUIRED_CALL(_get_style_margin, p_side, ret);
- return ret;
-}
+Size2 StyleBox::get_minimum_size() const {
+ Size2 min_size = Size2(get_margin(SIDE_LEFT) + get_margin(SIDE_RIGHT), get_margin(SIDE_TOP) + get_margin(SIDE_BOTTOM));
+ Size2 custom_size;
+ GDVIRTUAL_CALL(_get_minimum_size, custom_size);
-bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const {
- bool ret = true;
- GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret);
- return ret;
-}
+ if (min_size.x < custom_size.x) {
+ min_size.x = custom_size.x;
+ }
+ if (min_size.y < custom_size.y) {
+ min_size.y = custom_size.y;
+ }
-void StyleBox::draw(RID p_canvas_item, const Rect2 &p_rect) const {
- GDVIRTUAL_REQUIRED_CALL(_draw, p_canvas_item, p_rect);
+ return min_size;
}
-void StyleBox::set_default_margin(Side p_side, float p_value) {
+void StyleBox::set_content_margin(Side p_side, float p_value) {
ERR_FAIL_INDEX((int)p_side, 4);
- margin[p_side] = p_value;
+ content_margin[p_side] = p_value;
emit_changed();
}
-void StyleBox::set_default_margin_all(float p_value) {
+void StyleBox::set_content_margin_all(float p_value) {
for (int i = 0; i < 4; i++) {
- margin[i] = p_value;
+ content_margin[i] = p_value;
}
emit_changed();
}
-void StyleBox::set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
- margin[SIDE_LEFT] = p_left;
- margin[SIDE_TOP] = p_top;
- margin[SIDE_RIGHT] = p_right;
- margin[SIDE_BOTTOM] = p_bottom;
+void StyleBox::set_content_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ content_margin[SIDE_LEFT] = p_left;
+ content_margin[SIDE_TOP] = p_top;
+ content_margin[SIDE_RIGHT] = p_right;
+ content_margin[SIDE_BOTTOM] = p_bottom;
emit_changed();
}
-float StyleBox::get_default_margin(Side p_side) const {
+float StyleBox::get_content_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
- return margin[p_side];
+ return content_margin[p_side];
}
float StyleBox::get_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
- if (margin[p_side] < 0) {
+ if (content_margin[p_side] < 0) {
return get_style_margin(p_side);
} else {
- return margin[p_side];
+ return content_margin[p_side];
}
}
-CanvasItem *StyleBox::get_current_item_drawn() const {
- return CanvasItem::get_current_item_drawn();
-}
-
-Size2 StyleBox::get_minimum_size() const {
- return Size2(get_margin(SIDE_LEFT) + get_margin(SIDE_RIGHT), get_margin(SIDE_TOP) + get_margin(SIDE_BOTTOM));
-}
-
Point2 StyleBox::get_offset() const {
return Point2(get_margin(SIDE_LEFT), get_margin(SIDE_TOP));
}
-Size2 StyleBox::get_center_size() const {
- Size2 ret;
- GDVIRTUAL_CALL(_get_center_size, ret);
- return ret;
+void StyleBox::draw(RID p_canvas_item, const Rect2 &p_rect) const {
+ GDVIRTUAL_REQUIRED_CALL(_draw, p_canvas_item, p_rect);
}
Rect2 StyleBox::get_draw_rect(const Rect2 &p_rect) const {
@@ -114,37 +103,46 @@ Rect2 StyleBox::get_draw_rect(const Rect2 &p_rect) const {
return p_rect;
}
+CanvasItem *StyleBox::get_current_item_drawn() const {
+ return CanvasItem::get_current_item_drawn();
+}
+
+bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const {
+ bool ret = true;
+ GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret);
+ return ret;
+}
+
void StyleBox::_bind_methods() {
- ClassDB::bind_method(D_METHOD("test_mask", "point", "rect"), &StyleBox::test_mask);
+ ClassDB::bind_method(D_METHOD("get_minimum_size"), &StyleBox::get_minimum_size);
- ClassDB::bind_method(D_METHOD("set_default_margin", "margin", "offset"), &StyleBox::set_default_margin);
- ClassDB::bind_method(D_METHOD("set_default_margin_all", "offset"), &StyleBox::set_default_margin_all);
- ClassDB::bind_method(D_METHOD("get_default_margin", "margin"), &StyleBox::get_default_margin);
+ ClassDB::bind_method(D_METHOD("set_content_margin", "margin", "offset"), &StyleBox::set_content_margin);
+ ClassDB::bind_method(D_METHOD("set_content_margin_all", "offset"), &StyleBox::set_content_margin_all);
+ ClassDB::bind_method(D_METHOD("get_content_margin", "margin"), &StyleBox::get_content_margin);
ClassDB::bind_method(D_METHOD("get_margin", "margin"), &StyleBox::get_margin);
- ClassDB::bind_method(D_METHOD("get_minimum_size"), &StyleBox::get_minimum_size);
- ClassDB::bind_method(D_METHOD("get_center_size"), &StyleBox::get_center_size);
ClassDB::bind_method(D_METHOD("get_offset"), &StyleBox::get_offset);
- ClassDB::bind_method(D_METHOD("get_current_item_drawn"), &StyleBox::get_current_item_drawn);
ClassDB::bind_method(D_METHOD("draw", "canvas_item", "rect"), &StyleBox::draw);
+ ClassDB::bind_method(D_METHOD("get_current_item_drawn"), &StyleBox::get_current_item_drawn);
+
+ ClassDB::bind_method(D_METHOD("test_mask", "point", "rect"), &StyleBox::test_mask);
ADD_GROUP("Content Margins", "content_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_default_margin", "get_default_margin", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_content_margin", "get_content_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_content_margin", "get_content_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_content_margin", "get_content_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1,suffix:px"), "set_content_margin", "get_content_margin", SIDE_BOTTOM);
- GDVIRTUAL_BIND(_get_style_margin, "side")
- GDVIRTUAL_BIND(_test_mask, "point", "rect")
- GDVIRTUAL_BIND(_get_center_size)
- GDVIRTUAL_BIND(_get_draw_rect, "rect")
GDVIRTUAL_BIND(_draw, "to_canvas_item", "rect")
+ GDVIRTUAL_BIND(_get_draw_rect, "rect")
+ GDVIRTUAL_BIND(_get_minimum_size)
+ GDVIRTUAL_BIND(_test_mask, "point", "rect")
}
StyleBox::StyleBox() {
for (int i = 0; i < 4; i++) {
- margin[i] = -1;
+ content_margin[i] = -1;
}
}
@@ -165,38 +163,38 @@ Ref<Texture2D> StyleBoxTexture::get_texture() const {
return texture;
}
-void StyleBoxTexture::set_margin_size(Side p_side, float p_size) {
+void StyleBoxTexture::set_texture_margin(Side p_side, float p_size) {
ERR_FAIL_INDEX((int)p_side, 4);
- margin[p_side] = p_size;
+ texture_margin[p_side] = p_size;
emit_changed();
}
-void StyleBoxTexture::set_margin_size_all(float p_size) {
+void StyleBoxTexture::set_texture_margin_all(float p_size) {
for (int i = 0; i < 4; i++) {
- margin[i] = p_size;
+ texture_margin[i] = p_size;
}
emit_changed();
}
-void StyleBoxTexture::set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) {
- margin[SIDE_LEFT] = p_left;
- margin[SIDE_TOP] = p_top;
- margin[SIDE_RIGHT] = p_right;
- margin[SIDE_BOTTOM] = p_bottom;
+void StyleBoxTexture::set_texture_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
+ texture_margin[SIDE_LEFT] = p_left;
+ texture_margin[SIDE_TOP] = p_top;
+ texture_margin[SIDE_RIGHT] = p_right;
+ texture_margin[SIDE_BOTTOM] = p_bottom;
emit_changed();
}
-float StyleBoxTexture::get_margin_size(Side p_side) const {
+float StyleBoxTexture::get_texture_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
- return margin[p_side];
+ return texture_margin[p_side];
}
float StyleBoxTexture::get_style_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
- return margin[p_side];
+ return texture_margin[p_side];
}
Rect2 StyleBoxTexture::get_draw_rect(const Rect2 &p_rect) const {
@@ -218,7 +216,10 @@ void StyleBoxTexture::draw(RID p_canvas_item, const Rect2 &p_rect) const {
rect.size.x += expand_margin[SIDE_LEFT] + expand_margin[SIDE_RIGHT];
rect.size.y += expand_margin[SIDE_TOP] + expand_margin[SIDE_BOTTOM];
- RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), Vector2(margin[SIDE_LEFT], margin[SIDE_TOP]), Vector2(margin[SIDE_RIGHT], margin[SIDE_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate);
+ Vector2 start_offset = Vector2(texture_margin[SIDE_LEFT], texture_margin[SIDE_TOP]);
+ Vector2 end_offset = Vector2(texture_margin[SIDE_RIGHT], texture_margin[SIDE_BOTTOM]);
+
+ RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), start_offset, end_offset, RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate);
}
void StyleBoxTexture::set_draw_center(bool p_enabled) {
@@ -230,21 +231,29 @@ bool StyleBoxTexture::is_draw_center_enabled() const {
return draw_center;
}
-Size2 StyleBoxTexture::get_center_size() const {
- if (texture.is_null()) {
- return Size2();
+Size2 StyleBoxTexture::get_minimum_size() const {
+ Size2 min_size = StyleBox::get_minimum_size();
+
+ // Make sure that the min size is no smaller than the used texture region.
+ if (texture.is_valid()) {
+ if (min_size.x < region_rect.size.x) {
+ min_size.x = region_rect.size.x;
+ }
+ if (min_size.y < region_rect.size.y) {
+ min_size.y = region_rect.size.y;
+ }
}
- return region_rect.size - get_minimum_size();
+ return min_size;
}
-void StyleBoxTexture::set_expand_margin_size(Side p_side, float p_size) {
+void StyleBoxTexture::set_expand_margin(Side p_side, float p_size) {
ERR_FAIL_INDEX((int)p_side, 4);
expand_margin[p_side] = p_size;
emit_changed();
}
-void StyleBoxTexture::set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) {
+void StyleBoxTexture::set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
expand_margin[SIDE_LEFT] = p_left;
expand_margin[SIDE_TOP] = p_top;
expand_margin[SIDE_RIGHT] = p_right;
@@ -252,14 +261,14 @@ void StyleBoxTexture::set_expand_margin_size_individual(float p_left, float p_to
emit_changed();
}
-void StyleBoxTexture::set_expand_margin_size_all(float p_expand_margin_size) {
+void StyleBoxTexture::set_expand_margin_all(float p_expand_margin_size) {
for (int i = 0; i < 4; i++) {
expand_margin[i] = p_expand_margin_size;
}
emit_changed();
}
-float StyleBoxTexture::get_expand_margin_size(Side p_side) const {
+float StyleBoxTexture::get_expand_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0);
return expand_margin[p_side];
}
@@ -313,13 +322,13 @@ void StyleBoxTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &StyleBoxTexture::set_texture);
ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture);
- ClassDB::bind_method(D_METHOD("set_margin_size", "margin", "size"), &StyleBoxTexture::set_margin_size);
- ClassDB::bind_method(D_METHOD("set_margin_size_all", "size"), &StyleBoxTexture::set_margin_size_all);
- ClassDB::bind_method(D_METHOD("get_margin_size", "margin"), &StyleBoxTexture::get_margin_size);
+ ClassDB::bind_method(D_METHOD("set_texture_margin", "margin", "size"), &StyleBoxTexture::set_texture_margin);
+ ClassDB::bind_method(D_METHOD("set_texture_margin_all", "size"), &StyleBoxTexture::set_texture_margin_all);
+ ClassDB::bind_method(D_METHOD("get_texture_margin", "margin"), &StyleBoxTexture::get_texture_margin);
- ClassDB::bind_method(D_METHOD("set_expand_margin_size", "margin", "size"), &StyleBoxTexture::set_expand_margin_size);
- ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_size_all);
- ClassDB::bind_method(D_METHOD("get_expand_margin_size", "margin"), &StyleBoxTexture::get_expand_margin_size);
+ ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxTexture::set_expand_margin);
+ ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_all);
+ ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxTexture::get_expand_margin);
ClassDB::bind_method(D_METHOD("set_region_rect", "region"), &StyleBoxTexture::set_region_rect);
ClassDB::bind_method(D_METHOD("get_region_rect"), &StyleBoxTexture::get_region_rect);
@@ -338,17 +347,17 @@ void StyleBoxTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
- ADD_GROUP("Margins", "margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_margin_size", "get_margin_size", SIDE_BOTTOM);
+ ADD_GROUP("Texture Margins", "texture_margin_");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "texture_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_texture_margin", "get_texture_margin", SIDE_BOTTOM);
ADD_GROUP("Expand Margins", "expand_margin_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin_size", "get_expand_margin_size", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1,suffix:px"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM);
ADD_GROUP("Axis Stretch", "axis_stretch_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode");
@@ -450,13 +459,13 @@ int StyleBoxFlat::get_corner_radius(const Corner p_corner) const {
return corner_radius[p_corner];
}
-void StyleBoxFlat::set_expand_margin_size(Side p_side, float p_size) {
+void StyleBoxFlat::set_expand_margin(Side p_side, float p_size) {
ERR_FAIL_INDEX((int)p_side, 4);
expand_margin[p_side] = p_size;
emit_changed();
}
-void StyleBoxFlat::set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) {
+void StyleBoxFlat::set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom) {
expand_margin[SIDE_LEFT] = p_left;
expand_margin[SIDE_TOP] = p_top;
expand_margin[SIDE_RIGHT] = p_right;
@@ -464,14 +473,14 @@ void StyleBoxFlat::set_expand_margin_size_individual(float p_left, float p_top,
emit_changed();
}
-void StyleBoxFlat::set_expand_margin_size_all(float p_expand_margin_size) {
+void StyleBoxFlat::set_expand_margin_all(float p_expand_margin_size) {
for (int i = 0; i < 4; i++) {
expand_margin[i] = p_expand_margin_size;
}
emit_changed();
}
-float StyleBoxFlat::get_expand_margin_size(Side p_side) const {
+float StyleBoxFlat::get_expand_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0.0);
return expand_margin[p_side];
}
@@ -549,10 +558,6 @@ int StyleBoxFlat::get_corner_detail() const {
return corner_detail;
}
-Size2 StyleBoxFlat::get_center_size() const {
- return Size2();
-}
-
inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_rect, const real_t corner_radius[4], real_t *inner_corner_radius) {
real_t border_left = inner_rect.position.x - style_rect.position.x;
real_t border_top = inner_rect.position.y - style_rect.position.y;
@@ -891,9 +896,9 @@ void StyleBoxFlat::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_corner_radius", "corner", "radius"), &StyleBoxFlat::set_corner_radius);
ClassDB::bind_method(D_METHOD("get_corner_radius", "corner"), &StyleBoxFlat::get_corner_radius);
- ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin_size);
- ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_size_all);
- ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin_size);
+ ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin);
+ ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_all);
+ ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin);
ClassDB::bind_method(D_METHOD("set_draw_center", "draw_center"), &StyleBoxFlat::set_draw_center);
ClassDB::bind_method(D_METHOD("is_draw_center_enabled"), &StyleBoxFlat::is_draw_center_enabled);
@@ -1041,10 +1046,6 @@ float StyleBoxLine::get_style_margin(Side p_side) const {
return 0;
}
-Size2 StyleBoxLine::get_center_size() const {
- return Size2();
-}
-
void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const {
RenderingServer *vs = RenderingServer::get_singleton();
Rect2i r = p_rect;
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 5a80b4d4e2..91033617ab 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -41,36 +41,34 @@ class StyleBox : public Resource {
GDCLASS(StyleBox, Resource);
RES_BASE_EXTENSION("stylebox");
OBJ_SAVE_TYPE(StyleBox);
- float margin[4];
+ float content_margin[4];
protected:
- virtual float get_style_margin(Side p_side) const;
+ virtual float get_style_margin(Side p_side) const { return 0; }
static void _bind_methods();
- GDVIRTUAL1RC(float, _get_style_margin, Side)
- GDVIRTUAL2RC(bool, _test_mask, Point2, Rect2)
- GDVIRTUAL0RC(Size2, _get_center_size)
- GDVIRTUAL1RC(Rect2, _get_draw_rect, Rect2)
GDVIRTUAL2C(_draw, RID, Rect2)
+ GDVIRTUAL1RC(Rect2, _get_draw_rect, Rect2)
+ GDVIRTUAL0RC(Size2, _get_minimum_size)
+ GDVIRTUAL2RC(bool, _test_mask, Point2, Rect2)
public:
- virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const;
+ virtual Size2 get_minimum_size() const;
- void set_default_margin(Side p_side, float p_value);
- void set_default_margin_all(float p_value);
- void set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
- float get_default_margin(Side p_side) const;
+ void set_content_margin(Side p_side, float p_value);
+ void set_content_margin_all(float p_value);
+ void set_content_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
+ float get_content_margin(Side p_side) const;
float get_margin(Side p_side) const;
- virtual Size2 get_center_size() const;
+ Point2 get_offset() const;
- virtual Rect2 get_draw_rect(const Rect2 &p_rect) const;
virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const;
+ virtual Rect2 get_draw_rect(const Rect2 &p_rect) const;
CanvasItem *get_current_item_drawn() const;
- Size2 get_minimum_size() const;
- Point2 get_offset() const;
+ virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const;
StyleBox();
};
@@ -96,7 +94,7 @@ public:
private:
float expand_margin[4] = {};
- float margin[4] = {};
+ float texture_margin[4] = {};
Rect2 region_rect;
Ref<Texture2D> texture;
bool draw_center = true;
@@ -109,15 +107,17 @@ protected:
static void _bind_methods();
public:
- void set_expand_margin_size(Side p_expand_side, float p_size);
- void set_expand_margin_size_all(float p_expand_margin_size);
- void set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom);
- float get_expand_margin_size(Side p_expand_side) const;
+ virtual Size2 get_minimum_size() const override;
- void set_margin_size(Side p_side, float p_size);
- void set_margin_size_all(float p_size);
- void set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom);
- float get_margin_size(Side p_side) const;
+ void set_expand_margin(Side p_expand_side, float p_size);
+ void set_expand_margin_all(float p_expand_margin_size);
+ void set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
+ float get_expand_margin(Side p_expand_side) const;
+
+ void set_texture_margin(Side p_side, float p_size);
+ void set_texture_margin_all(float p_size);
+ void set_texture_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
+ float get_texture_margin(Side p_side) const;
void set_region_rect(const Rect2 &p_region_rect);
Rect2 get_region_rect() const;
@@ -127,7 +127,6 @@ public:
void set_draw_center(bool p_enabled);
bool is_draw_center_enabled() const;
- virtual Size2 get_center_size() const override;
void set_h_axis_stretch_mode(AxisStretchMode p_mode);
AxisStretchMode get_h_axis_stretch_mode() const;
@@ -198,10 +197,10 @@ public:
void set_corner_detail(const int &p_corner_detail);
int get_corner_detail() const;
- void set_expand_margin_size(Side p_expand_side, float p_size);
- void set_expand_margin_size_all(float p_expand_margin_size);
- void set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom);
- float get_expand_margin_size(Side p_expand_side) const;
+ void set_expand_margin(Side p_expand_side, float p_size);
+ void set_expand_margin_all(float p_expand_margin_size);
+ void set_expand_margin_individual(float p_left, float p_top, float p_right, float p_bottom);
+ float get_expand_margin(Side p_expand_side) const;
void set_draw_center(bool p_enabled);
bool is_draw_center_enabled() const;
@@ -223,8 +222,6 @@ public:
void set_aa_size(const real_t p_aa_size);
real_t get_aa_size() const;
- virtual Size2 get_center_size() const override;
-
virtual Rect2 get_draw_rect(const Rect2 &p_rect) const override;
virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override;
@@ -261,8 +258,6 @@ public:
void set_grow_end(float p_grow);
float get_grow_end() const;
- virtual Size2 get_center_size() const override;
-
virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override;
StyleBoxLine();
diff --git a/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl b/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl
index 134aae5ce7..b1ff46dd3b 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl
@@ -56,7 +56,7 @@ vec4 screen_space_to_view_space_depth(vec4 p_depth) {
float depth_linearize_mul = params.z_near;
float depth_linearize_add = params.z_far;
- // Optimised version of "-cameraClipNear / (cameraClipFar - projDepth * (cameraClipFar - cameraClipNear)) * cameraClipFar"
+ // Optimized version of "-cameraClipNear / (cameraClipFar - projDepth * (cameraClipFar - cameraClipNear)) * cameraClipFar"
// Set your depth_linearize_mul and depth_linearize_add to:
// depth_linearize_mul = ( cameraClipFar * cameraClipNear) / ( cameraClipFar - cameraClipNear );
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssao.glsl b/servers/rendering/renderer_rd/shaders/effects/ssao.glsl
index 2a87e273bc..ffaa6872c9 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssao.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssao.glsl
@@ -221,7 +221,7 @@ void SSAOTap(const int p_quality_level, inout float r_obscurance_sum, inout floa
// snap to pixel center (more correct obscurance math, avoids artifacts)
sample_offset = round(sample_offset);
- // calculate MIP based on the sample distance from the centre, similar to as described
+ // calculate MIP based on the sample distance from the center, similar to as described
// in http://graphics.cs.williams.edu/papers/SAOHPG12/.
float mip_level = (p_quality_level < SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (sample_pow_2_len + p_mip_offset);
@@ -259,7 +259,7 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o
// get this pixel's viewspace depth
pix_z = valuesUL.y;
- // get left right top bottom neighbouring pixels for edge detection (gets compiled out on quality_level == 0)
+ // get left right top bottom neighboring pixels for edge detection (gets compiled out on quality_level == 0)
pix_left_z = valuesUL.x;
pix_top_z = valuesUL.z;
pix_right_z = valuesBR.z;
@@ -304,7 +304,7 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o
float obscurance_sum = 0.0;
float weight_sum = 0.0;
- // edge mask for between this and left/right/top/bottom neighbour pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge)
+ // edge mask for between this and left/right/top/bottom neighbor pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge)
vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0);
// Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer; a lot smaller offsets needed when using 32bit floats
@@ -318,7 +318,7 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o
if (!p_adaptive_base && (p_quality_level >= SSAO_DETAIL_AO_ENABLE_AT_QUALITY_PRESET)) {
// disable in case of quality level 4 (reference)
if (p_quality_level != 4) {
- //approximate neighbouring pixels positions (actually just deltas or "positions - pix_center_pos" )
+ //approximate neighboring pixels positions (actually just deltas or "positions - pix_center_pos" )
vec3 normalized_viewspace_dir = vec3(pix_center_pos.xy / pix_center_pos.zz, 1.0);
vec3 pixel_left_delta = vec3(-pixel_size_at_center.x, 0.0, 0.0) + normalized_viewspace_dir * (pix_left_z - pix_center_pos.z);
vec3 pixel_right_delta = vec3(+pixel_size_at_center.x, 0.0, 0.0) + normalized_viewspace_dir * (pix_right_z - pix_center_pos.z);
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl b/servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl
index 04f98964e8..d234ab4417 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl
@@ -80,7 +80,7 @@ void main() {
#ifdef PROCESS_MAPA
vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0;
- float centre = textureLod(source_importance, uv, 0.0).x;
+ float center = textureLod(source_importance, uv, 0.0).x;
vec2 half_pixel = params.half_screen_pixel_size;
@@ -98,7 +98,7 @@ void main() {
#ifdef PROCESS_MAPB
vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0;
- float centre = textureLod(source_importance, uv, 0.0).x;
+ float center = textureLod(source_importance, uv, 0.0).x;
vec2 half_pixel = params.half_screen_pixel_size;
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl b/servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl
index f6a9a92fac..45cc62d361 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl
@@ -60,8 +60,8 @@ void main() {
int mx = int(pix_pos.x % 2);
int my = int(pix_pos.y % 2);
int index_center = mx + my * 2; // center index
- int index_horizontal = (1 - mx) + my * 2; // neighbouring, horizontal
- int index_vertical = mx + (1 - my) * 2; // neighbouring, vertical
+ int index_horizontal = (1 - mx) + my * 2; // neighboring, horizontal
+ int index_vertical = mx + (1 - my) * 2; // neighboring, vertical
int index_diagonal = (1 - mx) + (1 - my) * 2; // diagonal
vec2 center_val = texelFetch(source_texture, ivec3(pix_pos / uvec2(params.size_modifier), index_center), 0).xy;
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssil.glsl b/servers/rendering/renderer_rd/shaders/effects/ssil.glsl
index 513791dfbf..de7b97953f 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssil.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssil.glsl
@@ -234,7 +234,7 @@ void SSILTap(const int p_quality_level, inout vec3 r_color_sum, inout float r_ob
// snap to pixel center (more correct obscurance math, avoids artifacts)
sample_offset = round(sample_offset);
- // calculate MIP based on the sample distance from the centre, similar to as described
+ // calculate MIP based on the sample distance from the center, similar to as described
// in http://graphics.cs.williams.edu/papers/SAOHPG12/.
float mip_level = (p_quality_level < SSIL_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (sample_pow_2_len + p_mip_offset);
@@ -272,7 +272,7 @@ void generate_SSIL(out vec3 r_color, out vec4 r_edges, out float r_obscurance, o
// get this pixel's viewspace depth
pix_z = valuesUL.y;
- // get left right top bottom neighbouring pixels for edge detection (gets compiled out on quality_level == 0)
+ // get left right top bottom neighboring pixels for edge detection (gets compiled out on quality_level == 0)
pix_left_z = valuesUL.x;
pix_top_z = valuesUL.z;
pix_right_z = valuesBR.z;
@@ -318,7 +318,7 @@ void generate_SSIL(out vec3 r_color, out vec4 r_edges, out float r_obscurance, o
float obscurance_sum = 0.0;
float weight_sum = 0.0;
- // edge mask for between this and left/right/top/bottom neighbour pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge)
+ // edge mask for between this and left/right/top/bottom neighbor pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge)
vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0);
// Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer; a lot smaller offsets needed when using 32bit floats
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl b/servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl
index 47c56571f6..f48e6c4341 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl
@@ -124,14 +124,14 @@ void main() {
vec2 uv = (vec2(gl_GlobalInvocationID.xy) + vec2(0.5, 0.5)) * params.half_screen_pixel_size;
- vec4 centre = textureLod(source_ssil, uv, 0.0);
+ vec4 center = textureLod(source_ssil, uv, 0.0);
vec4 value = textureLod(source_ssil, vec2(uv + vec2(-half_pixel.x * 3, -half_pixel.y)), 0.0) * 0.2;
value += textureLod(source_ssil, vec2(uv + vec2(+half_pixel.x, -half_pixel.y * 3)), 0.0) * 0.2;
value += textureLod(source_ssil, vec2(uv + vec2(-half_pixel.x, +half_pixel.y * 3)), 0.0) * 0.2;
value += textureLod(source_ssil, vec2(uv + vec2(+half_pixel.x * 3, +half_pixel.y)), 0.0) * 0.2;
- vec4 sampled = value + centre * 0.2;
+ vec4 sampled = value + center * 0.2;
#else
#ifdef MODE_SMART
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl b/servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl
index 6b6b02739d..193e3458ab 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl
@@ -82,7 +82,7 @@ void main() {
#ifdef PROCESS_MAPA
vec2 uv = (vec2(ssC) + 0.5) * params.half_screen_pixel_size * 2.0;
- float centre = textureLod(source_importance, uv, 0.0).x;
+ float center = textureLod(source_importance, uv, 0.0).x;
vec2 half_pixel = params.half_screen_pixel_size;
@@ -100,7 +100,7 @@ void main() {
#ifdef PROCESS_MAPB
vec2 uv = (vec2(ssC) + 0.5f) * params.half_screen_pixel_size * 2.0;
- float centre = textureLod(source_importance, uv, 0.0).x;
+ float center = textureLod(source_importance, uv, 0.0).x;
vec2 half_pixel = params.half_screen_pixel_size;
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl b/servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl
index 9e86ac0cf0..ed85b8ee4c 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl
@@ -62,8 +62,8 @@ void main() {
int mx = int(pix_pos.x % 2);
int my = int(pix_pos.y % 2);
int index_center = mx + my * 2; // center index
- int index_horizontal = (1 - mx) + my * 2; // neighbouring, horizontal
- int index_vertical = mx + (1 - my) * 2; // neighbouring, vertical
+ int index_horizontal = (1 - mx) + my * 2; // neighboring, horizontal
+ int index_vertical = mx + (1 - my) * 2; // neighboring, vertical
int index_diagonal = (1 - mx) + (1 - my) * 2; // diagonal
vec4 color = texelFetch(source_texture, ivec3(pix_pos / uvec2(params.size_modifier), index_center), 0);
diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl
index 9f7449b8aa..06709f65d3 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl
@@ -24,7 +24,7 @@ struct ProcessVoxel {
uint albedo; // rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbors.
uint light; // rgbe8985 encoded total saved light, extra 2 bits for neighbors.
uint light_aniso; // 55555 light anisotropy, extra 2 bits for neighbors.
- //total neighbours: 26
+ //total neighbors: 26
};
#ifdef MODE_PROCESS_STATIC
@@ -443,10 +443,10 @@ void main() {
imageStore(dst_aniso1, positioni, vec4(aniso1, 0.0, 0.0));
imageStore(dst_light, positioni, uvec4(light_total_rgbe));
- //also fill neighbours, so light interpolation during the indirect pass works
+ //also fill neighbors, so light interpolation during the indirect pass works
- //recover the neighbour list from the leftover bits
- uint neighbours = (voxel_albedo >> 21) | ((voxel_position >> 21) << 11) | ((process_voxels.data[voxel_index].light >> 30) << 22) | ((process_voxels.data[voxel_index].light_aniso >> 30) << 24);
+ //recover the neighbor list from the leftover bits
+ uint neighbors = (voxel_albedo >> 21) | ((voxel_position >> 21) << 11) | ((process_voxels.data[voxel_index].light >> 30) << 22) | ((process_voxels.data[voxel_index].light_aniso >> 30) << 24);
const uint max_neighbours = 26;
const ivec3 neighbour_positions[max_neighbours] = ivec3[](
@@ -478,7 +478,7 @@ void main() {
ivec3(1, 1, 1));
for (uint i = 0; i < max_neighbours; i++) {
- if (bool(neighbours & (1 << i))) {
+ if (bool(neighbors & (1 << i))) {
ivec3 neighbour_pos = positioni + neighbour_positions[i];
imageStore(dst_light, neighbour_pos, uvec4(light_total_rgbe));
imageStore(dst_aniso0, neighbour_pos, aniso0);
diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl
index bce98f4054..dd35ae3b73 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl
@@ -102,10 +102,10 @@ dispatch_data;
struct ProcessVoxel {
uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
- uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbours
- uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
- uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
- //total neighbours: 26
+ uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbors
+ uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbors
+ uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbors
+ //total neighbors: 26
};
layout(set = 0, binding = 11, std430) restrict buffer writeonly ProcessVoxels {
@@ -135,10 +135,10 @@ dispatch_data;
struct ProcessVoxel {
uint position; // xyz 7 bit packed, extra 11 bits for neighbors.
- uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbours
- uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbours
- uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbours
- //total neighbours: 26
+ uint albedo; //rgb bits 0-15 albedo, bits 16-21 are normal bits (set if geometry exists toward that side), extra 11 bits for neighbors
+ uint light; //rgbe8985 encoded total saved light, extra 2 bits for neighbors
+ uint light_aniso; //55555 light anisotropy, extra 2 bits for neighbors
+ //total neighbors: 26
};
layout(set = 0, binding = 6, std430) restrict buffer readonly ProcessVoxels {
@@ -1016,14 +1016,14 @@ void main() {
store_positions[index].albedo = rgb >> 1; //store as it comes (555) to avoid precision loss (and move away the alpha bit)
store_positions[index].albedo |= (facing & 0x3F) << 15; // store facing in bits 15-21
- store_positions[index].albedo |= neighbour_bits << 21; //store lower 11 bits of neighbours with remaining albedo
- store_positions[index].position |= (neighbour_bits >> 11) << 21; //store 11 bits more of neighbours with position
+ store_positions[index].albedo |= neighbour_bits << 21; //store lower 11 bits of neighbors with remaining albedo
+ store_positions[index].position |= (neighbour_bits >> 11) << 21; //store 11 bits more of neighbors with position
store_positions[index].light = imageLoad(src_light, pos).r;
store_positions[index].light_aniso = imageLoad(src_light_aniso, pos).r;
- //add neighbours
- store_positions[index].light |= (neighbour_bits >> 22) << 30; //store 2 bits more of neighbours with light
- store_positions[index].light_aniso |= (neighbour_bits >> 24) << 30; //store 2 bits more of neighbours with aniso
+ //add neighbors
+ store_positions[index].light |= (neighbour_bits >> 22) << 30; //store 2 bits more of neighbors with light
+ store_positions[index].light_aniso |= (neighbour_bits >> 24) << 30; //store 2 bits more of neighbors with aniso
}
groupMemoryBarrier();
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index d32e6d717f..51e503b5b3 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -1351,8 +1351,8 @@ void fragment_shader(in SceneData scene_data) {
#endif // USE_MULTIVIEW
for (int i = 0; i < 4; i++) {
- const vec2 neighbours[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1));
- vec2 neighbour_coord = base_coord + neighbours[i] * scene_data.screen_pixel_size;
+ const vec2 neighbors[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1));
+ vec2 neighbour_coord = base_coord + neighbors[i] * scene_data.screen_pixel_size;
#ifdef USE_MULTIVIEW
float neighbour_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(neighbour_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
#else // USE_MULTIVIEW
@@ -1798,7 +1798,7 @@ void fragment_shader(in SceneData scene_data) {
shadow = float(shadow1 >> ((i - 4u) * 8u) & 0xFFu) / 255.0;
}
- shadow = shadow * directional_lights.data[i].shadow_opacity + 1.0 - directional_lights.data[i].shadow_opacity;
+ shadow = mix(1.0, shadow, directional_lights.data[i].shadow_opacity);
#endif
blur_shadow(shadow);
@@ -2082,7 +2082,7 @@ void fragment_shader(in SceneData scene_data) {
float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
- //store as 8985 to have 2 extra neighbour bits
+ //store as 8985 to have 2 extra neighbor bits
uint light_rgbe = ((uint(sRed) & 0x1FFu) >> 1) | ((uint(sGreen) & 0x1FFu) << 8) | (((uint(sBlue) & 0x1FFu) >> 1) << 17) | ((uint(exps) & 0x1Fu) << 25);
imageStore(emission_grid, grid_pos, uvec4(light_rgbe));
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index 5e64d4e651..2966a2ff65 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -1515,6 +1515,8 @@ void main() {
} else {
shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
}
+
+ shadow = mix(1.0, shadow, directional_lights.data[i].shadow_opacity);
#endif
blur_shadow(shadow);
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index 31377a10a0..7771f75a65 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -251,7 +251,7 @@ RID RenderSceneBuffersRD::create_texture(const StringName &p_context, const Stri
}
RID RenderSceneBuffersRD::create_texture_from_format(const StringName &p_context, const StringName &p_texture_name, const RD::TextureFormat &p_texture_format, RD::TextureView p_view, bool p_unique) {
- // TODO p_unique, if p_unique is true, this is a texture that can be shared. This will be implemented later as an optimisation.
+ // TODO p_unique, if p_unique is true, this is a texture that can be shared. This will be implemented later as an optimization.
NTKey key(p_context, p_texture_name);
diff --git a/servers/xr_server.h b/servers/xr_server.h
index 086a18c111..04cf6c1d1e 100644
--- a/servers/xr_server.h
+++ b/servers/xr_server.h
@@ -111,7 +111,7 @@ public:
Most VR platforms, and our assumption, is that 1 unit in our virtual world equates to 1 meter in the real mode.
This scale basically effects the unit size relationship to real world size.
- I may remove access to this property in GDScript in favour of exposing it on the XROrigin3D node
+ I may remove access to this property in GDScript in favor of exposing it on the XROrigin3D node
*/
double get_world_scale() const;
void set_world_scale(double p_world_scale);
diff --git a/tests/core/input/test_input_event_key.h b/tests/core/input/test_input_event_key.h
index 697215bab7..3317941fad 100644
--- a/tests/core/input/test_input_event_key.h
+++ b/tests/core/input/test_input_event_key.h
@@ -106,11 +106,11 @@ TEST_CASE("[InputEventKey] Key correctly converts itself to text") {
// Key is None without a physical key.
none_key.set_keycode(Key::NONE);
- CHECK(none_key.as_text() == " (Physical)");
+ CHECK(none_key.as_text() == "(Unset)");
// Key is none and has modifiers.
none_key.set_ctrl_pressed(true);
- CHECK(none_key.as_text() == "Ctrl+ (Physical)");
+ CHECK(none_key.as_text() == "Ctrl+(Unset)");
// Key is None WITH a physical key AND modifiers.
none_key.set_physical_keycode(Key::ENTER);
@@ -144,8 +144,7 @@ TEST_CASE("[InputEventKey] Key correctly converts itself to text") {
TEST_CASE("[InputEventKey] Key correctly converts its state to a string representation") {
InputEventKey none_key;
- // Set physical to true.
- CHECK(none_key.to_string() == "InputEventKey: keycode=0 (), mods=none, physical=true, pressed=false, echo=false");
+ CHECK(none_key.to_string() == "InputEventKey: keycode=(Unset), mods=none, physical=false, pressed=false, echo=false");
// Set physical key to Escape.
none_key.set_physical_keycode(Key::ESCAPE);
CHECK(none_key.to_string() == "InputEventKey: keycode=4194305 (Escape), mods=none, physical=true, pressed=false, echo=false");
diff --git a/tests/core/math/test_geometry_3d.h b/tests/core/math/test_geometry_3d.h
index 8d57bd5319..46a99aa4b6 100644
--- a/tests/core/math/test_geometry_3d.h
+++ b/tests/core/math/test_geometry_3d.h
@@ -388,13 +388,13 @@ TEST_CASE("[Geometry3D] Segment Intersects Triangle") {
TEST_CASE("[Geometry3D] Triangle and Box Overlap") {
struct Case {
- Vector3 box_centre;
+ Vector3 box_center;
Vector3 box_half_size;
Vector3 *tri_verts = nullptr;
bool want;
Case(){};
- Case(Vector3 p_centre, Vector3 p_half_size, Vector3 *p_verts, bool p_want) :
- box_centre(p_centre), box_half_size(p_half_size), tri_verts(p_verts), want(p_want){};
+ Case(Vector3 p_center, Vector3 p_half_size, Vector3 *p_verts, bool p_want) :
+ box_center(p_center), box_half_size(p_half_size), tri_verts(p_verts), want(p_want){};
};
Vector<Case> tt;
Vector3 GoodTriangle[3] = { Vector3(3, 2, 3), Vector3(2, 2, 1), Vector3(2, 1, 1) };
@@ -403,7 +403,7 @@ TEST_CASE("[Geometry3D] Triangle and Box Overlap") {
tt.push_back(Case(Vector3(1000, 1000, 1000), Vector3(1, 1, 1), BadTriangle, false));
for (int i = 0; i < tt.size(); ++i) {
Case current_case = tt[i];
- bool output = Geometry3D::triangle_box_overlap(current_case.box_centre, current_case.box_half_size, current_case.tri_verts);
+ bool output = Geometry3D::triangle_box_overlap(current_case.box_center, current_case.box_half_size, current_case.tri_verts);
CHECK(output == current_case.want);
}
}
diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h
index e98aece305..828029dabe 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -2773,7 +2773,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
CHECK(code_edit->get_line(0) == "''");
CHECK(code_edit->get_caret_column() == 1);
- /* Move out from centre, Should match and insert larger key. */
+ /* Move out from center, Should match and insert larger key. */
SEND_GUI_ACTION(code_edit, "ui_text_caret_right");
SEND_GUI_KEY_EVENT(code_edit, Key::APOSTROPHE);
CHECK(code_edit->get_line(0) == "''''''");