Browse Source

Add a graphics tablet input demo (#1162)

Hugo Locurcio 6 months ago
parent
commit
fdb2f50a20

+ 32 - 0
misc/graphics_tablet_input/README.md

@@ -0,0 +1,32 @@
+# Graphics Tablet Input
+
+A demo showing how to use graphics tablet input in Godot. Godot has full support
+for pressure sensitivity, tilt and pen inversion (i.e. checking whether the
+"eraser" is being used on the pen). Note that some platforms and tablets
+may not support reporting tilt.
+
+Input accumulation and V-Sync are disabled by default in this demo to minimize
+input lag and get crisp lines (even at low FPS). This makes for the most
+responsive drawing experience possible. You can toggle them in the sidebar to
+see the difference it makes. Note that on Android, iOS and Web platforms, V-Sync
+is forced at a system level and cannot be disabled.
+
+Lines are drawn using the Line2D node. Every time you lift off the open and start a new
+line, a new Line2D node is created. Line antialiasing is provided by enabling 2D MSAA
+in the Project Settings.
+
+Mouse input can also be used to draw in this demo, but using a tablet is recommended.
+
+> [!NOTE]
+>
+> If you experience issues on Windows, try changing the tablet driver in the Project
+> Settings to **wintab** instead of the default **winink**. Also, try changing your
+> tablet's input mode from relative to absolute mode.
+
+Language: GDScript
+
+Renderer: Mobile
+
+## Screenshots
+
+![Screenshot](screenshots/graphics_tablet_input.webp)

+ 189 - 0
misc/graphics_tablet_input/graphics_tablet_input.gd

@@ -0,0 +1,189 @@
+extends Control
+
+# Automatically split lines at regular intervals to avoid performance issues
+# while drawing. This is especially due to the width curve which has to be recreated
+# on every new point.
+const SPLIT_POINT_COUNT = 1024
+
+var stroke: Line2D
+var width_curve: Curve
+var pressures := PackedFloat32Array()
+var event_position: Vector2
+var event_tilt: Vector2
+
+var line_color := Color.BLACK
+var line_width: float = 3.0
+
+# If `true`, modulate line width accordding to pen pressure.
+# This is done using a width curve that is continuously recreated to match the line's actual profile
+# as the line is being drawn by the user.
+var pressure_sensitive: bool = true
+
+var show_tilt_vector: bool = true
+
+@onready var tablet_info: Label = %TabletInfo
+
+
+func _ready() -> void:
+	# This makes tablet and mouse input reported as often as possible regardless of framerate.
+	# When accumulated input is disabled, we can query the pen/mouse position at every input event
+	# seen by the operating system, without being limited to the framerate the application runs at.
+	# The downside is that this uses more CPU resources, so input accumulation should only be
+	# disabled when you need to have access to precise input coordinates.
+	Input.use_accumulated_input = false
+	start_stroke()
+	%TabletDriver.text = "Tablet driver: %s" % DisplayServer.tablet_get_current_driver()
+
+
+func _input(event: InputEvent) -> void:
+	if event is InputEventKey:
+		if Input.is_action_pressed(&"increase_line_width"):
+			$CanvasLayer/PanelContainer/Options/LineWidth/HSlider.value += 0.5
+			#_on_line_width_value_changed(line_width)
+		if Input.is_action_pressed(&"decrease_line_width"):
+			$CanvasLayer/PanelContainer/Options/LineWidth/HSlider.value -= 0.5
+			#_on_line_width_value_changed(line_width)
+
+	if not stroke:
+		return
+
+	if event is InputEventMouseMotion:
+		var event_mouse_motion := event as InputEventMouseMotion
+		tablet_info.text = "Pressure: %.3f\nTilt: %.3v\nInverted pen: %s" % [
+			event_mouse_motion.pressure,
+			event_mouse_motion.tilt,
+			"Yes" if event_mouse_motion.pen_inverted else "No",
+		]
+
+		if event_mouse_motion.pressure <= 0 and stroke.points.size() > 1:
+			# Initial part of a stroke; create a new line.
+			start_stroke()
+			# Enable the buttons if they were previously disabled.
+			%ClearAllLines.disabled = false
+			%UndoLastLine.disabled = false
+		if event_mouse_motion.pressure > 0:
+			# Continue existing line.
+			stroke.add_point(event_mouse_motion.position)
+			pressures.push_back(event_mouse_motion.pressure)
+			# Only compute the width curve if it's present, as it's not even created
+			# if pressure sensitivity is disabled.
+			if width_curve:
+				width_curve.clear_points()
+				for pressure_idx in range(pressures.size()):
+					width_curve.add_point(Vector2(
+							float(pressure_idx) / pressures.size(),
+							pressures[pressure_idx]
+					))
+
+			# Split into a new line if it gets too long to avoid performance issues.
+			# This is mostly reached when input accumulation is disabled, as enabling
+			# input accumulation will naturally reduce point count by a lot.
+			if stroke.get_point_count() >= SPLIT_POINT_COUNT:
+				start_stroke()
+
+		event_position = event_mouse_motion.position
+		event_tilt = event_mouse_motion.tilt
+		queue_redraw()
+
+
+func _draw() -> void:
+	if show_tilt_vector:
+		# Draw tilt vector.
+		draw_line(event_position, event_position + event_tilt * 50, Color(1, 0, 0, 0.5), 2, true)
+
+
+func start_stroke() -> void:
+	var new_stroke := Line2D.new()
+	new_stroke.begin_cap_mode = Line2D.LINE_CAP_ROUND
+	new_stroke.end_cap_mode = Line2D.LINE_CAP_ROUND
+	new_stroke.joint_mode = Line2D.LINE_JOINT_ROUND
+	# Adjust round precision depending on line width to improve performance
+	# and ensure it doesn't go above the default.
+	new_stroke.round_precision = mini(line_width, 8)
+	new_stroke.default_color = line_color
+	new_stroke.width = line_width
+	if pressure_sensitive:
+		new_stroke.width_curve = Curve.new()
+	add_child(new_stroke)
+
+	new_stroke.owner = self
+	stroke = new_stroke
+	if pressure_sensitive:
+		width_curve = new_stroke.width_curve
+	else:
+		width_curve = null
+	pressures.clear()
+
+
+func _on_undo_last_line_pressed() -> void:
+	# Remove last node of type Line2D in the scene.
+	var last_line_2d: Line2D = find_children("", "Line2D")[-1]
+	if last_line_2d:
+		# Remove stray empty line present at the end due to mouse motion.
+		# Note that doing it once doesn't always suffice, as multiple empty lines
+		# may exist at the end of the list (e.g. after changing line width/color settings).
+		# In this case, the user will have to use undo multiple times.
+		if last_line_2d.get_point_count() == 0:
+			last_line_2d.queue_free()
+
+			var other_last_line_2d: Line2D = find_children("", "Line2D")[-2]
+			if other_last_line_2d:
+				other_last_line_2d.queue_free()
+		else:
+			last_line_2d.queue_free()
+
+		# Since a new line is created as soon as mouse motion occurs (even if nothing is visible yet),
+		# we consider the list of lines to be empty with up to 2 items in it here.
+		%UndoLastLine.disabled = find_children("", "Line2D").size() <= 2
+		start_stroke()
+
+
+func _on_clear_all_lines_pressed() -> void:
+	# Remove all nodes of type Line2D in the scene.
+	for node in find_children("", "Line2D"):
+		node.queue_free()
+
+	%ClearAllLines.disabled = true
+	start_stroke()
+
+
+func _on_line_color_changed(color: Color) -> void:
+	line_color = color
+	# Required to make the setting change apply immediately.
+	start_stroke()
+
+func _on_line_width_value_changed(value: float) -> void:
+	line_width = value
+	$CanvasLayer/PanelContainer/Options/LineWidth/Value.text = "%.1f" % value
+	# Required to make the setting change apply immediately.
+	start_stroke()
+
+
+func _on_pressure_sensitive_toggled(toggled_on: bool) -> void:
+	pressure_sensitive = toggled_on
+	# Required to make the setting change apply immediately.
+	start_stroke()
+
+
+func _on_show_tilt_vector_toggled(toggled_on: bool) -> void:
+	show_tilt_vector = toggled_on
+
+
+func _on_msaa_item_selected(index: int) -> void:
+	get_viewport().msaa_2d = index as Viewport.MSAA
+
+
+func _on_max_fps_value_changed(value: float) -> void:
+	# Since the project has low-processor usage mode enabled, we change its sleep interval instead.
+	# Since this is a value in microseconds between frames, we have to convert it from a FPS value.
+	@warning_ignore("narrowing_conversion")
+	OS.low_processor_usage_mode_sleep_usec = 1_000_000.0 / value
+	$CanvasLayer/PanelContainer/Options/MaxFPS/Value.text = str(roundi(value))
+
+
+func _on_v_sync_toggled(toggled_on: bool) -> void:
+	DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if toggled_on else DisplayServer.VSYNC_DISABLED)
+
+
+func _on_input_accumulation_toggled(toggled_on: bool) -> void:
+	Input.use_accumulated_input = toggled_on

+ 228 - 0
misc/graphics_tablet_input/graphics_tablet_input.tscn

@@ -0,0 +1,228 @@
+[gd_scene load_steps=13 format=3 uid="uid://dxpettbof8pr8"]
+
+[ext_resource type="Script" path="res://graphics_tablet_input.gd" id="1_fhuxi"]
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0pp2f"]
+content_margin_left = 12.0
+content_margin_top = 12.0
+content_margin_right = 12.0
+content_margin_bottom = 12.0
+bg_color = Color(0.223529, 0.223529, 0.223529, 1)
+
+[sub_resource type="InputEventAction" id="InputEventAction_spbge"]
+action = &"undo_last_line"
+
+[sub_resource type="Shortcut" id="Shortcut_3mcds"]
+events = [SubResource("InputEventAction_spbge")]
+
+[sub_resource type="InputEventAction" id="InputEventAction_7n722"]
+action = &"clear_all_lines"
+
+[sub_resource type="Shortcut" id="Shortcut_5wv4g"]
+events = [SubResource("InputEventAction_7n722")]
+
+[sub_resource type="InputEventAction" id="InputEventAction_y8lr1"]
+action = &"change_line_color"
+
+[sub_resource type="Shortcut" id="Shortcut_1nmmy"]
+events = [SubResource("InputEventAction_y8lr1")]
+
+[sub_resource type="InputEventAction" id="InputEventAction_0l3by"]
+action = &"toggle_pressure_sensitive"
+
+[sub_resource type="Shortcut" id="Shortcut_mnr5q"]
+events = [SubResource("InputEventAction_0l3by")]
+
+[sub_resource type="InputEventAction" id="InputEventAction_4p65y"]
+action = &"toggle_tilt_vector"
+
+[sub_resource type="Shortcut" id="Shortcut_231fk"]
+events = [SubResource("InputEventAction_4p65y")]
+
+[node name="ColorRect" type="ColorRect"]
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_default_cursor_shape = 3
+script = ExtResource("1_fhuxi")
+
+[node name="CanvasLayer" type="CanvasLayer" parent="."]
+
+[node name="PanelContainer" type="PanelContainer" parent="CanvasLayer"]
+offset_right = 264.0
+offset_bottom = 648.0
+size_flags_horizontal = 0
+theme_override_styles/panel = SubResource("StyleBoxFlat_0pp2f")
+
+[node name="Options" type="VBoxContainer" parent="CanvasLayer/PanelContainer"]
+custom_minimum_size = Vector2(240, 0)
+layout_mode = 2
+size_flags_horizontal = 0
+theme_override_constants/separation = 10
+
+[node name="UndoLastLine" type="Button" parent="CanvasLayer/PanelContainer/Options"]
+unique_name_in_owner = true
+layout_mode = 2
+disabled = true
+shortcut = SubResource("Shortcut_3mcds")
+text = "Undo Last Line"
+
+[node name="ClearAllLines" type="Button" parent="CanvasLayer/PanelContainer/Options"]
+unique_name_in_owner = true
+layout_mode = 2
+disabled = true
+shortcut = SubResource("Shortcut_5wv4g")
+text = "Clear All Lines"
+
+[node name="HSeparator" type="HSeparator" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+
+[node name="LineColor" type="HBoxContainer" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+theme_override_constants/separation = 10
+
+[node name="Label" type="Label" parent="CanvasLayer/PanelContainer/Options/LineColor"]
+layout_mode = 2
+text = "Line Color"
+
+[node name="ColorPickerButton" type="ColorPickerButton" parent="CanvasLayer/PanelContainer/Options/LineColor"]
+custom_minimum_size = Vector2(0, 30)
+layout_mode = 2
+size_flags_horizontal = 3
+shortcut = SubResource("Shortcut_1nmmy")
+
+[node name="LineWidth" type="HBoxContainer" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+tooltip_text = "(-: Decrease, +: Increase)"
+theme_override_constants/separation = 10
+
+[node name="Label" type="Label" parent="CanvasLayer/PanelContainer/Options/LineWidth"]
+layout_mode = 2
+text = "Line Width"
+
+[node name="HSlider" type="HSlider" parent="CanvasLayer/PanelContainer/Options/LineWidth"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
+min_value = 0.5
+max_value = 20.0
+step = 0.5
+value = 3.0
+
+[node name="Value" type="Label" parent="CanvasLayer/PanelContainer/Options/LineWidth"]
+custom_minimum_size = Vector2(35, 0)
+layout_mode = 2
+text = "3.0"
+horizontal_alignment = 1
+
+[node name="PressureSensitive" type="CheckButton" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+tooltip_text = "If enabled, modulates line width according to pen pressure.
+This has no effect if drawing with a mouse or a tablet
+without pen pressure support."
+button_pressed = true
+shortcut = SubResource("Shortcut_mnr5q")
+text = "Pressure-Sensitive"
+
+[node name="ShowTiltVector" type="CheckButton" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+tooltip_text = "If enabled, shows a visual representation of the tilt vector
+reported by the graphics tablet. Tilt is not supported by all
+graphics tablets."
+button_pressed = true
+shortcut = SubResource("Shortcut_231fk")
+text = "Show Tilt Vector"
+
+[node name="HSeparator2" type="HSeparator" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+
+[node name="MSAA" type="HBoxContainer" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+theme_override_constants/separation = 10
+
+[node name="Label" type="Label" parent="CanvasLayer/PanelContainer/Options/MSAA"]
+layout_mode = 2
+text = "MSAA 2D"
+
+[node name="OptionButton" type="OptionButton" parent="CanvasLayer/PanelContainer/Options/MSAA"]
+layout_mode = 2
+selected = 3
+item_count = 4
+popup/item_0/text = "Disabled"
+popup/item_1/text = "2×"
+popup/item_1/id = 1
+popup/item_2/text = "4×"
+popup/item_2/id = 2
+popup/item_3/text = "8×"
+popup/item_3/id = 3
+
+[node name="MaxFPS" type="HBoxContainer" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+theme_override_constants/separation = 10
+
+[node name="Label" type="Label" parent="CanvasLayer/PanelContainer/Options/MaxFPS"]
+layout_mode = 2
+text = "Max FPS"
+
+[node name="HSlider" type="HSlider" parent="CanvasLayer/PanelContainer/Options/MaxFPS"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 4
+min_value = 10.0
+max_value = 240.0
+step = 5.0
+value = 145.0
+
+[node name="Value" type="Label" parent="CanvasLayer/PanelContainer/Options/MaxFPS"]
+custom_minimum_size = Vector2(35, 0)
+layout_mode = 2
+text = "145"
+horizontal_alignment = 1
+
+[node name="VSync" type="CheckButton" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+tooltip_text = "Disable V-Sync to achieve lower input latency.
+
+Note that Android, iOS and Web platforms enforce
+V-Sync at a system level with no reliable way to disable it."
+text = "V-Sync"
+
+[node name="InputAccumulation" type="CheckButton" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+tooltip_text = "If enabled, inputs are collected and merged into a single input event on every rendered frame.
+By default, this is enabled in Godot, but this project disables it by default.
+
+This should be left disabled for drawing apps that expect precise input,
+as lines can become visibly jagged otherwise."
+text = "Input Accumulation"
+
+[node name="Spacer" type="Control" parent="CanvasLayer/PanelContainer/Options"]
+layout_mode = 2
+size_flags_vertical = 3
+
+[node name="TabletInfo" type="Label" parent="CanvasLayer/PanelContainer/Options"]
+unique_name_in_owner = true
+modulate = Color(1, 1, 1, 0.67451)
+layout_mode = 2
+text = "Pressure: 0.000
+Tilt: (0.000, 0.000)
+Inverted pen: No"
+
+[node name="TabletDriver" type="Label" parent="CanvasLayer/PanelContainer/Options"]
+unique_name_in_owner = true
+modulate = Color(1, 1, 1, 0.501961)
+layout_mode = 2
+text = "Tablet driver: <driver>"
+
+[connection signal="pressed" from="CanvasLayer/PanelContainer/Options/UndoLastLine" to="." method="_on_undo_last_line_pressed"]
+[connection signal="pressed" from="CanvasLayer/PanelContainer/Options/ClearAllLines" to="." method="_on_clear_all_lines_pressed"]
+[connection signal="color_changed" from="CanvasLayer/PanelContainer/Options/LineColor/ColorPickerButton" to="." method="_on_line_color_changed"]
+[connection signal="value_changed" from="CanvasLayer/PanelContainer/Options/LineWidth/HSlider" to="." method="_on_line_width_value_changed"]
+[connection signal="toggled" from="CanvasLayer/PanelContainer/Options/PressureSensitive" to="." method="_on_pressure_sensitive_toggled"]
+[connection signal="toggled" from="CanvasLayer/PanelContainer/Options/ShowTiltVector" to="." method="_on_show_tilt_vector_toggled"]
+[connection signal="item_selected" from="CanvasLayer/PanelContainer/Options/MSAA/OptionButton" to="." method="_on_msaa_item_selected"]
+[connection signal="value_changed" from="CanvasLayer/PanelContainer/Options/MaxFPS/HSlider" to="." method="_on_max_fps_value_changed"]
+[connection signal="toggled" from="CanvasLayer/PanelContainer/Options/VSync" to="." method="_on_v_sync_toggled"]
+[connection signal="toggled" from="CanvasLayer/PanelContainer/Options/InputAccumulation" to="." method="_on_input_accumulation_toggled"]

+ 1 - 0
misc/graphics_tablet_input/icon.svg

@@ -0,0 +1 @@
+<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="m23.361485 80.005717c-2.104041 2.400048-3.360066 5.840116-3.360066 9.904197 0 13.024266-25.1044898-1.424028-2.696053 21.360426 7.072139 7.20014 21.232415 5.36011 28.304553-1.82404a18.640364 18.640374 0 0 0 0-26.048516c-8.800171-8.952179-17.600343-8.672174-22.240434-3.392067zm18.400358-13.120264 19.200375 19.200385 54.401062-54.40109a13.718869 13.718876 0 0 0 -19.200375-19.600392z" fill="#808080"/></svg>

+ 37 - 0
misc/graphics_tablet_input/icon.svg.import

@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://besl3a0sbq1v0"
+path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.svg"
+dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false

+ 71 - 0
misc/graphics_tablet_input/project.godot

@@ -0,0 +1,71 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+;   [section] ; section goes between []
+;   param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="Graphics Tablet Input"
+config/description="A demo showing how to use graphics tablet input in Godot."
+config/tags=PackedStringArray("2d", "demo", "input", "official", "porting")
+run/main_scene="res://graphics_tablet_input.tscn"
+config/features=PackedStringArray("4.3")
+run/low_processor_mode=true
+config/icon="res://icon.svg"
+
+[display]
+
+window/stretch/mode="canvas_items"
+window/stretch/aspect="expand"
+window/vsync/vsync_mode=0
+
+[input]
+
+undo_last_line={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194308,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":90,"physical_keycode":0,"key_label":0,"unicode":122,"location":0,"echo":false,"script":null)
+]
+}
+clear_all_lines={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":4194308,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+]
+}
+change_line_color={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":67,"physical_keycode":0,"key_label":0,"unicode":99,"location":0,"echo":false,"script":null)
+]
+}
+increase_line_width={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194437,"physical_keycode":0,"key_label":0,"unicode":43,"location":0,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":61,"key_label":0,"unicode":61,"location":0,"echo":false,"script":null)
+]
+}
+decrease_line_width={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194435,"physical_keycode":0,"key_label":0,"unicode":45,"location":0,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":45,"key_label":0,"unicode":41,"location":0,"echo":false,"script":null)
+]
+}
+toggle_pressure_sensitive={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":80,"physical_keycode":0,"key_label":0,"unicode":112,"location":0,"echo":false,"script":null)
+]
+}
+toggle_tilt_vector={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":84,"physical_keycode":0,"key_label":0,"unicode":116,"location":0,"echo":false,"script":null)
+]
+}
+
+[rendering]
+
+renderer/rendering_method="mobile"
+anti_aliasing/quality/msaa_2d=3

+ 0 - 0
misc/graphics_tablet_input/screenshots/.gdignore


BIN
misc/graphics_tablet_input/screenshots/graphics_tablet_input.webp