wl_tablet specification draft
Peter Hutterer
peter.hutterer at who-t.net
Wed Jun 25 21:14:33 PDT 2014
On Wed, Jun 25, 2014 at 08:22:21PM -0700, Jason Ekstrand wrote:
>
> On 06/25/2014 06:05 PM, Peter Hutterer wrote:
> >On Wed, Jun 25, 2014 at 03:19:02PM +0300, Pekka Paalanen wrote:
> >>On Tue, 24 Jun 2014 21:56:09 -0400
> >>Chandler Paul <thatslyude at gmail.com> wrote:
> >>
> >>>Hello! As you all know I've been working on adding drawing tablet
> >>>support to the Wayland protocol. Now that we've added support for
> >>>tablets to libinput, the next step is writing the actual protocol that
> >>>will be implemented by the compositor. Following this blurb is the
> >>>current draft of the tablet protocol we have. Feel free to critique it.
> >>>
> >>>Cheers,
> >>> Lyude
> >>>
> >>>----------------------------------------------------------------------------
> >>>
> >>> wl_tablet specifications
> >>>
> >>>General notes:
> >>>- Many of the axis values in this are normalized to either 0-65535 or
> >>> (-65535)-65535. I would leave the axis values as-is since libinput reports
> >>> them as doubles, but since we only have 8 bits of precision we'd lose way
> >>> too many values. 65535 seemed like the best choice since it's the maximum
> >>> length of a signed short, it's a whole number, it's way higher then the
> >>> range of any of the axes (with the exception of X and Y, but these aren't
> >>> normalized anyway) and we can do just about any basic arithmatic with it
> >>> without having to worry about overflowing. plus, all we have to do is
> >>> multiply the value by 65535 after we get it from libinput.
> >>>
> >>>Definitions:
> >>>- WL_TABLET_AXIS_MAX = 65535
> >>>- WL_TABLET_AXIS_MIN = (-65535)
> >>>
> >>>Enumerators:
> >>>- wl_tablet_axis:
> >>> - WL_TABLET_AXIS_X
> >>> - WL_TABLET_AXIS_Y
> >>> Represents the X and Y axes respectively. Only used in bitfields to
> >>> indicate whether or not they've changed since the last event.
> >>>
> >>> - WL_TABLET_AXIS_DISTANCE
> >>> Represents the distance axis on a tablet. Normalized from 0 to
> >>> WL_TABLET_AXIS_MAX. For tablets that do not support reporting the
> >>> distance, this will always be 0.
> >>>
> >>> - WL_TABLET_AXIS_PRESSURE
> >>> Represents the pressure axis on a tablet. Normalized from 0 to
> >>> WL_TABLET_AXIS_MAX. For tablets that do not support reporting the
> >>> pressure, this will always be WL_TABLET_AXIS_MAX.
> >>>
> >>> - WL_TABLET_AXIS_TILT_VERTICAL
> >>> - WL_TABLET_AXIS_TILT_HORIZONTAL
> >>> Each represents the vertical and horizontal tilt axes respectfully.
> >>> Normalized from WL_TABLET_AXIS_MIN to WL_TABLET_AXIS_MAX. For
> >>> tablets that do not support this, this value will always be 0.
> >>>
> >>> - WL_TABLET_AXIS_CNT
> >>> Represents the number of axes
> >>>- wl_tablet_tool_type:
> >>> - pen
> >>> - eraser
> >>> - brush
> >>> - pencil
> >>> - airbrush
> >>> - finger
> >>> - mouse
> >>> - lens
> >>>- wl_tablet_button_state
> >>> - pressed
> >>> - released
> >>>
> >>>Events:
> >>>- proximity_in
> >>> Sent when the tool comes into proximity above the client surface, either by
> >>> the tool coming into proximity or a tool being in-proximity and moving to
> >>> the client surface. If a tablet tool makes contact with the tablet at the
> >>> same time that the tool comes into proximity, the proximity event comes
> >>> first and the down event comes afterwards.
> >>> Arguments:
> >>> - Name: id
> >>> Type: uint
> >>> the id of the tablet sending this event.
> >>>
> >>> - Name: type
> >>> Type: uint
> >>> The type of tool that came into proximity, e.g. pen, airbrush, etc.
> >>>
> >>> - Name: serial
> >>> Type: uint
> >>> The serial number of the tool that came into proximity. On tablets
> >>> where this isn't provided, this value will always be 0.
> >>>
> >>> - Name: x
> >>> Type: fixed
> >>> Surface relative x coordinate
> >>>
> >>> - Name: y
> >>> Type: fixed
> >>> Surface relative y coordinate
> >>>
> >>> - Name: surface
> >>> Type: object
> >>> Interface: wl_surface
> >>> The current surface the tablet tool is over
> >>>
> >>> - Name: time
> >>> Type: uint
> >>> The time of the event with millisecond granularity.
> >>>
> >>> - Name: axes
> >>> Type: array
> >>> The current values of each of the tablet axes starting at
> >>> WL_TABLET_AXIS_DISTANCE. The length of the array is equal to the
> >>> number of axes that are reported. Any axes >= WL_TABLET_AXIS_CNT
> >>> must be ignored. The size of the array remains fixed for the
> >>> lifetime of the tablet.
> >>>
> >>>- proximity_out
> >>> Send whenever the tool leaves the proximity of the tablet or moves out of
> >>> the client surface. When the tool goes out of proximity, a set of button
> >>> release events are sent before the initial proximity_out event for each
> >>> button that was held down before the tablet tool left proximity. In
> >>> addition, axis updates always come before a proximity-out event.
> >>> Arguments:
> >>> - Name: id
> >>> Type: uint
> >>> The id of the tablet sending this event.
> >>>
> >>> - Name: time
> >>> Type: uint
> >>> The time of the event with millisecond granularity.
> >>>
> >>>- axis
> >>> Sent whenever an axis on the tool changes. This can include movement on the
> >>> X and Y axis.
> >>> Arguments:
> >>> - Name: id
> >>> Type: uint
> >>> The id of the tablet sending this event.
> >>>
> >>> - Name: x
> >>> Type: fixed
> >>> Surface relative x coordinate
> >>>
> >>> - Name: y
> >>> Type: fixed
> >>> Surface relative y coordinate
> >>>
> >>> - Name: surface
> >>> Type: object
> >>> Interface: wl_surface
> >>> The current surface the tablet tool is over
> >>How about using enter/leave events telling the client which wl_surface
> >>the input device is targeting? That way you don't have to repeat the
> >>wl_surface argument in every event.
> >good point, thanks!
> >>> - Name: time
> >>> Type: uint
> >>> The time of the event with millisecond granularity.
> >>>
> >>> - Name: changed_axes
> >>> Type: bitfield
> >>> Indicates which axes have changed.
> >>>
> >>> - Name: axes
> >>> Type: array
> >>> The current values of each of the tablet axes starting at
> >>> WL_TABLET_AXIS_DISTANCE. The length of the array is equal to the
> >>> number of axes that are reported. Any axes >= WL_TABLET_AXIS_CNT
> >>> must be ignored.
> Is there a reason we are using an array rather than sending different
> events? It's tempting to try and save something by using an array, but
> extra events don't really cost anything significant. Also, once you use an
> enum value in a public protocol, you can NEVER change it. In particular,
> you can't change WL_TABLET_AXIS_CNT and you are locked into only ever using
> those axes and never extending the protocol to include more. I don't think
> this is what you intended.
the basic idea here was to simply provide the client with a single event
containing all the data at all times rather than a flurry of events with the
deltas, terminated by a FRAME event. A few calculations showed that sending
all axes every time in one event is still smaller than sending frame events
(given "average" axis usage) so we're not losing anything here.
the basic idea behind the array is that we can add to it in later revisions.
a client gets the array size and up to that size axes are included. If the
compositor uses a higher _CNT, then the client is supposed to ignore
anything above that value.
also, though that isn't clear: I don't think _CNT is something that's
actually in the protocol, a client would #define that themselves or just use
whatever the highest axis is they want to deal with.
> Also, is there a reason why you have one axis event rather than
> wl_tablet.position, wl_tablet.distance, wl_tablet.tilt, etc? Not that
> having one axis event and an enum is bad, but it's something to think about.
I do like this idea, though it still requires the frame event.
> >>>
> >>>- button
> >>> Sent whenever a button on the tool is pressed or released.
> >>> Arguments:
> >>> - Name: id
> >>> Type: uint
> >>> The id of the tablet sending this event.
> >>>
> >>> - Name: button
> >>> Type: uint
> >>> The button whose state has changed
> >>>
> >>> - Name: state
> >>> Type: uint
> >>> Whether the button was pressed or released
> >>>
> >>> - Name: time
> >>> Type: uint
> >>> The time of the event with millisecond granularity.
> >>>
> >>>- added
> >>> Sent when a tablet device is added.
> >>> Arguments:
> >>> - Name: id
> >>> Type: uint
> >>> The id of the tablet sending this event.
> >>>
> >>>- removed
> >>> Sent when the tablet device has been removed.
> >>> Arguments:
> >>> - Name: id
> >>> Type: uint
> >>> The id of the tablet sending this event.
> >>>
> >>>How tablet IDs are generated:
> >>>Tablet IDs are aggressively recycled, e.g. we always try to get the lowest
> >>>possible tablet ID. This means that the client can always assume that the ID
> >>>number for a new tablet will never be greater then the number of tablets
> >>>currently connected.
> >>Hi,
> >>
> >>using tablet IDs this way seems like this is a raw wire protocol, and
> >>not object oriented like Wayland usually is.
> >>
> >>Could this be wrapped into an object like the following?
> >>
> >>Define interface "wl_tablet" which represents one device (I assume
> >>aggregating makes no sense, just like with gamepads). Then you can drop
> >>the "id" argument from all events and requests, and just use the
> >>protocol object.
> >It's possible, look at this RFC from last september.
> >http://lists.freedesktop.org/archives/wayland-devel/2013-September/011173.html
> >
> >The gist of that was that the wl_seat::get_tablet_manager request that
> >returned a tablet manager object. that object was then the one that sent
> >wl_tablet_manager::device_added events with the new tablet object. And that
> >object had the wl_tablet interface as above (without the IDs).
> >
> >Lyude and I talked about this and couldn't decide which approach was the
> >correct-er one for wayland :)
> I'll second what pekka said. We already have a way of handling IDs and
> agressively recycling them; it's called object IDs. I'm guessing the IDs
> thing came from the wl_touch interface. There we have a wl_touch object for
> the physical device and IDs for the different touchpoints. Here we have one
> pen per physical device (I think).
that's not quite true, and it's the biggest difference between pointer/touch
and tablet. For pointer/touch we don't care that there are more devices,
they all mangle together. For tablets, it does matter if the event came from
the Cintiq or the attached Bamboo, both may be assigned different functions,
configurations, behaviours, etc.
So I do think we need multiple tablet objects instead of just one like
wl_pointer has.
You usually have more than one pen as well: the physical pen that comes with
a tablet already has two tools built-in (pen + eraser) and both have
separate serial numbers. You can buy extra tools and the unique serial means
that with appropriate client support you can use the same physical tool on
different tablets and always get the same settings. Having said that, those
tools currently abstracted in the serial/tool type fields so it's not a wl
object as such anyway.
> >>I'm not sure how you want to advertise and create the wl_tablet objects.
> >>How do tablet devices relate to wl_seat protocol objects?
> >tablets control the cursor, so we definitely need to couple them
> >with the seats somehow.
> Does it control THE cursor or A cursor? I question whether we really want
> it to be that intertwined with wl_pointer.
>
> This brings up another point: tablet focus. How do you usually tell the
> compositor what window you want to receive tablet input? For a tablet with
> a screen, you can treat it more-or-less like a single-point touch-screen,
> but what about tablets that aren't attached to a screen? In the past,
> tablets frequently existed as a more natural way to move the mouse around
> with a little extra meta-data for an app if it wanted it. Is that the way
> they SHOULD work? That's a different question.
Yes, but that doesn't change that tablets belong to one seat at a time :)
How the compositor moves the cursor/controls the focus around is none of the
protocol's business.
Cheers,
Peter
> >>While the protocol is experimental, you could have your own (temporary)
> >>global interface for advertising tablets, so that you don't need to
> >>modify the Wayland core protocol (wl_seat). Or you could advertise each
> >>tablet device as a separate global wl_tablet that a client can bind to.
> >>The proper approach finally depends on the relation to wl_seat once you
> >>are ready to set the protocol in stone.
> >good point, thanks.
> >
> >>Would clients need some information to differentiate between multiple
> >>tablets in a human-friendly way?
> >yes, we'll at least need to add PID/VID. From then on the clients can look
> >up all they need in libwacom. I don't think we need much more than that.
> >
> >>Or should all clients always subscribe to all tablets?
> >Yes, I think that's the sensible option. in 99% of the cases there is only
> >one tablet anyway, sometimes there are 2 (laptops have wacom tablets
> >built-in or a Cintiq+Intuos combo), I haven't seen a real-world setup with 3
> >tablet yet.
> >
> >Cheers,
> > Peter
More information about the wayland-devel
mailing list