How do I connect a apple pencil in godot

Godot Version

4

Question

I’m making a drawing app so I want to be able to detect a apple pencil or all other pencils. The reason why I need to connect them is so that I can receive separate inputs from the pencil.

For example if I want the apple pencil to only be able to draw and do nothing else and the hand only to be able to do gestures then I could only draw when I receive a input from the apple pencil and if I receive a input from the hand and it is doing a gesture then I could zoom in for example. This has many other use cases. I’d also like to know how do I auto detect it so that they don’t have to configure it in the settings menu

Can someone please help me

Godot doesn’t make this easy. But you will need to create or find a resource that you can assign input devices to a set of input actions. Your apple pen will probably be a mixture of a mouse and a joypad. Only joypads can set devices, so I guess the first thing to do is monitor input function for actions taken by the Apple pen. better yer each InputEvent has a device associated with it, so you should be able to listen to specific devices for their input.

I suspect the apple pen should show up as a joypad so you can query the connected dvices like this.

for device:int in Input.get_connected_joypads():
  print("device name:  ", Input.get_device_name( device ))
  print("device info:  ", Input.get_device_info( device ))

Thanks man. At first I didn’t know what to do for getting it because their is no Bluetooth device connections or input for apple pencil but this helps a lot. But what are the controls if it is a Joy Stick?

It will probably be a combination of mouse input and joypad is my guess.

If you look at InputEventMouseMotion class/node you can get common pen like inputs to work with.

This is just a guess, but all operating systems have a singular mouse input, but the devices can output in different ways. Each input event has a device number, so if it is a mouse it will probably always be device 0 or something… im not sure if you can discern, i own a pen and tablet but never tried it with Godot. my track pad though acts like a mouse and joypad at the same time…

Hey there!

I am currently working on a vector based note-taking app targeted for Windows, Linux, macOS and iOS/iPadOS.

You have 2 ways to deal with this:

1.) You treat touch gestures entirely as mouse inputs. (This is Godots default behaviour, it seems)

2.) You actually enable Touch Gestures on mobile: In Project Settings, you disable “Emulate Mouse from Touch” and “Emulate Touch from Mouse”.

This way, your events will fire as InputEventScreenDrag (instead of InputEventMouseMotion) and InputEventScreenTouch (instead of InputEventMouseButton).

(edit: Disabling these two emulation settings does not disable Mouse or Keyboard events completely, so you don’t have to do extra work to make 2 different projects, you can just check for all 4 events in the same _input() method. All it does is to disable the actual emulation, as otherwise these Touch and Drag events will “turn into” Mouse events which don’t have information like pressure)

The good thing:

  • You can differentiate InputEventScreenDrag events by checking for is_nan(event.pressure) - if it’s not a number, then you have a finger. If it has a number, it’s the pencil.
  • You have event.index for Touch events, even though you need to work yourself out what it is

The bad thing:

  • This does not work with InputEventScreenTouch, no pressure-value here
  • The deviceId remains the same for both events (=1), no matter if it’s a finger or a pencil, it will always be one. At least with Godot 4.1 to 4.2.1 so far.

So you have to keep track of how many “Touch” events you have, which can either be the pencil or the fingers and then work around that.

For example, if a drag event starts while only one touch event has started AND !is_nan(event.pressure) then we can 100% be sure that this is just the tip of the pencil.

If we have 1 touch event and receive a second one that starts (= 2 events at the same time) and THEN have 2 drag events that both come without pressure, we know 2 fingers are on the screen. Then it’s all about saving positions on touch, checking what’s actually happening on drag and build our logic that way.

I will have a fully working open source application later this year and I plan on building some sort of “App Toolkit” for Godot which provides some wrappers and basic functionality.

There is also a InputEventMagnifyGesture and a InputEventPanGesture, however these only seemed to be triggered by my Wacom Tablet on macOS and Windows, NOT on the iPad.

Oh and one important thing: Touch Events DON’T trigger UI elements, so buttons and stuff like that.

This has been my workaround so far, but it’s not perfect. I will share a better solution as soon as I have taken care of it:

unc _input(event: InputEvent) -> void:
	if event is InputEventScreenTouch or event is InputEventScreenDrag:
		var buttons:Array = get_children()
		buttons.append_array($"../HBoxContainer".get_children())
		
		for child in buttons:
			var isInteractable:bool = child is Button or child is VScrollBar or child is TabBar
			if isInteractable:
				#print(child.name)
				if child.visible and Rect2(child.global_position, (child as Control).size).has_point(event.position):
					if child is Button:
						child.emit_signal("pressed")

This basically checks if a touch event happens on top of a Button and then emits the pressed signal for that button. But it’s buggy and sometimes doesn’t trigger unless I drag outside of the button’s Rect.