Skip to content

Commit

Permalink
wayland: implement tablet-v2
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed May 2, 2024
1 parent da2500a commit dee9962
Show file tree
Hide file tree
Showing 61 changed files with 5,173 additions and 314 deletions.
16 changes: 16 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,22 @@ You can use the `configure-input` action to change these settings at runtime.

See the specification for more details.

### Mapping Tablets to Outputs

You can map tablets to outputs using the `output` property:

```toml
[[outputs]]
name = "left"
match.serial-number = "33K03894SL0"

[[inputs]]
match.name = "Wacom Bamboo Comic 2FG Pen"
output.name = "left"
```

See the specification for more details.

# Theming

You can configure the colors, sizes, and fonts used by the compositor with the top-level `theme` table.
Expand Down
2 changes: 1 addition & 1 deletion docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ Jay supports the following wayland protocols:
| zwp_pointer_gestures_v1 | 3 | |
| zwp_primary_selection_device_manager_v1 | 1 | |
| zwp_relative_pointer_manager_v1 | 1 | |
| zwp_tablet_manager_v2 | 1 | |
| zwp_text_input_manager_v3 | 1 | |
| zwp_virtual_keyboard_manager_v1 | 1 | Yes |
| zxdg_decoration_manager_v1 | 1 | |
Expand All @@ -182,5 +183,4 @@ The following features are currently not supported but might get implemented in

- Fine-grained damage tracking.
- Touch support.
- Tablet support.
- Tearing updates of fullscreen games.
1 change: 1 addition & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Focus-follows-mouse can now be disabled.
- Add support for pointer-gestures-unstable-v1.
- Configs can now handle switch events (laptop lid closed/opened).
- Add support for tablet-v2.

# 1.1.0 (2024-04-22)

Expand Down
64 changes: 63 additions & 1 deletion src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ use {
drm_feedback::DrmFeedback,
fixed::Fixed,
gfx_api::{GfxFramebuffer, SyncFile},
ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
ifs::wl_seat::{
tablet::{
PadButtonState, TabletInit, TabletPadId, TabletPadInit, TabletRingEventSource,
TabletStripEventSource, TabletToolChanges, TabletToolId, TabletToolInit,
ToolButtonState,
},
wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
},
libinput::consts::DeviceCapability,
video::drm::{ConnectorType, DrmConnector, DrmError, DrmVersion},
},
Expand Down Expand Up @@ -122,6 +129,8 @@ pub trait HardwareCursor: Debug {

pub type TransformMatrix = [[f64; 2]; 2];

linear_ids!(InputDeviceGroupIds, InputDeviceGroupId, usize);

pub trait InputDevice {
fn id(&self) -> InputDeviceId;
fn removed(&self) -> bool;
Expand Down Expand Up @@ -165,6 +174,12 @@ pub trait InputDevice {
None
}
fn set_natural_scrolling_enabled(&self, enabled: bool);
fn tablet_info(&self) -> Option<Box<TabletInit>> {
None
}
fn tablet_pad_info(&self) -> Option<Box<TabletPadInit>> {
None
}
}

#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
Expand Down Expand Up @@ -317,6 +332,53 @@ pub enum InputEvent {
time_usec: u64,
event: SwitchEvent,
},

TabletToolAdded {
time_usec: u64,
init: Box<TabletToolInit>,
},
TabletToolChanged {
time_usec: u64,
id: TabletToolId,
changes: Box<TabletToolChanges>,
},
TabletToolButton {
time_usec: u64,
id: TabletToolId,
button: u32,
state: ToolButtonState,
},
TabletToolRemoved {
time_usec: u64,
id: TabletToolId,
},

TabletPadButton {
time_usec: u64,
id: TabletPadId,
button: u32,
state: PadButtonState,
},
TabletPadModeSwitch {
time_usec: u64,
pad: TabletPadId,
group: u32,
mode: u32,
},
TabletPadRing {
time_usec: u64,
pad: TabletPadId,
ring: u32,
source: Option<TabletRingEventSource>,
angle: Option<f64>,
},
TabletPadStrip {
time_usec: u64,
pad: TabletPadId,
strip: u32,
source: Option<TabletStripEventSource>,
position: Option<f64>,
},
}

pub enum DrmEvent {
Expand Down
92 changes: 88 additions & 4 deletions src/backends/metal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@ use {
crate::{
async_engine::SpawnedFuture,
backend::{
Backend, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId,
InputEvent, KeyState, TransformMatrix,
Backend, InputDevice, InputDeviceAccelProfile, InputDeviceCapability,
InputDeviceGroupId, InputDeviceId, InputEvent, KeyState, TransformMatrix,
},
backends::metal::video::{MetalDrmDeviceData, MetalRenderContext, PendingDrmDevice},
dbus::{DbusError, SignalHandler},
drm_feedback::DrmFeedback,
gfx_api::GfxError,
ifs::wl_seat::tablet::{
TabletId, TabletInit, TabletPadGroupInit, TabletPadId, TabletPadInit,
},
libinput::{
consts::{
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT, LIBINPUT_DEVICE_CAP_TABLET_PAD,
LIBINPUT_DEVICE_CAP_TABLET_TOOL,
},
device::RegisteredDevice,
device::{LibInputDevice, RegisteredDevice},
LibInput, LibInputAdapter, LibInputError,
},
logind::{LogindError, Session},
Expand All @@ -39,6 +43,7 @@ use {
gbm::GbmError,
},
},
bstr::ByteSlice,
std::{
any::Any,
cell::{Cell, RefCell},
Expand Down Expand Up @@ -286,18 +291,22 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<MetalBackend>, MetalError> {
}

struct MetalInputDevice {
state: Rc<State>,
slot: usize,
id: InputDeviceId,
devnum: c::dev_t,
fd: CloneCell<Option<Rc<OwnedFd>>>,
inputdev: CloneCell<Option<Rc<RegisteredDevice>>>,
devnode: CString,
_sysname: CString,
syspath: CString,
removed: Cell<bool>,
events: SyncQueue<InputEvent>,
cb: CloneCell<Option<Rc<dyn Fn()>>>,
name: CloneCell<Rc<String>>,
transform_matrix: Cell<Option<TransformMatrix>>,
tablet_id: Cell<Option<TabletId>>,
tablet_pad_id: Cell<Option<TabletPadId>>,

// state
pressed_keys: SmallMap<u32, (), 5>,
Expand Down Expand Up @@ -597,6 +606,71 @@ impl InputDevice for MetalInputDevice {
fn natural_scrolling_enabled(&self) -> Option<bool> {
self.effective.natural_scrolling_enabled.get()
}

fn tablet_info(&self) -> Option<Box<TabletInit>> {
let dev = self.inputdev.get()?;
let dev = dev.device();
if !dev.has_cap(LIBINPUT_DEVICE_CAP_TABLET_TOOL) {
return None;
}
let id = match self.tablet_id.get() {
Some(id) => id,
None => {
let id = self.state.tablet_ids.next();
self.tablet_id.set(Some(id));
id
}
};
Some(Box::new(TabletInit {
id,
group: self.get_device_group(&dev),
name: dev.name(),
pid: dev.product(),
vid: dev.vendor(),
path: self.syspath.as_bytes().as_bstr().to_string(),
}))
}

fn tablet_pad_info(&self) -> Option<Box<TabletPadInit>> {
let dev = self.inputdev.get()?;
let dev = dev.device();
if !dev.has_cap(LIBINPUT_DEVICE_CAP_TABLET_PAD) {
return None;
}
let id = match self.tablet_pad_id.get() {
Some(id) => id,
None => {
let id = self.state.tablet_pad_ids.next();
self.tablet_pad_id.set(Some(id));
id
}
};
let buttons = dev.pad_num_buttons();
let strips = dev.pad_num_strips();
let rings = dev.pad_num_rings();
let mut groups = vec![];
for n in 0..dev.pad_num_mode_groups() {
let Some(group) = dev.pad_mode_group(n) else {
break;
};
groups.push(TabletPadGroupInit {
buttons: (0..buttons).filter(|b| group.has_button(*b)).collect(),
rings: (0..rings).filter(|b| group.has_ring(*b)).collect(),
strips: (0..strips).filter(|b| group.has_strip(*b)).collect(),
modes: group.num_modes(),
mode: group.mode(),
});
}
Some(Box::new(TabletPadInit {
id,
group: self.get_device_group(&dev),
path: self.syspath.as_bytes().as_bstr().to_string(),
buttons,
strips,
rings,
groups,
}))
}
}

impl MetalInputDevice {
Expand All @@ -606,4 +680,14 @@ impl MetalInputDevice {
cb();
}
}

fn get_device_group(&self, dev: &LibInputDevice) -> InputDeviceGroupId {
let group = dev.device_group();
let mut id = group.user_data();
if id == 0 {
id = self.state.input_device_group_ids.next().raw();
group.set_user_data(id);
}
InputDeviceGroupId::from_raw(id)
}
}
Loading

0 comments on commit dee9962

Please sign in to comment.