Stylus/Touch position is rotated 180° on KDE Wayland, but behaves differently on SDDM Wayland

Description

I’m experiencing a coordinate mismatch with a USB stylus (CUBE TK.Xie-V01.05-0813) on KDE Plasma Wayland.
The stylus position and the on-screen cursor are rotated 180 degrees relative to each other.

For simplicity, touch input is disabled (using udev. but the situation is same for touch).

Observed behavior

Case 1: CalibrationMatrix = identity

  • SDDM (Wayland): stylus is rotated 180° (incorrect)
  • KDE Plasma Wayland session: stylus is also rotated 180° (same incorrect behavior)
    The cursor is 180 rotated from stylus. (90clockwise rotated display is normal because this is laptop tablet)
    After login to Plasma, the same.

Case 2: CalibrationMatrix = 180° rotation

  • SDDM (Wayland): stylus works correctly
  • KDE Plasma Wayland session: stylus position becomes unusable
    (the cursor jumps far away / appears off-screen, location is unclear)
    The cursor position == stylus position.
    After login, cursor goes away when using stylus.

This suggests that SDDM and the KDE Wayland session apply different coordinate transforms.
ChatGPT says KDE Plasma’s transformation has a problem.

libinput investigation

Using:

libinput debug-events --device /dev/input/event12

The raw coordinates reported by libinput are:

Top-left     : X=400 Y=427
Top-right    : X=0   Y=427
Bottom-right : X=0   Y=0
Bottom-left  : X=400 Y=0
400, 427 0, 427
400, 0 0, 0

This indicates that the device’s native coordinate system is already rotated 180°. (ChatGPT says TopLeft should be (0, 0))

Question

  • Is there any supported way to apply a 180° correction for tablet tool coordinates in KDE Wayland?
  • Is this expected behavior, or should this be reported as a KWin / libinput bug?

Any guidance or pointers would be appreciated.

Appendix

Device Info

# after 180 calibration. this is stylus (touch is disabled)
~> sudo libinput list-devices | sed -n '/CUBE TK.Xie/,/^$/p'                                           
Device:                  CUBE TK.Xie-V01.05-0813 Stylus                  
Kernel:                  /dev/input/event12                              
Id:                      usb:4451:1982                                   
Group:                   6                                               
Seat:                    seat0, default                                  
Size:                    400x427mm                                       
Capabilities:            tablet                                          
Tap-to-click:            n/a                                             
Tap-and-drag:            n/a                                             
Tap button map:          n/a                                             
Tap drag lock:           n/a                                             
Left-handed:             disabled                                        
Nat.scrolling:           n/a                                             
Middle emulation:        n/a                                             
Calibration:             -1.00 0.00 1.00 0.00 -1.00 1.00                 
Scroll methods:          none                                            
Scroll button:           n/a                                             
Scroll button lock:      n/a                                             
Click methods:           none                                            
Clickfinger button map:  n/a                                             
Disable-w-typing:        n/a                                             
Disable-w-trackpointing: n/a                                             
Accel profiles:          none                                            
Rotation:                n/a                                             
Area rectangle:          n/a                                             

Software

KDE Plasma version: 6.5.3
KWin version: 6.5.3

Calibration 180° by using hwdb

/etc/udev/hwdb.d/90-touch-calibration.hwdb:

evdev:name:CUBE TK.Xie-V01.05-0813*
LIBINPUT_CALIBRATION_MATRIX=-1 0 1 0 -1 1

I modified&built libinput and saw behavior. I found when I changed the code like:

src/evdev-tablet.c

static inline void
tablet_update_xy(struct tablet_dispatch *tablet, struct evdev_device *device)
{
	const struct input_absinfo *absinfo;
	int value;
	//*
	absinfo = device->abs.absinfo_x;
	value = invert_axis(absinfo);
	tablet->axes.point.x = value;

	absinfo = device->abs.absinfo_y;
	value = invert_axis(absinfo);
	tablet->axes.point.y = value;

	evdev_transform_absolute(device, &tablet->axes.point);
	apply_tablet_area(tablet, device, &tablet->axes.point);
	return;
	//*/

(only) stylus works correctly.

But still problems.

  1. touch is still 180° rotated.
    sudo libinput debug-events --device /dev/input/event11 also shows 180° rotated X/Ys.
    In my understanding, evdev-tablet.c handles both stylus and touch but not?
  2. After using stylus, touch disabled (even both devices are enabled and could touch at first)

I found touchscreen is handled in evdev-fallback.c and modified like ↓ works (but multitouching (and stylus) breaks touch).

diff --git a/src/evdev-fallback.c b/src/evdev-fallback.c
index 54a4c479..122d1958 100644
--- a/src/evdev-fallback.c
+++ b/src/evdev-fallback.c
@@ -629,6 +629,7 @@ fallback_process_touch(struct fallback_dispatch *dispatch,
 {
        struct mt_slot *slot = &dispatch->mt.slots[dispatch->mt.slot];

+       int min, max;
        switch (evdev_usage_enum(e->usage)) {
        case EVDEV_ABS_MT_SLOT:
                if ((size_t)e->value >= dispatch->mt.slots_len) {
@@ -668,14 +669,21 @@ fallback_process_touch(struct fallback_dispatch *dispatch,
                slot->dirty = true;
                break;
        case EVDEV_ABS_MT_POSITION_X:
+               evdev_log_info(device,
+                       "EVDEV_ABS_MT_POSITION_X %d\n",
+                       e->value);
                evdev_device_check_abs_axis_range(device, e->usage, e->value);
-               dispatch->mt.slots[dispatch->mt.slot].point.x = e->value;
+               min = device->abs.warning_range.min.x;
+               max = device->abs.warning_range.max.x;
+               dispatch->mt.slots[dispatch->mt.slot].point.x = max - (e->value-min);
                dispatch->pending_event |= EVDEV_ABSOLUTE_MT;
                slot->dirty = true;
                break;
        case EVDEV_ABS_MT_POSITION_Y:
                evdev_device_check_abs_axis_range(device, e->usage, e->value);
-               dispatch->mt.slots[dispatch->mt.slot].point.y = e->value;
+               min = device->abs.warning_range.min.y;
+               max = device->abs.warning_range.max.y;
+               dispatch->mt.slots[dispatch->mt.slot].point.y = max - (e->value-min);
                dispatch->pending_event |= EVDEV_ABSOLUTE_MT;
                slot->dirty = true;
                break;

So, modifying kernel module is better but for stylus/touch position glitch, this is OK for me. (It is kernel module’s problem?)
But still other problems (seems to be libinput bugs).

  1. After using stylus, touch disabled (even both devices are enabled and could touch at first)
  2. Multitouching breaks touchscreen