Custom libwacom .tablet files for Wacom devices

Hi everyone,

I have a GPD Pocket 3 convertible laptop, which has a Wacom-enabled touchscreen, however I’m currently unable to configure this via the GNOME desktop settings panel for this. On non-NixOS distros, I created a custom .tablet file which I can either copy to /usr/share/libwacom/ or /etc/libwacom/, update udev and update the libwacom database to fix this, however I’m not sure how to actually go about doing this in NixOS.

I’m currently using NixOS 22.11 and GNOME desktop, let me know if you need any further info or my configuration files and I’ll share as needed!

I took the “easy” option and simply created this in my configuration.nix:

{ config, lib, pkgs, modulesPath, ... }:

{

services.udev.packages = [ pkgs.unstable.libwacom ];
environment.etc = {
    "libwacom/GXTP7380.tablet" = {
    text = ''
# Example model file description for a tablet
#
# The .tablet file must have a name matching the device, usually
# the lowercase version of <vendor>-<model>.tablet. See existing data files
# for guidance, Wacom devices can skip the vendor name.
#
# In most cases, a tablet data file can be autogenerated, see the README
# in the wacom-hid-descriptors repository:
# https://github.com/linuxwacom/wacom-hid-descriptors/
#
# In 90% of remaining cases we already ship a file for a device that is
# similar to the new one to be added. The best approach is to copy that file
# and change it. This example file here describes all possible keys.
#
# To test a new file, copy it into /usr/share/libwacom/ and run
# libwacom-list-local-devices. This should show your device with all
# information from this file.
#
# The file should start with a pseudo-drawing of the device that illustrates
# where the buttons are. See the data/intuos5-m.tablet file for a full
# example:
#
# Wacom
# Intuos5 M
# PTK-650
#
# Button Map:
# (A=1, B=2, C=3, ...)
#
#    *-----------------------*
#    |                       |
#  B |                       |
#  C |                       |
#  D |                       |
#  E |                       |
#  A |        TABLET         |
#  F |                       |
#  G |                       |
#  H |                       |
#  I |                       |
#    |                       |
#    *-----------------------*
#
[Device]

# The name is the vendor and product name announced by the kernel. This
# filename is shown as device name by tools like libinput record,
# evemu-record or evtest.
Name=GXTP7380:00 27C6:0113 Stylus

# The unique model name for this device where it differs significantly from
# the Name. For example, Wacom has several devices named Wacom Intuos Pro
# but they all have a unique model name (e.g. PTH-660).
# Leave blank where the device name is sufficient to identify.
ModelName=

# DeviceMatch includes the bus (usb, bluetooth, serial), the vendor ID and
# product ID. This is the connector used, not whatever name the kernel
# might give it, so some "Wacom Serial" builtin devices will be USB
# as that's how they're connected.
#
# For example:
# $ lsusb | grep Wacom
# Bus 002 Device 003: ID 056a:00bc Wacom Co., Ltd Intuos4 6x9
# will give you the device match below.
#
# You can find a full list of known Device IDs at:
# https://github.com/linuxwacom/input-wacom/wiki/Device-IDs
#
# Do not add 0x in front of the hex numbers, make sure to pad each ID
# so it has exactly 4 digits. hex letters must be lowercase.
DeviceMatch=i2c:27c6:0113

# Paired PID includes the match line of any device that share the same
# physical device but has different product or vendor ids (e.g. the touch
# device on the 24HDT). The format of the match line is identical to
# DeviceMatch but only one value is permitted.
# Note: the PIDs listed may not be libwacom devices themselves.
#PairedIDs=

# Class of the tablet. Valid classes include Intuos3, Intuos4, Graphire, Bamboo, Cintiq
# If unsure, or not applicable (the tablet isn't stand-alone for example).
#
# The class is deprecated as of v1.4. For non-Wacom devices, set to Bamboo
# for external tablets and ISDV4 for built-in ones.
Class=

# (Optional) Width in inches, as advertised by the manufacturer
Width=7

# (Optional) Height in inches, as advertised by the manufacturer
Height=4.5

# Integration flags. Set to Display where the device is an external monitor
# (e.g. Cintiq) or Display;System where the device is built into the display
# of the system itself (i.e. part of a laptop). Leave empty for external
# tablets.
# Note, if unspecified, the integration flags will be taken from the kernel.
IntegratedIn=Display;System

# Filename of the SVG representing this tablet. Only needed for tablets with
# pad buttons.
#Layout=bamboo-16fg-m-pt.svg
# Styli
#
# This is a list of stylus IDs supported by the tablet. Non-Wacom devices
# usually do not support specific stylus IDs and default to the generic
# pens. If the stylus has an eraser:
# Styli=0xffffe;0xfffff;
# If the stylus does not have an eraser:
# Styli=0xffffd
#
# For Wacom devices this is needed only for the professional series devices,
# i.e. Intuos Pro and Cintiq.
#
# In general, differently sized models of the same range support the same
# styli, so you can copy/paste the list from another definition.
#
# After that, you can try piecing the stylus list from the names of the
# styli in libwacom.stylus, using the Wacom webshop as a reference
# (how many supported styli, what do they look like, etc.)
#
# Finally, if you cannot find any information about the styli supported
# by your device, you will need to gather the "Wacom Serial IDs",
# and getting each stylus in proximity of the tablet.
Styli=0xffffe;0xfffff;

# Optional features that this tablet supports
# Some features are dependent on the actual tool used, e.g. not all styli
# have an eraser and some styli have additional custom axes (e.g. the
# airbrush pen). These features describe those available on the tablet.
#
# Features not set in a file default to false/0

[Features]
# This tablet supports styli (and erasers, if present on the actual stylus)
Stylus=true

# Whether the tablet can be used left-handed.
# This is only for asymmetrical stand-alone tablets. The tablet
# is deemed reversible if the tablet can be turned 180 degrees
# so buttons are placed on the other side. The Intuos4 tablet
# is a great example of that.
Reversible=false

# This tablet supports touch.
Touch=true

# This tablet provides a hardware touch switch.
TouchSwitch=false

# This tablet has a touch ring (Intuos4 and Cintiq 24HD)
# A touch ring is a circular button that responds to touch
# (rather than clicks):
# http://intuos.wacom.com/americas/touch-ring.php
Ring=false
# This tablet has a second touch ring (Cintiq 24HD)
Ring2=false

# This tablet's number of strips, default is zero
NumStrips=0

# Number of buttons on the tablet
Buttons=0

# Metadata about the buttons on the tablet
# Buttons are "numbered" using upper-case letters
#[Buttons]
# Location of the buttons
#Left=A;B
#Right=C;D
#Top=
#Bottom=
## The evdev codes for the buttons in order A, B, C, ...
# The code must be defined for all buttons or this line is ignored
#EvdevCodes=0x110;0x112;0x111;0x113

#####################
# ADVANCED FEATURES #
#####################

# Those are only needed for a few professional tablets
# for which the values have already been filled in.

# Which buttons have OLEDs associated to them
# Only the Intuos4 devices had this.
# http://101.wacom.com/i4settings/images/expresskeys-feature.jpg
#OLEDs=B;C;D;E;F;G;H;I

# The location of the various rings, if associated with a button
# or buttons.
# For example, a single button in the middle of the touchring, like
# on the Intuos4 tablets. You will need to mention the number of modes
# that the button allows if there isn't one button per mode.
#Ring=A
#RingNumModes=4
# Or the 2nd touchring associated with 3 buttons like the Cintiq24HD
#Ring2=I;J;K
# Implied, as we have 3 buttons for that ring
#Ring2NumModes=3

# If the touchstrips have mode toggling through a button
# like on the Cintiq 21UX2
#Touchstrip=A
#Touchstrip2=J
# We assume the same number of modes for each of the touchstrips
# if there is more than one
#StripsNumModes=4

'';
};
};
}

However this doesn’t seem to have achieved the desired effect. If I try to manually run the “libwacom-update-db” command saying it can’t find the /etc/udev/hwdb.d/ directory which is to be expected. I understand I can add udev rules via the services.udev configuration options but I’m not actually sure what libwacom writes here exactly so I’m not sure what exactly to add.

Has anyone achieved this with the Pocket 3, or even anything that requires a similar custom configuration? I have already sent my .tablet file upstream to libwacom but it’s yet to be rolled in so this seems like my only option for now.

Thanks!

1 Like

I’m also having the same problem.
I’ve found with strace that libwacom is lookup-ing in "${libwacom}/etc" instead of /etc! But I don’t know how to fix this.
The problem with “libwacom-update-database” might be solved with just mkdir /etc/udev/hwdb.d/.
Regards.

This patch might fix the problem, but I haven’t tried it because it requires rebuilding some packages depending on libwacom.

index f767163..48d29fd 100644
--- a/meson.build
+++ b/meson.build
@@ -6,7 +6,7 @@ project('libwacom', 'c',
 
 dir_bin     = get_option('prefix') / get_option('bindir')
 dir_data    = get_option('prefix') / get_option('datadir') / 'libwacom'
-dir_etc     = get_option('prefix') / get_option('sysconfdir') / 'libwacom'
+dir_etc     = get_option('sysconfdir') / 'libwacom'
 dir_src     = meson.current_source_dir()  / 'libwacom'
 dir_src_data= meson.current_source_dir()  / 'data'
 dir_test    = meson.current_source_dir()  / 'test'

Looks like it worked for me with this:

dir_etc.patch:

diff --git a/meson.build b/meson.build
index f767163..0328630 100644
--- a/meson.build
+++ b/meson.build
@@ -6,7 +6,7 @@ project('libwacom', 'c',
 
 dir_bin     = get_option('prefix') / get_option('bindir')
 dir_data    = get_option('prefix') / get_option('datadir') / 'libwacom'
-dir_etc     = get_option('prefix') / get_option('sysconfdir') / 'libwacom'
+dir_etc     = '/' / get_option('sysconfdir') / 'libwacom'
 dir_src     = meson.current_source_dir()  / 'libwacom'
 dir_src_data= meson.current_source_dir()  / 'data'
 dir_test    = meson.current_source_dir()  / 'test'
...
system.replaceRuntimeDependencies = [{
  original = pkgs.libwacom;
  replacement = pkgs.libwacom.overrideAttrs (old: { patches = [ ./dir_etc.patch ] });
}];
...

And we’ll need to build with impure mode.

Since the project does not install anything to sysconfdir, you do not even need to patch the source:

--- a/pkgs/development/libraries/libwacom/default.nix
+++ b/pkgs/development/libraries/libwacom/default.nix
@@ -51,6 +51,7 @@ stdenv.mkDerivation rec {
 
   mesonFlags = [
     "-Dtests=${if doCheck then "enabled" else "disabled"}"
+    "--sysconfdir=/etc"
   ];
 
   checkInputs = [

Maybe something like the following will work (untested):

environment.etc =
  let
    tablet = ./foo.tablet;
  in {
    "libwacom/foo.tablet".source = tablet;
    # libwacom uses 65 as priority so we need a higher one in case there is a conflict.
    "udev/hwdb.d/96-libwacom-foo.hwdb".source = pkgs.runCommandLocal "foo.hwdb" { } ''
      ${pkgs.python3.interpreter} ${lib.getExe' pkgs.libwacom "libwacom-update-db"} --buildsystem-mode "${tablet}" > "$out"
    '';
  };

This fails with /nix/store/5cc92y090fh46rzmi3ac594bspni7591-libwacom-2.12.2/bin/libwacom-update-db: cannot execute: required file not found

Tested with:

  environment.etc =
  let
    tablet = ./google-jinlon.tablet;
  in {
    "libwacom/google-jinlon.tablet".source = tablet;
    # libwacom uses 65 as priority so we need a higher one in case there is a conflict.
    "udev/hwdb.d/96-libwacom-google-jinlon.hwdb".source = pkgs.runCommandLocal "google-jinlon.hwdb" { } ''
      ${lib.getExe' pkgs.libwacom "libwacom-update-db"} --buildsystem-mode " ${tablet}" > "$out"
    '';
  };

Looks like the libwacom-update-db program has /usr/bin/env python3 in shebang, which is not available in the sandbox, so it will need to be executed by Python explicitly. Additionally, I had an extra space in the file name argument. I have fixed the example above.

Also, do not forget you will also need to rebuild libwacom to actually load the files. Something like the following should do until libwacom: Load config from /etc by jtojnar · Pull Request #329208 · NixOS/nixpkgs · GitHub is available in your channel:

system.replaceRuntimeDependencies = [{
  original = pkgs.libwacom;
  replacement = pkgs.libwacom.overrideAttrs (old: {
    mesonFlags = old.mesonFlags ++ [ "--sysconfdir=/etc" ];
  });
}];

This builds fine, but it seems that libwacom does not detect the changes.
I am not sure about the order of environment and the replaceRuntimeDependencies, does it matter?

The order does not matter. But you will probably need to re-log in.

I rebooted after I built it. Did I do something wrong? Here is my complete config.

That looks good to me. Not sure what is wrong.