In my experience the built-in Controls work well for only the most straight forward usages, and even then you'll find awkward holes in their functionality.
A lot of what you're wanting does exist in the CPP implementation, but isn't exposed.
It often ends up being best to go the route of writing your own. If you use Area2Ds and need to have legitimate overlapping of controls, you'll want to keep and list and implement a priority (height) check of your own. This isn't implemented in the engine currently.
To go down the path of repurposing the built-in Controls... it tends to venture into hacking territory. I have an example below, that responds to holding a click while hovering over a Button.
It only gets your part the way there. You'd have to ignore the pressed signal and implement your own pressed signal based around internal flags and such.
This code exploits calling into the virtual function to call into some of the desired internal functions. There are side effects, so a lot of the other functionality will likely misbehave or stop working. You'd have to work around that too.
That said, it may be more work, but writing your own widgets over something like the code below is probably the better bet.
extends Button
func _ready() -> void:
connect("mouse_entered", self, "check_press")
connect("mouse_exited", self, "clear_press")
func clear_press() -> void:
if(pressed):
set_faux_press(false)
func check_press() -> void:
if(Input.is_mouse_button_pressed(BUTTON_LEFT)):
set_faux_press(true)
func _physics_process(delta: float) -> void:
if(pressed and not Input.is_mouse_button_pressed(BUTTON_LEFT)):
set_faux_press(false)
func set_faux_press(p_state : bool) -> void:
var e = InputEventMouseButton.new()
e.button_index = BUTTON_LEFT
e.pressed = p_state
_gui_input(e)
func _gui_input(e) -> void:
._gui_input(e) # Hacky, be careful here.