First of all register input events to know if mouse button is pressed or released.
var pressed = false
func _input(event):
if event is InputEventMouseButton and event.button_index == BUTTON_LEFT:
pressed = event.pressed
Another way to check mouse button state is to add an Action to Input Map (in Project Settings) and add Mouse Button to the Actions keys list. Then you can check it with
var pressed = Input.is_action_pressed("MyMouseCliskAction")
Second, connect a callback to register mouse_entered and mouse_exited signals of the Button node.
var mouseIsOverButton = false
...
button.connect("mouse_entered", self, "_on_mouse_entered")
button.connect("mouse_exited", self, "_on_mouse_exited")
...
func _on_mouse_entered():
mouseIsOverButton = true
func _on_mouse_exited():
mouseIsOverButton = false
The described problem with mouse_exited signal happens only if mouse button was pressed inside the button area and not released until cursor leaves the button area. is_hovered() may be a more convenient way to check it for Button controls, but it is just a shortcut for the code above and has the same described problem.
If you want to overcome the issue you can use CanvasItem.get_local_mouse_position() (or get_global_mouse_position()) methods of the Button node and then just manually check if the position is within button's rect:
var pos = button.get_local_mouse_position()
var rect = Rect2(button.rect_position, button.rect_size)
var mouseIsOverButton = rect.has_point(pos)