Code Monkey home page Code Monkey logo

wacom-gui's Introduction

wacom-gui

Python/PyQt Wacom GUI for MATE/KDE

Screenshots

Getting Started

These instructions will help you get a copy of the project up and running on yoru local machine for development/testing purposes.

Prerequisites

You will require a few packages to get this working on your system:

  • PyQt5

Installing

  • Running from source
    • download the source, run wacom-gui.py from the wacom-gui directory
    • you can also build an RPM from the SPEC file in the wacom-gui directory
    • libwacom-data-1.11 or newer
  • Running from RPM
    • download the RPM, install
    • RPM can be added to a repository for deployment
    • menu option will appear under System > Preferences > Hardware > Wacom Tablet

Features

  • should work with any tablet detected by libwacom
  • per tablet model configuration files
  • supports multiple tablets at once, can be of the same model
  • refresh connected devices without restarting the interface
  • auto-load config on login
  • Configuration Features
    • Express Keys
      • Enable/Disable/Default options
      • supports modifier keys (Alt/Ctrl/Shift)
      • can create custom, global keystrokes
      • can create system hotkeys to run scripts/commands
    • Stylus/Eraser
      • pressure curve, sensitivity, various other options available
      • mapping input to specific display as well as enabling "force perspective" for drawing area
      • rotate tablet at 90° increments, as needed
      • multi-monitor support with toggle to easily swap displays
    • Touch
      • enable/disable, if available for device
      • enable/disable gestures, if desired as well as setting scroll/zoom sensitivity

Contributing

If you have found any bugs, have feature requests, or would like to contribute in some way please feel free to contact me.

License

This project is licensed under the GPL 3.0 License - See the LICENSE.nd file for details

Acknowledgements

touch icons:

Icons made by Mobiletuxedo from www.flaticon.com is licensed by CC 3.0 BY

All testing has been done on Rocky => 8.7. If you still require the GUI for CentOS 7, please use the last release (v0.3.1). Once some additional development is completed I will release an "official" Py3/Qt5 RPM but the current code release should be functional for use.

wacom-gui's People

Contributors

pinglinux avatar rafaelgss avatar skomra avatar tb2097 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wacom-gui's Issues

basic instalation info

Hello, I need to install this application on my centos 7 with gnome, since I want to use it with my wacom cintiq pro 24. In the documentation it indicates that there is an RPM to install. Where is it to download it?

Calibration?

Super happy to find this one - thank you for the work on the app. Can't wait to check it on OpenSUSE Leap 15 with Xfce.
Does it have any calibration capabilities? Would be great for fine tuning Cintiqs.

AttributeError: 'NoneType' object has no attribute 'replace'

I have just found out about this amazing tool, having used it on my school's computer. I installed it on my home workstation, but every time I run it, I get the following traceback from Python:

QPainter::begin: Paint device returned engine == 0, type: 2 QPainter::font: Painter not active QPainter::setFont: Painter not active QPainter::setPen: Painter not active QPainter::end: Painter not active, aborted Traceback (most recent call last): File "/usr/local/wacom-gui/wacom-gui.py", line 299, in <module> main() File "/usr/local/wacom-gui/wacom-gui.py", line 218, in main window = WacomGui() File "/usr/local/wacom-gui/wacom-gui.py", line 25, in __init__ self.initUI() File "/usr/local/wacom-gui/wacom-gui.py", line 32, in initUI self.cursorControl = pressure(self.pad.Tablet.deviceNames['cursor'], 'cursor') File "/usr/local/wacom-gui/pressure.py", line 312, in __init__ self.tabletName = name.replace('Pad', 'Pen') AttributeError: 'NoneType' object has no attribute 'replace'

This happens whether I am running it from the actual source files, or via the installed rpm.

I tried figuring out the problem on my own, since I know a little bit of Python, but without any luck. Any idea, what might be causing this issue.

I am sure it has nothing to do with the tablet itself, as I have tried it with two different ones (both should be supported) and, in both cases, I got the same outcome.

The models I used are:

  1. Bamboo Pen & Touch 4x5 (CTH-460K)
  2. Cintiq 13hd (DTK-1300)

PTH-660 not found on CentOS 7 when using Bluetooth

On CentOS 7.5, an Intuos Pro 2 M (PTH-660) over Bluetooth is identified by 'xsetwacom --list' as:

Wacom Intuos Pro M Pad pad              id: 16  type: PAD       
Wacom Intuos Pro M Pen stylus           id: 17  type: STYLUS    
Wacom Intuos Pro M Pen eraser           id: 18  type: ERASER    
Wacom Intuos Pro M Pen cursor           id: 19  type: CURSOR    
Wacom Intuos Pro M Finger touch         id: 20  type: TOUCH     

... which is the same as when connected over USB - and hence wacom-gui fails to find the tablet

I notice that the very latest libwacom-data has merged the intuos-pro-2-m.tablet and intuos-pro-2-m-wl.tablet in to a single intuos-pro-2-m.tablet file - see https://github.com/linuxwacom/libwacom/blob/master/data/intuos-pro-2-m.tablet - which has the line:

DeviceMatch=usb:056a:0357;bluetooth:056a:0360;

If I remove intuos-pro-2-m-wl.tablet and change intuos-pro-2-m.tablet as above, then wacom-gui finds the tablet

Tablet maps to 'wrong' screen if screen order is reversed

Another issue:

wacom-gui assumes 'Screen 0' is the left monitor, but if the order of the monitors is changed, then it maps the tablet to the 'other' screen

I believe the following patch fixes this - it sets the screen with the lowest top left x-coordinate to be the left screen (and also use round() when comparing screen coordinates)

--- ./wacom-gui/options.py.dist 2018-02-02 18:10:47.000000000 +0000
+++ ./wacom-gui/options.py      2018-04-06 12:03:48.677251539 +0100
@@ -15,6 +15,7 @@ class otherOptions(QtGui.QWidget):
         self.devices = []
         self.tabletActiveArea = ""
         self.orient = ''
+        self.screenOrder = [0, 1]
         
         #layout code
         self.mainLayout = QtGui.QHBoxLayout()
@@ -105,9 +106,9 @@ class otherOptions(QtGui.QWidget):
                     #    if self.otherOptionSettings[i].find("xinput set-prop") != -1 and self.otherOptionSettings[i].find(device) != -1:
                     #        self.otherOptionSettings[i] =  "xinput set-prop \"" + device + "\" --type=float \"Coordinate Transformation Matrix\" 1 0 0 0 1 0 0 0 1"
         elif buttonId.text() == "Left Monitor":
-            screen = QtGui.QDesktopWidget().screenGeometry(0)
+            screen = QtGui.QDesktopWidget().screenGeometry(self.screenOrder[0])
         elif buttonId.text() == "Right Monitor":
-            screen = QtGui.QDesktopWidget().screenGeometry(1)
+            screen = QtGui.QDesktopWidget().screenGeometry(self.screenOrder[1])
         if screen != "":
             totalResolution = os.popen("xdpyinfo | grep dimensions | awk '{print $2}' | awk -Fx '{print $1, $2}'").read()
             totalResolution = totalResolution.split()
@@ -164,6 +165,13 @@ class otherOptions(QtGui.QWidget):
         else:
             screen1 = QtGui.QDesktopWidget().screenGeometry(0)
             screen2 = QtGui.QDesktopWidget().screenGeometry(1)
+
+            # check order of screens - screen with the lowest x coord
+            # is assumed to be the left screen
+            if screen1.topLeft().x() > screen2.topLeft().x():
+                self.screenOrder = [1, 0]
+                (screen2, screen1) = (screen1, screen2)
+
             totalResolution = os.popen("xdpyinfo | grep dimensions | awk '{print $2}' | awk -Fx '{print $1, $2}'").read()
             totalResolution = totalResolution.split()
 
@@ -184,7 +192,7 @@ class otherOptions(QtGui.QWidget):
             isLeft = True
             for i in range(0,3):
                 for j in range(0,3):
-                    if float(tabletScreenCoords[(i,j)]) != float(display[i][j]):
+                    if round(float(tabletScreenCoords[(i,j)]),6) != round(float(display[i][j]),6):
                         isLeft = False
                         break
 
@@ -205,7 +213,7 @@ class otherOptions(QtGui.QWidget):
                 isRight = True
                 for i in range(0,3):
                     for j in range(0,3):
-                        if float(tabletScreenCoords[(i,j)]) != float(display[i][j]):
+                        if round(float(tabletScreenCoords[(i,j)]),6) != round(float(display[i][j]),6):
                             isRight = False
                             break
                 if isRight:

Device info not found, but dev_type string is OK---Wacom Intuos Pro L

Thanks in advance.

I've looked and found similar issues (and the corresponding hacks in the current master of wacom_data.py), where there is some sort of naming mismatch leading to the titled error:

Device information for "Wacom Intuos Pro L" not found.

If I understand correctly, then the strange thing in my case is that all of the device-type strings agree! That is, libwacom-list-local-devices, xsetwacom --list devices and the Name= line of /usr/share/libwacom/intuos-pro-l.tablet all agree with the dev_type string in wacom_data.py. (See listed items below.)

Thanks again for your time---even if you only have time to point me in a direction.

> libwacom-list-local-devices --database /usr/share/libwacom 
# Device node: /dev/input/event6
[Device]
Name=Wacom Intuos Pro L
ModelName=PTH-851
DeviceMatch=usb:056a:0317;
Class=Intuos5
Width=13
Height=8
IntegratedIn=
Layout=intuos-pro-l.svg
Styli=0x6;0x802;0x804;0x806;0x80a;0x80c;0x902;0x90a;0x100802;0x100804;0x10080a;0x10080c;0x100902;0x10090a;0x120802;0x140802;0x14080a;0x160802;0x16080a;

[Features]
Reversible=true
Stylus=true
Ring=true
Ring2=false
Touch=true
TouchSwitch=false
StatusLEDs=Ring;
NumStrips=0
Buttons=9

[Buttons]
Left=A;B;C;D;E;F;G;H;I;
# Right=
# Top=
# Bottom=
# Touchstrip=
# Touchstrip2=
# OLEDs=
Ring=A;
# Ring2=
EvdevCodes=0x100;0x101;0x102;0x103;0x104;0x105;0x106;0x107;0x108;
RingNumModes=4
Ring2NumModes=0
StripsNumModes=0

---------------------------------------------------------------
# Device node: /dev/input/event4
[Device]
Name=Wacom Intuos Pro L
ModelName=PTH-851
DeviceMatch=usb:056a:0317;
Class=Intuos5
Width=13
Height=8
IntegratedIn=
Layout=intuos-pro-l.svg
Styli=0x6;0x802;0x804;0x806;0x80a;0x80c;0x902;0x90a;0x100802;0x100804;0x10080a;0x10080c;0x100902;0x10090a;0x120802;0x140802;0x14080a;0x160802;0x16080a;

[Features]
Reversible=true
Stylus=true
Ring=true
Ring2=false
Touch=true
TouchSwitch=false
StatusLEDs=Ring;
NumStrips=0
Buttons=9

[Buttons]
Left=A;B;C;D;E;F;G;H;I;
# Right=
# Top=
# Bottom=
# Touchstrip=
# Touchstrip2=
# OLEDs=
Ring=A;
# Ring2=
EvdevCodes=0x100;0x101;0x102;0x103;0x104;0x105;0x106;0x107;0x108;
RingNumModes=4
Ring2NumModes=0
StripsNumModes=0

---------------------------------------------------------------
# Device node: /dev/input/event11
[Device]
Name=Wacom Intuos Pro L
ModelName=PTH-851
DeviceMatch=usb:056a:0317;
Class=Intuos5
Width=13
Height=8
IntegratedIn=
Layout=intuos-pro-l.svg
Styli=0x6;0x802;0x804;0x806;0x80a;0x80c;0x902;0x90a;0x100802;0x100804;0x10080a;0x10080c;0x100902;0x10090a;0x120802;0x140802;0x14080a;0x160802;0x16080a;

[Features]
Reversible=true
Stylus=true
Ring=true
Ring2=false
Touch=true
TouchSwitch=false
StatusLEDs=Ring;
NumStrips=0
Buttons=9

[Buttons]
Left=A;B;C;D;E;F;G;H;I;
# Right=
# Top=
# Bottom=
# Touchstrip=
# Touchstrip2=
# OLEDs=
Ring=A;
# Ring2=
EvdevCodes=0x100;0x101;0x102;0x103;0x104;0x105;0x106;0x107;0x108;
RingNumModes=4
Ring2NumModes=0
StripsNumModes=0
> xsetwacom --list devices                                  
Wacom Intuos Pro L Pen stylus   	id: 9	type: STYLUS    
Wacom Intuos Pro L Pad pad      	id: 10	type: PAD       
Wacom Intuos Pro L Finger touch 	id: 11	type: TOUCH     
Wacom Intuos Pro L Pen eraser   	id: 17	type: ERASER    
Wacom Intuos Pro L Pen cursor   	id: 18	type: CURSOR    
> cat /usr/share/libwacom/intuos-pro-l.tablet
# Wacom
# Intuos Pro L
# PTH-851
#
# Button Map:
# (A=1, B=2, C=3, ...)
#
#    *-----------------------*
#    |                       |
#  B |                       |
#  C |                       |
#  D |                       |
#  E |                       |
#  A |        TABLET         |
#  F |                       |
#  G |                       |
#  H |                       |
#  I |                       |
#    |                       |
#    *-----------------------*
#
# Touch Ring Map:
# (A=1st ring, B=2nd ring, ...)
#
#    *-----------------------*
#    |                       |
#  A |        TABLET         |
#    |                       |
#    *-----------------------*
#
# LED Map:
# (XY=Bank X, LED Y; *=Invisible)
#
#        *-----------------------*
#        |                       |
#        |                       |
#  00 01 |                       |
#        |        TABLET         |
#  03 02 |                       |
#        |                       |
#        |                       |
#        *-----------------------*
#

[Device]
Name=Wacom Intuos Pro L
ModelName=PTH-851
DeviceMatch=usb:056a:0317
Class=Intuos5
Width=13
Height=8
Layout=intuos-pro-l.svg
IntegratedIn=
Styli=@intuos4-lens;@intuos4-puck;@intuos5;@intuos4;

[Features]
Stylus=true
Reversible=true
Touch=true
Buttons=9
Ring=true
StatusLEDs=Ring

[Buttons]
Left=A;B;C;D;E;F;G;H;I

Ring=A
RingNumModes=4

Any plans for PyQt5 ?

Hello,

This seems a nice approach for wacom settings, as it follows the "official" design of the elements and settings options. Thanks for making it. I'm trying it right now on Manjaro XFCE, but firsti have to compile the python-pyqt4 from AUR, and for arch based distribution this is not quite efficient ...
Any plans to port it to PyQt5?
Cheers!

Crash when using tablets that have different device names

When using a Intuos Pro M (PTH-651), wacom-gui crashes with:

Cannot find device 'Wacom Intuos Pro M Finger  touch'.
Traceback (most recent call last):
  File "/usr/local/wacom-gui/wacom-gui.py", line 305, in <module>
    main()    
  File "/usr/local/wacom-gui/wacom-gui.py", line 218, in main
    window = WacomGui()
  File "/usr/local/wacom-gui/wacom-gui.py", line 25, in __init__
    self.initUI()
  File "/usr/local/wacom-gui/wacom-gui.py", line 33, in initUI
    self.touch = touch(self.pad.Tablet.deviceNames['touch'])
  File "/usr/local/wacom-gui/touch.py", line 16, in __init__
    self.initUI()
  File "/usr/local/wacom-gui/touch.py", line 27, in initUI
    self.getEnableStatus()
  File "/usr/local/wacom-gui/touch.py", line 47, in getEnableStatus
    if getCommand[0] == "on\n":
IndexError: list index out of range

Not sure why touch.py is re-assigning 'tabletName' - as it already has it set correctly ???

The following patch tidies this all up - plus removes a later unnecessary check :

--- ./wacom-gui/touch.py.dist   2018-05-28 17:13:39.000000000 +0100
+++ ./wacom-gui/touch.py        2018-06-05 10:54:55.279117673 +0100
@@ -6,20 +6,14 @@ import sys, os, re
 class touch(QtGui.QWidget):
     def __init__(self, tabletName, parent=None):
         QtGui.QWidget.__init__(self, parent)
-        devices = os.popen("xsetwacom --list devices").readlines()
-        self.tabletName = None
-        for device in devices:
-            attr = device.strip().split('\t')
-            if attr[2] == 'type: TOUCH':
-                self.tabletName = attr[0][:-6]
-                self.enable = None
+        if tabletName ==  "":
+            return None
+        self.tabletName = tabletName
+        self.enable = None
         self.initUI()
 
     def initUI(self):
         self.devices = []
-        # check if it is even necessary
-        if os.popen("xsetwacom --list devices | grep touch").readlines().__len__() == 0:
-            return None
         # layout code
         self.mainLayout = QtGui.QHBoxLayout()
         self.mainLayout.setAlignment(QtCore.Qt.AlignLeft)

Crash with Intuos PT 2 CTH-690

Hi i have somme issue with wacom-gui
i try with rc17 and rc18. i'm on Centos 7.7
Out of box i have this error : Device information for "Wacom Intuos PT M 2" not found
But im go to data folder and change name in intuos-m-pt2.tablet to Wacom Intuos PT M 2
Buit when i try to lunch i have this error :

Qt: Session management error: None of the authentication protocols specified are supported
error: The connection is closed

Usage:
dconf load DIR

Populate a subpath from stdin

Arguments:
DIR A directory path (starting and ending with '/')

invalid literal for float(): 13.0,25.25
invalid literal for float(): 13.0,25.25
Traceback (most recent call last):
File "wacom-gui.py", line 746, in
main()
File "wacom-gui.py", line 738, in main
form = WacomGui()
File "wacom-gui.py", line 70, in init
self.refreshTablets()
File "wacom-gui.py", line 113, in refreshTablets
self.tabletSelect(0)
File "wacom-gui.py", line 304, in tabletSelect
self.setToolsAvail(idx)
File "wacom-gui.py", line 139, in setToolsAvail
self.tablet_data.tablets[self.dev][self.dev_id]['eraser']['id']]
KeyError: 'eraser'

my xsetwacom list :

Wacom Intuos PT M 2 Pad pad id: 12 type: PAD
Wacom Intuos PT M 2 Pen stylus id: 13 type: STYLUS
Wacom Intuos PT M 2 Finger touch id: 14 type: TOUCH

my libwacom-list-local-devices :

[Device]
Name=Intuos Pen & Touch Medium
DeviceMatch=usb:056a:033e;
Class=Bamboo
Width=9
Height=5
IntegratedIn=
Layout=intuos-m-pt2.svg
Styli=0x8e2;

[Features]
Reversible=false
Stylus=true
Ring=false
Ring2=false
Touch=true
TouchSwitch=true
StatusLEDs=
NumStrips=0
Buttons=4
[Buttons]
Left=
Right=
Top=A;B;C;D;
Bottom=
Touchstrip=
Touchstrip2=
OLEDs=
Ring=
Ring2=
EvdevCodes=0x110;0x111;0x115;0x116;
RingNumModes=0
Ring2NumModes=0
StripsNumModes=0


[Device]
Name=Intuos Pen & Touch Medium
DeviceMatch=usb:056a:033e;
Class=Bamboo
Width=9
Height=5
IntegratedIn=
Layout=intuos-m-pt2.svg
Styli=0x8e2;

[Features]
Reversible=false
Stylus=true
Ring=false
Ring2=false
Touch=true
TouchSwitch=true
StatusLEDs=
NumStrips=0
Buttons=4
[Buttons]
Left=
Right=
Top=A;B;C;D;
Bottom=
Touchstrip=
Touchstrip2=
OLEDs=
Ring=
Ring2=
EvdevCodes=0x110;0x111;0x115;0x116;
RingNumModes=0
Ring2NumModes=0
StripsNumModes=0


[Device]
Name=Intuos Pen & Touch Medium
DeviceMatch=usb:056a:033e;
Class=Bamboo
Width=9
Height=5
IntegratedIn=
Layout=intuos-m-pt2.svg
Styli=0x8e2;

[Features]
Reversible=false
Stylus=true
Ring=false
Ring2=false
Touch=true
TouchSwitch=true
StatusLEDs=
NumStrips=0
Buttons=4
[Buttons]
Left=
Right=
Top=A;B;C;D;
Bottom=
Touchstrip=
Touchstrip2=
OLEDs=
Ring=
Ring2=
EvdevCodes=0x110;0x111;0x115;0x116;
RingNumModes=0
Ring2NumModes=0
StripsNumModes=0


Sourcing ~/.wacom-gui.sh from ~/.bashrc - not a good idea?

Running X11 specific commands (xsetwacom and xinput) from ~/.bashrc is not a good idea ...

This sort of thing should really be run from an autostart .desktop file - I would suggest either creating or copying in a suitable desktop file to ~/.config/autostart/ that execs ~/.wacom-gui.sh instead?

Add support for CTL-4100K, CTL-4100WL and CTL-6100WL

Wacom seems to have updated their line-up recently with these three new models of the Wacom Intuos.

They are detected with xsetwacom and they are working fine on Linux, but I still haven't managed to set any parameters on them using xsetwacom, and they are not working with the GUI.

When I try running the GUI, this is the error I get:

Button number does not exist on device.
Traceback (most recent call last):
File "/usr/local/wacom-gui/wacom-gui.py", line 313, in
main()
File "/usr/local/wacom-gui/wacom-gui.py", line 232, in main
window = WacomGui()
File "/usr/local/wacom-gui/wacom-gui.py", line 25, in init
self.initUI()
File "/usr/local/wacom-gui/wacom-gui.py", line 29, in initUI
self.pad = Pad()
File "/usr/local/wacom-gui/pad.py", line 22, in init
self.initUI()
File "/usr/local/wacom-gui/pad.py", line 170, in initUI
if getCommand[0] == "button +0 \n":
IndexError: list index out of range

Any chance you can add support for them?

Wacom Pro Not Recognized on CentOS 7

I'm running CentOS Linux release 7.5.1804 in my studio, the artists like MATE so this project is a huge help for us. We recently upgraded to Intuos Pro tablets and its recognized by X as "Intuos Pro M" instead of "Intuos Pro".

I edited wacom_data.py to

 # PTH-660/PTH-860 hack
            if dev_type == 'Wacom Intuos Pro M':

as a workaround. Not sure if other builds are affected by this issue

Express Keys Orientation

I cant seem to find the setting to tell the software you're using the tablet as a southpaw with the express keys to the right.
Is this available?

Intuos Pro L Paper not recognized

When I start wacom-gui form source (master) I get popup reporting unknown device "Wacom Intuos Pro L". I noticed there are already several similar issues raised for other tablet models. libwacom-list-local-devices reports device name "Wacom Intuos Pro 2 L WL"

Tried adding hack similar to previous ones, the error goes away but the window comes up empty, same as with the error

                if dev_type == 'Wacom Intuos Pro L':
                    dev_type = 'Wacom Intuos Pro 2 L WL'

Device information for "Wacom Bamboo One M" not found.

Recently I've switched to Linux and decided to use my tablet, definitely got tired of setting work area via terminal commands.
My tablet: One by Wacom M / CTL-671
Unfortunately I'm receiving 2 errors while launching wacom-gui:
obraz
After that, said GUI shows nothing - no model, no available options, basically nothing - I can try to refresh connected device but (put title of this issue here) error pops up.

When launching with terminal (not sure if important):

(python:23552): dbind-WARNING **: 19:37:47.222: Couldn't register with accessibility bus: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.

xsetwacom list:

Wacom Bamboo One M Pen stylus id: 10 type: STYLUS
Wacom Bamboo One M Pen eraser id: 11 type: ERASER

and at last, libwacom-list-local-devices --database /usr/local/wacom-gui/data

[Device]
Name=One by Wacom (medium)
ModelName=
DeviceMatch=usb:056a:0301;
Class=Bamboo
Width=9
Height=5
IntegratedIn=
Styli=0xffffe;0xfffff;
[Features]
Reversible=true
Stylus=true
Ring=false
Ring2=false
Touch=false
TouchSwitch=false
(there was hash sign here) StatusLEDs=
NumStrips=0
Buttons=0


Startup errors with Wacom Intuos S

Using Ubuntu 18.04 with XFce.


When tablet is not connected :
garrom@GarromMachine:~/Plocha/wacom-gui-0.3.0-rc1/wacom-gui$ python '/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom-gui.py' Traceback (most recent call last): File "/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom-gui.py", line 429, in <module> main() File "/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom-gui.py", line 424, in main form = WacomGui() File "/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom-gui.py", line 62, in __init__ self.refreshTablets() File "/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom-gui.py", line 88, in refreshTablets self.tablet_data.get_connected_tablets() File "/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom_data.py", line 61, in get_connected_tablets self.__get_libwacom_data() File "/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom_data.py", line 186, in __get_libwacom_data if data['pad']['buttons'].__len__() == 0: KeyError: 'buttons'


After I connected tablet :
garrom@GarromMachine:~/Plocha/wacom-gui-0.3.0-rc1/wacom-gui$ python '/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom-gui.py' Traceback (most recent call last): File "/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom-gui.py", line 11, in <module> from wacom_data import Tablets File "/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom_data.py", line 390, in <module> tablet_test = Tablets() File "/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom_data.py", line 32, in __init__ self.get_connected_tablets() File "/home/garrom/Plocha/wacom-gui-0.3.0-rc1/wacom-gui/wacom_data.py", line 68, in get_connected_tablets devID = self.device_data[dev_type]['devID'] KeyError: 'Wacom Intuos S Pad'


Is support for my tablet missing ?
-Garrom

tabletActiveArea not set on single screen

When the prefs are written on a single screen system, tabletActiveArea is empty, so the xinput command line has the wrong syntax - e.g.

xinput set-prop "Wacom Intuos4 6x9 stylus" --type=float "Coordinate Transformation Matrix"

i.e. it is missing the actual Matrix ... which gives errors when attempting to load the prefs

A simple fix could be:

--- ./wacom-gui/options.py.dist 2018-05-23 22:45:22.000000000 +0100
+++ ./wacom-gui/options.py      2018-05-24 14:39:13.605167721 +0100
@@ -175,10 +175,12 @@ class otherOptions(QtGui.QWidget):
 
     def getScreenArea(self):
         setCommands = []
+        if self.tabletActiveArea == "":
+            self.tabletActiveArea = "HEAD-0"
         for device in self.devices:
             if device != "pad" and device != 'touch':
                 if 'HEAD' in self.tabletActiveArea:
-                    setCommands.append("xsetwacom set \"%s %s\" MapToOutput %s" %
+                    setCommands.append("xsetwacom --set \"%s %s\" MapToOutput %s" %
                                        (self.deviceNames[device], device, self.tabletActiveArea))
                 else:
                     setCommands.append("xinput set-prop \"%s %s\" --type=float \"Coordinate Transformation Matrix\" %s"

(also change 'xsetwacom set' to 'xsetwacom --set' to be consistent with the other xsetwacom prefs)

Feature Request: Add support for monitor aspect mapping

Some of our users prefer to have a tablet area that matches their monitor(s) aspect ratio - i.e. so a circle on the tablet is a circle on screen etc - even when using 2 monitors (which means only half the tablet area is used) - but is also useful when just using one monitor that doesn't match the aspect ratio of the tablet

The (largish) patch below adds this support to the 'Other Settings' tab

A few notes:

wacom-gui current assumes the tablet is in landscape mode which (usually) maps to monitor(s) also in landscape mode. The selectable Aspect Mapping setting are:

  • 'None' - no aspect mapping
  • 'Top' - the upper part of the tablet is mapped to the monitor(s)
  • 'Middle' - the middle part of the tablet is mapped to the monitor(s)
  • 'Bottom' - the lower part of the tablet is mapped to the monitor(s)

However, if the monitor(s) are in a portrait layout (screen width is less than height), then the Aspect Mappings will map to the Right, Middle and Left parts of the tablet area - corresponding to the Top, Middle and Bottom selections (there isn't any support if the tablet is used in portrait mode ...)

To make life a lot easier, the patch also adds support for 'preferences' that are saved and loaded when wacom-gui exits/starts - which saves having to probe the wacom device for settings and attempting to match with what wacom-gui expects.

I've added preferences not only for the "Aspect Mapping" settings, but for the "Screen Area" and "Tablet Orientation" settings - if there are no existing saved settings for these, it will fall-back to probing the device as before. Adding preferences for "Tablet Orientation" is not actually needed for Aspect Mapping support, but as I had added it for "Screen Area", it seemed silly not to :-)

These preferences are saved in a file 'prefs.json' in the same directory as the 'default.sh' script for each tablet type

AFAIK, it all appears to work as expected - however, python is not my first language, so there may well be more pythonesque ways of doing what it does ...

Let me know what you think

--- ./wacom-gui/help.html.dist  2018-06-19 16:08:27.000000000 +0100                                        
+++ ./wacom-gui/help.html       2018-07-31 12:05:57.343886905 +0100                                        
@@ -134,6 +134,7 @@ section ul {                                                                           
         <section id="other"><h2>Other Settings</h2>                                                       
             <ul>                                                                                          
                 <li>Map tablet input to a specific monitor or all (if more than one)</li>                 
+                <li>Map tablet area keeping the aspect ratio of the screen(s) using the Top, Middle or Bottom of the tablet - <b>Note</b>: if screen(s) are in 'portrait' mode, then Top will map to the Left of the tablet and Bottom to the Right of the tablet</li>                                                                         
                 <li>Switch tablet between left and right orientation</li>                                      
                 <li>Restore tablet to all default settings</li>                                                
             </ul>                                                                                              
--- ./wacom-gui/options.py.dist 2018-06-19 16:08:27.000000000 +0100                                             
+++ ./wacom-gui/options.py      2018-07-31 12:05:57.344886918 +0100                                             
@@ -7,7 +7,7 @@ import re                                                                                       
                                                                                                                
                                                                                                                
 class otherOptions(QtGui.QWidget):                                                                             
-    def __init__(self, deviceNames, parent=None):                                                              
+    def __init__(self, deviceNames, prefs, parent=None):                                                       
         QtGui.QWidget.__init__(self, parent)                                                                   
         #self.tabletName = tabletName.replace('Pad', 'Pen')                                                    
         # use the detected device names                                                                        
@@ -17,16 +17,20 @@ class otherOptions(QtGui.QWidget):                                                          
         self.tabletTouch = deviceNames['touch']                                                                
         self.tabletPad = deviceNames['pad']                                                                    
         self.deviceNames = deviceNames                                                                         
+        self.prefs = prefs                                                                                     
+        #print prefs                                                                                           
         self.initUI()                                                                                          
                                                                                                                
                                                                                                                
     def initUI(self):                                                                                          
         self.devices = []                                                                                      
         self.tabletActiveArea = ""                                                                             
+        self.tabletAspectArea = "-1 -1 -1 -1"                                                                  
         self.orient = ''                                                                                       
         # layout code                                                                                          
         self.mainLayout = QtGui.QHBoxLayout()                                                                  
         self.mainLayout.setAlignment(QtCore.Qt.AlignLeft)                                                      
+        self.mainLayout.addWidget(self.aspectOptions())                                                        
         screens = self.screenOptions()                                                                         
         if screens:                                                                                            
             self.mainLayout.addWidget(screens)                                                                 
@@ -35,25 +39,64 @@ class otherOptions(QtGui.QWidget):                                                          
         self.setLayout(self.mainLayout)                                                                        
                                                                                                                
                                                                                                                
+    def aspectOptions(self):                                                                                   
+        groupBox = QtGui.QGroupBox("Aspect Mapping")                                                           
+        groupBox.setAlignment(QtCore.Qt.AlignHCenter)                                                          
+        groupBox.setFixedHeight(120)                                                                           
+        self.aspectGroup = QtGui.QButtonGroup(groupBox)                                                        
+        self.aspectNone = QtGui.QRadioButton("None")                                                           
+        self.aspectTop = QtGui.QRadioButton("Top")                                                             
+        self.aspectMiddle = QtGui.QRadioButton("Middle")                                                       
+        self.aspectBottom = QtGui.QRadioButton("Bottom")                                                       
+        self.aspectGroup.addButton(self.aspectNone)                                                            
+        self.aspectGroup.addButton(self.aspectTop)                                                             
+        self.aspectGroup.addButton(self.aspectMiddle)                                                          
+        self.aspectGroup.addButton(self.aspectBottom)                                                          
+        aspectLayout = QtGui.QVBoxLayout()                                                                     
+        aspectLayout.addWidget(self.aspectNone)                                                                
+        aspectLayout.addWidget(self.aspectTop)                                                                 
+        aspectLayout.addWidget(self.aspectMiddle)                                                              
+        aspectLayout.addWidget(self.aspectBottom)                                                              
+       aspectLayout.addStretch(1)                                                                              
+        # See if we have saved prefs                                                                           
+       if "Aspect Mapping" in self.prefs:                                                                      
+            if self.prefs['Aspect Mapping'] == "None":                                                         
+                self.aspectNone.setChecked(1)                                                                  
+            elif self.prefs['Aspect Mapping'] == "Top":                                                        
+                self.aspectTop.setChecked(1)                                                                   
+            elif self.prefs['Aspect Mapping'] == "Middle":                                                     
+                self.aspectMiddle.setChecked(1)                                                                
+            elif self.prefs['Aspect Mapping'] == "Bottom":                                                     
+                self.aspectBottom.setChecked(1)                                                                
+        else:                                                                                                  
+            # Default is 'None'                                                                                
+            self.aspectNone.setChecked(1)                                                                      
+            self.prefs['Aspect Mapping'] = "None"                                                              
+        self.aspectGroup.buttonClicked.connect(self.aspectChange)                                              
+        groupBox.setLayout(aspectLayout)                                                                       
+        return groupBox                                                                                        
+                                                                                                               
+                                                                                                               
     def screenOptions(self):                                                                                   
         if QtGui.QDesktopWidget().numScreens() == 1:                                                           
             self.screenFull = None                                                                             
+            self.prefs['Screen Area'] = "All Monitors"                                                         
             return None                                                                                        
         groupBox = QtGui.QGroupBox("Screen Area")                                                              
         groupBox.setAlignment(QtCore.Qt.AlignHCenter)                                                          
         groupBox.setFixedHeight(120)                                                                           
         self.screenGroup = QtGui.QButtonGroup(groupBox)                                                        
         self.displays = []                                                                                     
+        self.screenFull = QtGui.QRadioButton("All Monitors")                                                   
         for x in range(0, QtGui.QDesktopWidget().numScreens()):                                                
             self.displays.append(QtGui.QRadioButton("Monitor %d" % x))                                         
-        self.screenFull = QtGui.QRadioButton("All Monitors")                                                   
         for screen in self.displays:                                                                           
             self.screenGroup.addButton(screen)                                                                 
         self.screenGroup.addButton(self.screenFull)                                                            
         screenLayout = QtGui.QVBoxLayout()                                                                     
+        screenLayout.addWidget(self.screenFull)                                                                
         for screen in self.displays:                                                                           
             screenLayout.addWidget(screen)                                                                     
-        screenLayout.addWidget(self.screenFull)                                                                
         screenLayout.addStretch(1)                                                                             
         self.screenGroup.buttonClicked.connect(self.screenChange)                                              
         groupBox.setLayout(screenLayout)                                                                       
@@ -73,16 +116,29 @@ class otherOptions(QtGui.QWidget):                                                         
         flipLayout.addWidget(self.tabletRight)                                                                 
         flipLayout.addWidget(self.tabletLeft)                                                                  
         flipLayout.addStretch(1)                                                                               
-        getCommand = os.popen("xsetwacom --get \"%s stylus\" Rotate" % self.tabletStylus).readlines()          
-        # check correct button for orientation                                                                 
-        if getCommand[0] == "none\n":                                                                          
-            self.orient = "xsetwacom --set \"%s stylus\" Rotate none" % self.tabletStylus                      
-            self.orient += "\nxsetwacom --set \"%s eraser\" Rotate none" % self.tabletEraser                   
-            self.tabletRight.setChecked(1)                                                                     
-        elif getCommand[0] == "half\n":                                                                        
-            self.orient = "xsetwacom --set \"%s stylus\" Rotate half" % self.tabletStylus                      
-            self.orient += "\nxsetwacom --set \"%s eraser\" Rotate half" % self.tabletEraser                   
-            self.tabletLeft.setChecked(1)                                                                      
+        # See if we have saved prefs - if we don't, probe for existing setting                                 
+        if "Tablet Orientation" in self.prefs:                                                                 
+            if self.prefs['Tablet Orientation'] == "Right-Handed":                                             
+                self.tabletRight.setChecked(1)                                                                 
+            elif self.prefs['Tablet Orientation'] == "Left-Handed":                                            
+                self.tabletLeft.setChecked(1)                                                                  
+        else:                                                                                                  
+            getCommand = os.popen("xsetwacom --get \"%s stylus\" Rotate" % self.tabletStylus).readlines()      
+            # check correct button for orientation                                                             
+            if getCommand[0] == "none\n":                                                                      
+                self.orient = "xsetwacom --set \"%s stylus\" Rotate none" % self.tabletStylus                  
+                self.orient += "\nxsetwacom --set \"%s eraser\" Rotate none" % self.tabletEraser               
+                self.tabletRight.setChecked(1)                                                                 
+                self.prefs['Tablet Orientation'] = "Right-Handed"                                              
+            elif getCommand[0] == "half\n":                                                                    
+                self.orient = "xsetwacom --set \"%s stylus\" Rotate half" % self.tabletStylus                  
+                self.orient += "\nxsetwacom --set \"%s eraser\" Rotate half" % self.tabletEraser               
+                self.tabletLeft.setChecked(1)                                                                  
+                self.prefs['Tablet Orientation'] = "Left-Handed"                                               
+            else:                                                                                              
+                # Default to Right-Handed                                                                      
+                self.tabletRight.setChecked(1)                                                                 
+                self.prefs['Tablet Orientation'] = "Right-Handed"                                              
         self.tabletFlipGroup.buttonClicked.connect(self.tabletFlipChange)                                      
         groupBox.setLayout(flipLayout)                                                                         
         return groupBox                                                                                        
@@ -95,11 +151,87 @@ class otherOptions(QtGui.QWidget):                                                         
         elif buttonId.text() == "Left-Handed":                                                                 
             self.orient = "xsetwacom --set \"%s stylus\" Rotate half" % self.deviceNames['stylus']             
             self.orient += "\nxsetwacom --set \"%s eraser\" Rotate half" % self.deviceNames['eraser']          
+        self.prefs['Tablet Orientation'] = str(buttonId.text())                                                
         flipTablet = os.popen(self.orient)                                                                     
                                                                                                                
+    def aspectChange(self, buttonId):                                                                          
+        self.aspectChangeMain(str(buttonId.text()), False)                                                     
+                                                                                                               
+                                                                                                               
+    def aspectChangeMain(self, buttonText, screenDone):                                                        
+        self.prefs['Aspect Mapping'] = buttonText                                                              
+        #print self.prefs['Aspect Mapping']                                                                    
+                                                                                                               
+        # reset the tablet area to the full tablet before getting the area                                     
+        self.tabletAspectArea = "-1 -1 -1 -1"                                                                  
+        cmd = "xsetwacom --set \"%s stylus\" area %s" % (self.deviceNames['stylus'], self.tabletAspectArea)    
+        cmd += "\nxsetwacom --get \"%s stylus\" area" % self.deviceNames['stylus']                             
+        [tx, ty] = os.popen(cmd).read().split()[2:]                                                            
+                                                                                                               
+        # if set to "None" - we don't need to do any more here                                                 
+        if buttonText == "None":                                                                               
+            self.tabletAspectArea = "-1 -1 -1 -1"                                                              
+        else:                                                                                                  
+            sa = self.prefs['Screen Area']                                                                     
+            if sa == "All Monitors":                                                                           
+                # get the total screen dimensions                                                              
+                cmd = "xdpyinfo | grep dimensions | awk '{print $2}' | awk -Fx '{print $1, $2}'"               
+                [sx, sy] = os.popen(cmd).read().split()                                                        
+            else:                                                                                              
+                # get the dimensions on the current Monitor                                                    
+                id = sa.split(' ')[1]                                                                          
+                screen = QtGui.QDesktopWidget().screenGeometry(int(id))                                        
+                sx = screen.width()                                                                            
+                sy = screen.height()                                                                           
+                                                                                                               
+            # default 'new' tablet area                                                                        
+            ox = 0                                                                                             
+            oy = 0                                                                                             
+            nx = int(tx)                                                                                       
+            ny = int(ty)                                                                                       
+                                                                                                               
+            if float(sy)/float(sx) <= 1.0:                                                                     
+                # screen landscape mode                                                                        
+                ny = int(float(tx) * float(sy) / float(sx))                                                    
+                # Move tablet Y origin (already 0 for "Top")                                                   
+                if buttonText == "Middle":                                                                     
+                    oy = (int(ty) - ny) / 2                                                                    
+                elif buttonText == "Bottom":                                                                   
+                    oy = int(ty) - ny                                                                          
+            else:                                                                                              
+                # screen portrait mode                                                                         
+                # Top = Left, Middle = Middle and Bottom = Right                                               
+                nx = int(float(ty) * float(sx) / float(sy))                                                    
+                # Move tablet X origin (already 0 for "Left")                                                  
+                if buttonText == "Middle":                                                                     
+                    ox = (int(tx) - nx) / 2                                                                    
+                elif buttonText == "Bottom":                                                                   
+                    ox = int(tx) - nx                                                                          
+            ny += oy                                                                                           
+            nx += ox                                                                                           
+            self.tabletAspectArea = "%d %d %d %d" % (ox, oy, nx, ny)                                           
+                                                                                                               
+        #print self.tabletAspectArea                                                                           
+        for device in self.devices:                                                                            
+            if device != "pad" and device != 'touch':                                                          
+                cmd = "xsetwacom --set \"%s %s\" Area %s" % (self.deviceNames[device], device, self.tabletAspectArea)                                                                                                          
+                setCommand = os.popen(cmd)                                                                     
+        # This probably isn't needed, but as we do something similar                                           
+        # when Monitors change wrt Aspect, so update Monitors based                                            
+        # on previous pref (if required)                                                                       
+        if screenDone == False:                                                                                
+            self.screenChangeMain(self.prefs['Screen Area'], True)                                             
+                                                                                                               
                                                                                                                
     def screenChange(self, buttonId):                                                                          
-        if buttonId.text() == "All Monitors":                                                                  
+        self.screenChangeMain(str(buttonId.text()), False)                                                     
+                                                                                                               
+                                                                                                               
+    def screenChangeMain(self, buttonText, aspectDone):                                                        
+        # is we only have one screen, then we don't make any changes here                                      
+        if QtGui.QDesktopWidget().numScreens() == 1:                                                           
+            return                                                                                             
+        if buttonText == "All Monitors":                                                                       
             self.tabletActiveArea = "1 0 0 0 1 0 0 0 1"                                                        
             for device in self.devices:                                                                        
                 if device != "pad":                                                                            
@@ -107,14 +239,30 @@ class otherOptions(QtGui.QWidget):                                                        
                           % (self.deviceNames[device], device, self.tabletActiveArea)                          
                     setCommand = os.popen(cmd)                                                                 
         else:                                                                                                  
-            self.tabletActiveArea = "HEAD-%s" % buttonId.text().split(' ')[1]                                  
+            self.tabletActiveArea = "HEAD-%s" % buttonText.split(' ')[1]                                       
             for device in self.devices:                                                                        
                 if device != "pad":                                                                            
                     cmd = "xsetwacom set \"%s %s\" MapToOutput %s" % (self.deviceNames[device], device, self.tabletActiveArea)                                                                                                 
                     setCommand = os.popen(cmd)                                                                 
+        self.prefs['Screen Area'] = buttonText                                                                 
+        # As Monitor mapping has changed, the Aspect mapping may not match                                     
+        # so update Aspect based on previous pref (if required)                                                
+        if aspectDone == False:                                                                                
+            self.aspectChangeMain(self.prefs['Aspect Mapping'], True)                                          
                                                                                                                
                                                                                                                
     def getTabletArea(self):                                                                                   
+        sa = "Screen Area"                                                                                     
+        # See if we have saved prefs - if we don't, probe for existing setting                                 
+        if sa in self.prefs:                                                                                   
+            if self.prefs[sa] == "All Monitors":                                                               
+                 self.screenFull.setChecked(1)                                                                 
+                 return                                                                                        
+            # only check if we have more than one screen                                                       
+            for x in range(0, QtGui.QDesktopWidget().numScreens()):                                            
+                if self.prefs[sa] == "Monitor %d" % x:                                                         
+                    self.displays[x].setChecked(1)                                                             
+                    return                                                                                     
         # get current tablet area                                                                              
         tabletInfo = os.popen("xinput list-props \"%s stylus\" | grep Coordinate" % self.tabletStylus).readlines()                                                                                                             
         tabletInfo[0] = tabletInfo[0][41:].rstrip('\n')                                                        
@@ -139,6 +287,7 @@ class otherOptions(QtGui.QWidget):                                                          
                     break                                                                                      
         if fullScreen:                                                                                         
             self.screenFull.setChecked(1)                                                                      
+            self.prefs[sa] = "All Monitors"                                                                    
         # have to build array then compare... boo                                                              
         else:                                                                                                  
             for id in range(0, QtGui.QDesktopWidget().numScreens()):                                           
@@ -165,7 +314,11 @@ class otherOptions(QtGui.QWidget):                                                         
                             break                                                                              
                 if valid:                                                                                      
                     self.displays[id].setChecked(1)                                                            
+                    self.prefs[sa] = "Monitor %d" % id                                                         
                     break                                                                                      
+        # Default to all screens                                                                               
+        self.screenFull.setChecked(1)                                                                          
+        self.prefs[sa] = "All Monitors"                                                                        
                                                                                                                
                                                                                                                
     def setDevices(self, devices):                                                                             
@@ -180,6 +333,7 @@ class otherOptions(QtGui.QWidget):                                                          
             self.tabletActiveArea = "HEAD-0"                                                                   
         for device in self.devices:                                                                            
             if device != "pad" and device != 'touch':                                                          
+                setCommands.append("xsetwacom --set \"%s %s\" Area %s" % (self.deviceNames[device], device, self.tabletAspectArea))                                                                                            
                 if 'HEAD' in self.tabletActiveArea:                                                            
                     setCommands.append("xsetwacom --set \"%s %s\" MapToOutput %s" %                            
                                        (self.deviceNames[device], device, self.tabletActiveArea))              
@@ -197,11 +351,16 @@ class otherOptions(QtGui.QWidget):                                                        
         self.orient = "xsetwacom --set \"%s stylus\" Rotate none" % self.deviceNames['stylus']                 
         self.orient += "\nxsetwacom --set \"%s eraser\" Rotate none" % self.deviceNames['eraser']              
         self.tabletRight.setChecked(1)                                                                         
+        self.prefs['Tablet Orientation'] = "Right-Handed"                                                      
         os.popen(self.orient)                                                                                  
         for device in self.devices:                                                                            
             if device != "pad":                                                                                
                 cmd = "xinput set-prop \"%s %s\" --type=float \"Coordinate Transformation Matrix\" 1 0 0 0 1 0 0 0 1" \                                                                                                        
                       % (self.deviceNames[device], device)                                                     
+                cmd += "\nxsetwacom --set \"%s %s\" Area -1 -1 -1 -1" % (self.deviceNames[device], device)     
                 setCommand = os.popen(cmd)                                                                     
         if self.screenFull is not None:                                                                        
             self.screenFull.setChecked(True)                                                                   
+        self.prefs['Screen Area'] = "All Monitors"                                                             
+        self.prefs['Aspect Mapping'] = "None"                                                                  
+        self.aspectNone.setChecked(1)                                                                          
--- ./wacom-gui/pad.py.dist     2018-06-19 16:08:27.000000000 +0100                                             
+++ ./wacom-gui/pad.py  2018-07-31 12:05:57.344886918 +0100                                                     
@@ -7,6 +7,7 @@ import distutils.dir_util                                                                       
 import shutil                                                                                                  
 import os                                                                                                      
 import re                                                                                                      
+import json                                                                                                    
 from os.path import expanduser                                                                                 
 from PyQt4 import QtCore, QtGui                                                                                
 from wacom_data import tabletidentities                                                                        
@@ -115,6 +116,19 @@ class Pad(QtGui.QWidget):                                                                  
             QtGui.QMessageBox.warning(w, "Information", label)                                                 
             w.show()                                                                                           
                                                                                                                
+        prefsFile = "%s/.wacom-gui/%s/prefs.json" % (expanduser("~"), self.Tablet.devID)                       
+        if os.path.exists(prefsFile) and os.access(prefsFile, os.R_OK):                                        
+            try:                                                                                               
+                with open(prefsFile, 'r') as f:                                                                
+                    self.Tablet.prefs = json.load(f)                                                           
+            except:                                                                                            
+                # ignore problems with the prefs file for now ...                                              
+                self.Tablet.prefs = {}                                                                         
+        else:                                                                                                  
+            self.Tablet.prefs = {}                                                                             
+                                                                                                               
+        self.Tablet.prefsFile = prefsFile                                                                      
+                                                                                                               
         opPath = os.path.dirname(os.path.realpath(__file__))                                                   
                                                                                                                
         self.setWindowIcon(QtGui.QIcon(opPath + '/images/wacom-gui.svg'))                                      
@@ -223,6 +237,8 @@ class Pad(QtGui.QWidget):                                                                   
                 return item                                                                                    
         return self.TabletIds.Tablets[len(self.TabletIds.Tablets)-1]                                           
                                                                                                                
+    def getTabletPrefs(self):                                                                                  
+        return self.Tablet.prefs                                                                               
                                                                                                                
     def getTabletName(self):                                                                                   
         return self.Tablet.Name
--- ./wacom-gui/wacom-gui.py.dist       2018-06-19 16:08:27.000000000 +0100
+++ ./wacom-gui/wacom-gui.py    2018-07-31 12:05:57.343886905 +0100
@@ -8,6 +8,7 @@ import os
 import time
 # import threading
 import subprocess
+import json
 from os.path import expanduser
 from PyQt4 import QtCore, QtGui

@@ -31,7 +32,7 @@ class WacomGui(QtGui.QWidget):
         self.eraserControl = pressure(self.pad.Tablet.deviceNames['eraser'], 'eraser')
         self.cursorControl = pressure(self.pad.Tablet.deviceNames['cursor'], 'cursor')
         self.touch = touch(self.pad.Tablet.deviceNames['touch'])
-        self.options = otherOptions(self.pad.Tablet.deviceNames)
+        self.options = otherOptions(self.pad.Tablet.deviceNames, self.pad.Tablet.prefs)
         self.help = Help()
         self.setMaximumSize(1000, 500)
         self.setMinimumSize(1000, 500)
@@ -211,6 +212,9 @@ class WacomGui(QtGui.QWidget):
             config.close()
             os.chmod(self.pad.Tablet.config, 0774)

+        with open(self.pad.Tablet.prefsFile, 'w') as f:
+            json.dump(self.pad.Tablet.prefs, f, indent=4)
+
     def closeEvent(self, event):
         reply = QtGui.QMessageBox.question(self, 'Message',
                                            "Quit and write config file?",

rc19 rpmbuild issue

I'm trying to build an rpm of rc19 for RHEL 7.9 and the following python script fails to compile:

Compiling ~/rpmbuild/BUILDROOT/wacom-gui-0.3.0-rc19.x86_64/usr/local/wacom-gui/data/test_data_files.py ...
File "/usr/local/wacom-gui/data/test_data_files.py", line 37
assert bus in ['usb', 'bluetooth', 'i2c', 'serial'], f'{tabletfile}: unknown bus type'
^
SyntaxError: invalid syntax
error: Bad exit status from /var/tmp/rpm-tmp.gtSNow (%install)

Add support for 'Cintiq 22HD Touch'

The 'Cintiq 22HD Touch' (USB ID 056a:005b) appears to be almost identical to the 'Cintiq 22HD' (056a:00fa) - so to add support, it is simply a case of copying the 'DTK-22hd' png and xml files to corresponding 'DTK-22hdt' files and applying the following patch:

--- ./wacom-gui/wacom_data.py.dist      2018-08-01 13:56:15.534163401 +0100
+++ ./wacom-gui/wacom_data.py   2018-08-01 16:29:08.335121012 +0100
@@ -53,6 +53,7 @@ class tabletidentities:
         self.Tablets.append(tablet("DTZ-21ux",  "Wacom Cintiq21UX", 0x3F))
         self.Tablets.append(tablet("DTZ-20wsx", "Wacom Cintiq20WSX", 0xC5))
         self.Tablets.append(tablet("DTK-22hd", "Wacom Cintiq 22HD", 0xFA))
+        self.Tablets.append(tablet("DTK-22hdt", "Wacom Cintiq 22HDT", 0x5B))
         self.Tablets.append(tablet("DTK-1300", "Wacom Cintiq 13HD", 0x304))
         self.Tablets.append(tablet("DTK-1301", "Wacom Cintiq 13HD", 0x305))
         self.Tablets.append(tablet("DTZ-12wx",  "Wacom Cintiq12WX", 0xC6))

Error at startup when using a Wacom Cintiq Pro 16 (DTH-1620)

wacom-gui fails to start when using Wacom Cintiq Pro 16 (DTH-1620) - error is:

  File "./wacom-gui.py", line 318, in <module>
    main()    
  File "./wacom-gui.py", line 233, in main
    window = WacomGui()
  File "./wacom-gui.py", line 25, in __init__
    self.initUI()
  File "./wacom-gui.py", line 29, in initUI
    self.pad           = Pad()
  File "/usr/local/wacom-gui/pad.py", line 22, in __init__
    self.initUI()
  File "/usr/local/wacom-gui/pad.py", line 62, in initUI
    self.Tablet.pop(idx - count)
IndexError: pop index out of range

I'm not really sure of the logic where this happens:

    # make sure we have at least 1 tablet detected...
    if gen_idx.__len__() < self.Tablet.__len__():
        gen_idx = sorted(gen_idx)
        count = 0 
        for idx in gen_idx:
            self.Tablet.pop(idx - count)

count is set to zero - but doesn't change - so (idx - count) is just (idx) ?

I can work around the error with the following patch:

--- ./wacom-gui/pad.py.dist     2018-06-18 16:26:00.000000000 +0100
+++ ./wacom-gui/pad.py  2018-07-30 12:11:35.666138338 +0100
@@ -56,7 +56,7 @@ class Pad(QtGui.QWidget):
                         gen_idx.append(idx)
                 # make sure we have at least 1 tablet detected...
                 if gen_idx.__len__() < self.Tablet.__len__():
-                    gen_idx = sorted(gen_idx)
+                    gen_idx = sorted(gen_idx, reverse=True)
                     count = 0
                     for idx in gen_idx:
                         self.Tablet.pop(idx - count)

But that might just be papering over the real issue?

IMHO the logic for selecting the 'first' tablet to use if there are more than one seems over complicated?

In this case, there is only one tablet connected, but it reports 4 separate USB ids - and only one is a 'known' tablet device

Device information not found

Plugged in my old Wacom tablet, an Intuos "pen & touch small" (CTH-480) as I need to do some graphics stuff over the next few days.

Trying out Wacom GUI (wacom-gui v0.3.0-rc17 rpm download) just displays a error box twice:

Wacom_GUI-screenshot1

... then a mostly blank window:

Wacom_GUI-screenshot2

The console output (as this was launched manually from the cli) shows:

$ /usr/local/bin/wacom-gui
invalid literal for float(): 2,10.5
invalid literal for float(): 2,10.5

The problem sounds a lot like what's described in a comment on #26 (comment).

For reference:

$ xsetwacom list
Wacom Intuos PT S Pad pad               id: 9   type: PAD       
Wacom Intuos PT S Pen stylus            id: 10  type: STYLUS    
Wacom Intuos PT S Pen eraser            id: 11  type: ERASER    
Wacom Intuos PT S Finger touch          id: 12  type: TOUCH
$ libwacom-list-local-devices --database /usr/local/wacom-gui/data
[Device]
Name=Intuos Pen & Touch Small
DeviceMatch=usb:056a:0302;
Class=Bamboo
Width=6
Height=4
IntegratedIn=
Layout=intuos-s-pt.svg
Styli=0xfffff;0xffffe;

[Features]
Reversible=false
Stylus=true
Ring=false
Ring2=false
Touch=true
TouchSwitch=true
StatusLEDs=
NumStrips=0
Buttons=4
[Buttons]
Left=
Right=
Top=A;B;C;D;
Bottom=
Touchstrip=
Touchstrip2=
OLEDs=
Ring=
Ring2=
EvdevCodes=0x110;0x111;0x115;0x116;
RingNumModes=0
Ring2NumModes=0
StripsNumModes=0

---------------------------------------------------------------
[Device]
Name=Intuos Pen & Touch Small
DeviceMatch=usb:056a:0302;
Class=Bamboo
Width=6
Height=4
IntegratedIn=
Layout=intuos-s-pt.svg
Styli=0xfffff;0xffffe;

[Features]
Reversible=false
Stylus=true
Ring=false
Ring2=false
Touch=true
TouchSwitch=true
StatusLEDs=
NumStrips=0
Buttons=4
[Buttons]
Left=
Right=
Top=A;B;C;D;
Bottom=
Touchstrip=
Touchstrip2=
OLEDs=
Ring=
Ring2=
EvdevCodes=0x110;0x111;0x115;0x116;
RingNumModes=0
Ring2NumModes=0
StripsNumModes=0

---------------------------------------------------------------
[Device]
Name=Intuos Pen & Touch Small
DeviceMatch=usb:056a:0302;
Class=Bamboo
Width=6
Height=4
IntegratedIn=
Layout=intuos-s-pt.svg
Styli=0xfffff;0xffffe;

[Features]
Reversible=false
Stylus=true
Ring=false
Ring2=false
Touch=true
TouchSwitch=true
StatusLEDs=
NumStrips=0
Buttons=4
[Buttons]
Left=
Right=
Top=A;B;C;D;
Bottom=
Touchstrip=
Touchstrip2=
OLEDs=
Ring=
Ring2=
EvdevCodes=0x110;0x111;0x115;0x116;
RingNumModes=0
Ring2NumModes=0
StripsNumModes=0

---------------------------------------------------------------

Error at startup with Wacom Intuos BT M - Ubuntu 19.04

invalid literal for float(): 42,10.5
invalid literal for float(): 42,10.5
Traceback (most recent call last):
  File "/usr/local/wacom-gui/wacom-gui.py", line 741, in <module>
    main()
  File "/usr/local/wacom-gui/wacom-gui.py", line 733, in main
    form = WacomGui()
  File "/usr/local/wacom-gui/wacom-gui.py", line 70, in __init__
    self.refreshTablets()
  File "/usr/local/wacom-gui/wacom-gui.py", line 108, in refreshTablets
    self.tabletSelect(0)
  File "/usr/local/wacom-gui/wacom-gui.py", line 299, in tabletSelect
    self.setToolsAvail(idx)
  File "/usr/local/wacom-gui/wacom-gui.py", line 134, in setToolsAvail
    self.tablet_data.tablets[self.dev][self.dev_id]['eraser']['id']]
KeyError: 'eraser'

Warnings when using a Wacom Cintiq Pro 16 (DTH-1620)

When using a Cintiq Pro 16, wacom-gui gives the following warnings:

Cannot find device 'None cursor'.
Cannot find device 'None cursor'.
QPainter::begin: Paint device returned engine == 0, type: 2
QPainter::font: Painter not active
QPainter::setFont: Painter not active
QPainter::setPen: Painter not active
QPainter::end: Painter not active, aborted

I believe this is because this tablet doesn't have a cursor device:

% xsetwacom --list
Wacom Cintiq Pro 16 Pen stylus          id: 8   type: STYLUS    
Wacom Cintiq Pro 16 Pen eraser          id: 15  type: ERASER    
Wacom Cintiq Pro 16 Touch Finger touch  id: 16  type: TOUCH  

Minor tidy up of tablet names

A couple of the tablet names defined in wacom_data.py are inconsistent with the others - a simple patch to clean this up:

--- ./wacom-gui/wacom_data.py.dist      2018-05-24 17:17:36.000000000 +0100
+++ ./wacom-gui/wacom_data.py   2018-05-25 10:10:22.057286358 +0100
@@ -69,8 +69,8 @@ class tabletidentities:
         self.Tablets.append(tablet("PTK-1240", "Wacom Intuos4 12x19", 0xBB))
         self.Tablets.append(tablet("PTH-650", "Wacom Intuos5 touch M Pen", 0x27))
         self.Tablets.append(tablet("PTH-651", "Wacom Intuos Pro M Pen", 0x315))
-        self.Tablets.append(tablet("PTH-660", "Wacom Co,.Ltd. Wacom Intuos Pro M Pen", 0x357))
-        self.Tablets.append(tablet("PTH-680", "Wacom Co,.Ltd. Wacom Intuos Pro L Pen", 0x358))
+        self.Tablets.append(tablet("PTH-660", "Wacom Intuos Pro M Pen", 0x357))
+        self.Tablets.append(tablet("PTH-680", "Wacom Intuos Pro L Pen", 0x358))
         self.Tablets.append(tablet("CTH-460", "Wacom Bamboo Pen 6x4", 0xD1))
         self.Tablets.append(tablet("CTH-661", "Wacom BambooFun 2FG 6x8", 0xD3))
         self.Tablets.append(tablet("CTL-460", "Wacom BambooFun 2FG 4x5", 0xD4))

Feature requests

Hi,
This is a really handy tool, can I suggest two little features that could be handy:

  • having a reset to default option (something that would just remove the config file)
  • having an option to remove all assignment to the pad buttons (Users here often complain that here pressing buttons inadvertently and they usually end up putting some gaffer on the pad !)

If I can find some time, I'll try to implement these, if anyone can that'd be great !
Thanks for the effort and sharing.

Feature Requests - Indicators, Keystrokes, and Asking

-Indicators-
When the Wacom Gui is on focus, it would be nice that when you pressed a side panel button, or a button on the stylus, that it would highlight which one in the list you pressed. Maybe flash where it lists the keystroke or whatever a color such as blue or red.

This will help people quickly know which button corresponds with with entry on the list.

-Keystrokes-

In the dialog for setting up keystrokes, it is an extreme hassle to go through the list to define a keystroke. It is actually quicker to open custom.json and manually define them in there than it is to use the dialog.

What would be quicker is if you could click into the keystrokes inputbox and then be able to press the keys to map them. The menu could still be there for those who aren't able to use a keyboard, or be available to select keys they don't have access to (like F13-F24). If that's not possible, then atleast let us manually type in {lctrl}{lshift}{d}, it would still be quicker. As is you have to go into the menu tree three levels just to find a letter

Or, maybe have it pop up a virtual keyboard where you can click on the buttons you want. Which could be setup so that the keyboard stays up so you can select every key you wanted, highlighting each one as you go. That would be quick method for users to set a keystroke without the need of a keyboard.

-Asking-
Minor annoyance this one. If you are working on a config, and you go and click to create a new config before saving, it'll forget what changes you've made.

Basically, it would be nice if when you have unsaved changes to a config, it should pop up a message asking if you want to save before creating a new config.

All that being said, I do like what you've got so far. I was able to use it to get my wacom up and running on linux mint (mate) with little hassle.

Map Tilde Key

Hi,

Not sure if this is some kind of limitation or a bug but every time I try to map the tilde key onto a Wacom pad button it doesn't seem to work.

Intuos Pro Medium (PTH-651)
CentOS Linux release 7.6.1810

Any ideas? thanks 😃

device information for "wacom intuos BT M" not found

os: elementary Juno
device: CTL-6100WL
fail to find the device?

$ python wacom-gui.py 
invalid literal for float(): 42,10.5
invalid literal for float(): 42,10.5
Traceback (most recent call last):
  File "wacom-gui.py", line 741, in <module>
    main()
  File "wacom-gui.py", line 733, in main
    form = WacomGui()
  File "wacom-gui.py", line 70, in __init__
    self.refreshTablets()
  File "wacom-gui.py", line 100, in refreshTablets
    self.tablet_data.get_connected_tablets()
  File "/home/super/ws/wacom/wacom-gui-0.3.0-rc16/wacom-gui/wacom_data.py", line 63, in get_connected_tablets
    self.__get_libwacom_data()
  File "/home/super/ws/wacom/wacom-gui-0.3.0-rc16/wacom-gui/wacom_data.py", line 194, in __get_libwacom_data
    if data['pad']['buttons'].__len__() == 0:
KeyError: 'buttons'

$ xsetwacom --list devices
Wacom Intuos BT M Pen stylus    	id: 14	type: STYLUS    
Wacom Intuos BT M Pen eraser    	id: 15	type: ERASER    
Wacom Intuos BT M Pen cursor    	id: 16	type: CURSOR    
Wacom Intuos BT M Pad pad       	id: 17	type: PAD 
$ libwacom-list-local-devices
# Device node: /dev/input/event16
[Device]
Name=Wacom Intuos BT M
ModelName=CTL-6100WL
DeviceMatch=usb:056a:0378;bluetooth:056a:0379;
Class=Bamboo
Width=10
Height=8
IntegratedIn=
Layout=intuos-m-p3.svg
Styli=0x862;

[Features]
Reversible=false
Stylus=true
Ring=false
Ring2=false
Touch=false
TouchSwitch=false
# StatusLEDs=
NumStrips=0
Buttons=4

[Buttons]
# Left=
# Right=
Top=A;B;C;D;
# Bottom=
# Touchstrip=
# Touchstrip2=
# OLEDs=
# Ring=
# Ring2=
EvdevCodes=0x110;0x111;0x115;0x116;
RingNumModes=0
Ring2NumModes=0
StripsNumModes=0

---------------------------------------------------------------
# Device node: /dev/input/event15
[Device]
Name=Wacom Intuos BT M
ModelName=CTL-6100WL
DeviceMatch=usb:056a:0378;bluetooth:056a:0379;
Class=Bamboo
Width=10
Height=8
IntegratedIn=
Layout=intuos-m-p3.svg
Styli=0x862;

[Features]
Reversible=false
Stylus=true
Ring=false
Ring2=false
Touch=false
TouchSwitch=false
# StatusLEDs=
NumStrips=0
Buttons=4

[Buttons]
# Left=
# Right=
Top=A;B;C;D;
# Bottom=
# Touchstrip=
# Touchstrip2=
# OLEDs=
# Ring=
# Ring2=
EvdevCodes=0x110;0x111;0x115;0x116;
RingNumModes=0
Ring2NumModes=0
StripsNumModes=0

---------------------------------------------------------------

tablet file

$ sudo cat /usr/share/libwacom/intuos-m-p3-wl.tablet          
# Wacom
# Intuos Pen Medium Wireless
# CTL-6100WL
#
# This is the third generation "Intuos", a successor to
# the CTL-690. It has a Stylus with two buttons and no
# eraser. The device has no touch.
#
# Buttons are no loger RIGHT, LEFT, FORWARD, and BACKWARD.
# The buttons are now reported as numbered buttons as with
# the Intuos Pro series.
#
#      A   B           C   D
#    *-----------------------*
#    |                       |
#    |        TABLET         |
#    |                       |
#    *-----------------------*

[Device]
Name=Wacom Intuos BT M
ModelName=CTL-6100WL
DeviceMatch=usb:056a:0378;bluetooth:056a:0379
Class=Bamboo
Width=10
Height=8
Layout=intuos-m-p3.svg
IntegratedIn=
Styli=@intuospt3;

[Features]
Stylus=true
Reversible=false
Buttons=4

[Buttons]
Top=A;B;C;D

toggle problems with rotated monitor

I'm having problems getting the '--toggle' option to work when one monitor is rotated by 90 degrees

I'm using CentOS 7.4 with Mate and two 1920x1200 monitors using the Nvidia driver

The right-hand monitor is rotated 90 degrees left (via nvidia-settings) i.e. in portrait mode

Using wacom-gui in GUI mode, I can set the Wacom tablet to use left, right or both monitors - which works fine - however when using in 'toggle' mode, it crashes with:
Traceback (most recent call last):
File "/usr/local/wacom-gui/wacom-gui.py", line 338, in
main()
File "/usr/local/wacom-gui/wacom-gui.py", line 178, in main
parseArgs(sys.argv)
File "/usr/local/wacom-gui/wacom-gui.py", line 193, in parseArgs
toggleScreens()
File "/usr/local/wacom-gui/wacom-gui.py", line 211, in toggleScreens
coords = getTabletArea(mod[0])
File "/usr/local/wacom-gui/wacom-gui.py", line 286, in getTabletArea
display[0][0] = float(screens[1][2]) / float(totalResolution[0])
IndexError: list index out of range

The problem is that xrandr returns a slightly different result when monitors are rotated - in my case:

DVI-I-1 connected 1920x1200+0+360 (normal left inverted right x axis y axis) 519mm x 324mm
DP-1 connected 1200x1920+1920+0 left (normal left inverted right x axis y axis) 518mm x 324mm

i.e. the extra 'left' in the output for the rotated monitor (which I guess mean the monitor is rotated to the left ...)

I can 'fix' this by replacing the 'get screen dimensions/coords' code in wacom-gui.py with:

info = os.popen("xrandr | grep ' connected'").read().strip().split('\n')
screens = []
for screen in info:
    scr = re.findall(r'\d+x\d+\+\d+\+\d+', screen)[0]
    scr = scr.replace('x','+')
    scr = scr.split('+')
    scr.insert(3,scr.pop(0))
    scr.insert(3,scr.pop(0))
    if screen.find('primary') == -1:
        screens.append(scr)
    else:
        screens.insert(0, scr)

However, it now only allows me to toggle between full screen and the left monitor ... it won't ever toggle to the right monitor

In fact, I can only get it to toggle between left, right and both monitors when both monitors are not rotated and aligned with the same top-left 'y' coordinate - if there is any offset in the vertical , then I can not toggle to the right monitor

I haven't had a chance to workout how the code is selecting which monitor to toggle to, but I suspect it is not taking into account any offsets between the monitors ?

Thanks

Wacom Tablet Intuos2

Hello!
It seems that the code doesn't work with Intuos2 tablets. Everytime I tried to run it a "Device information for 'Intuos2 12x18' not found" message appeared.
I tried some debugging and found out that this tablet model didn't appear in wacom_data.py.
Is my assumption correct? Can you add up this tablet model to your code?
Thanks a lot!

wacom-gui 'silent' when run via a .desktop file with no tablet attached

If wacom-gui is launched from a .desktop file as a menu item when there is no tablet attached, the "No tablet detected" error to stdout isn't seen

A simple 'fix' is to report this via something like zenity - e.g.

--- ./wacom-gui/pad.py.dist     2018-02-02 18:10:47.000000000 +0000
+++ ./wacom-gui/pad.py  2018-04-03 13:58:12.000000000 +0100
@@ -28,8 +28,9 @@ class Pad(QtGui.QWidget):
         label = ''
         if len(tablets) == 0:
             label = "No tablet detected"
+            os.system("zenity --error --title=wacom-gui --text \"%s\"" % label)
             print label
-            sys.exit()
+            sys.exit(1)
         #if len(tablets) > 1:
             # no longer checking for multiple tablets; only the first is configured
         #    label = "Multiple tablets detected. Please connect only one at a time"

(also as it's an error, the app should have a non-zero exit status)

Error when restoring default config when tablet doesn't have Touch support

wacom-gui prints the following when 'Restore Default Configuration" is selected using a PTK-640 tablet:

Traceback (most recent call last):
  File "./wacom-gui.py", line 105, in restoreDefaults
    self.touch.resetDefaults()
  File "/usr/local/wacom-gui/touch.py", line 57, in resetDefaults
    if self.tabletName:
AttributeError: 'touch' object has no attribute 'tabletName'

The following patch fixes this:

--- ./wacom-gui/touch.py.orig   2018-07-24 15:42:08.000000000 +0100
+++ ./wacom-gui/touch.py        2018-07-26 16:34:49.058371533 +0100
@@ -7,6 +7,7 @@ class touch(QtGui.QWidget):
     def __init__(self, tabletName, parent=None):
         QtGui.QWidget.__init__(self, parent)
         if tabletName is None:
+            self.tabletName = tabletName
             return None
         self.tabletName = tabletName
         self.enable = None

Launch fails on xubuntu and wacom intuos 3

Hi,
I would like first to congratulate you for your project, its very nice, well designed and useful. As I am a python developer, I could help a bit.

I have a wacom intuos 3 (PTZ-630), running on Xubuntu 18.04. I first installed the dconf-tools package, which should be in your prerequisites I think, for desktops that don't use it by default. I launched wacom-gui from source files, but all I got at first were errors:

local variable 'svg_write' referenced before assignment
local variable 'svg_write' referenced before assignment
Traceback (most recent call last):
File "wacom-gui.py", line 741, in
main()
File "wacom-gui.py", line 733, in main
form = WacomGui()
File "wacom-gui.py", line 70, in init
self.refreshTablets()
File "wacom-gui.py", line 108, in refreshTablets
self.tabletSelect(0)
File "wacom-gui.py", line 300, in tabletSelect
self.getConfigs(idx)
File "wacom-gui.py", line 259, in getConfigs
self.loadConfig(dev, dev_id, self.config)
File "wacom-gui.py", line 278, in loadConfig
self.configs[dev][config]['pad']['buttons'])
File "/home/francois/Téléchargements/wacom-gui/wacom-gui/pad.py", line 172, in init_keys
svg_size = svgWidget.sizeHint()
AttributeError: 'NoneType' object has no attribute 'sizeHint'

I dug a little bit and modified the wacom_data.py file to make the interface work (it was an svg creation issue):
patch.txt

The interface is now usable to setup everything, but with display issues (image of express keys is stretched, no pen image, and mapping settings are not well displayed):

wacom-gui

Also, I found no way to set the two "strips" in the express keys bindings, is this a xsetwacom limitation ?

It would be nice if you find time to look at this but anyway, thanks for sharing this program.

PTK-640 limited script functionality on Fedora 29

In my quest to find something to help me obtain proper functionality of the centre ring button I installed your package. "Proper" meaning the ability to scroll through 4 options so that, at least, I can control brush size as well as zoom with the "RingUp" and "RingDown. Alas, this doesn't seem to be possible.
Furthermore, the "Keystroke..." functionality when trying to set a stroke with a keypad input does not register. Too bad because this seems to provide the only option to set Labels for the buttons.

PTH-660 - GUI Not loading

All our "older" tablets work with wacom-gui (0.3.0-rc13)
Unfortunately the latest PTH-660 tablet works at the OS level (xsetwacom 0.36.1) but I can't get your wacom-gui to load.

Error:
Traceback (most recent call last): File ”/usr/local/wacom-gui/wacom-gui.py”, line 15, in <module> from pad import Pad, Touch File ”/usr/local/wacom-gui/pad.py”, line 10, in <module> from hotkeys import HotkeyWidget File ”/usr/local/wacom-gui/hotkeys.py”, line 17, in <module> class Hotkey(QObject): NameError: name ’QObject’ is not defined

Thank you

Feature Request: Add support for multiple tablets

I had a go at allowing the GUI to support multiple tablets - and have come up with the patch below

If multiple tablets are found, then it prompts for for which tablet to use - however, I have no idea how to do this with PyQt4 - so I've just used zenity :-)

This patch has the side effect of replacing the code causing the problem with issue #15

--- ./wacom-gui/pad.py.dist     2018-07-31 12:05:57.344886918 +0100
+++ ./wacom-gui/pad.py  2018-08-01 14:02:27.260979779 +0100
@@ -24,7 +24,7 @@ class Pad(QtGui.QWidget):
         
     def initUI(self):
         #get tablet name/type
-        tablets = os.popen("lsusb | grep -i wacom").readlines()
+        tablets = os.popen("lsusb -d 056a:").readlines()
         self.TabletIds = tabletidentities()
         # reset button configs button
         self.buttonReset = QtGui.QPushButton("Reset Buttons")
@@ -39,43 +39,70 @@ class Pad(QtGui.QWidget):
             w.show()
             sys.exit(-1)
         else:
+            # we have at least one Wacom USB ID - extact the details of
+            # the tablets we know about - if we don't know about one
+            # (or more) then save this as a generic tablet
             self.Tablet = []
-            for idx, tablet in enumerate(tablets):
+            for tablet in tablets:
                 (VendId, DevId) = tablet.split(" ")[5].split(":")
-                self.Tablet.append(self.IdentifyByUSBId(VendId, DevId))
-                if self.Tablet[idx].Model != "generic":
-                    self.Tablet[idx].devID = DevId
+                item = self.IdentifyByUSBId(VendId, DevId)
+                if item.Model != "generic":
+                    item.devID = DevId
+                    self.Tablet.append(item)
                 else:
-                    self.Tablet[idx].devID = "generic"
-                    # break
-            # if we have multiple tablets, need to figure out which one we use...
-            if self.Tablet.__len__() != 1:
-                # check of "generic" tablet exists, if it does we ignore it
-                gen_idx = []
-                for idx, dev in enumerate(self.Tablet):
-                    if dev.Model == 'generic':
-                        gen_idx.append(idx)
-                # make sure we have at least 1 tablet detected...
-                if gen_idx.__len__() < self.Tablet.__len__():
-                    gen_idx = sorted(gen_idx)
-                    count = 0
-                    for idx in gen_idx:
-                        self.Tablet.pop(idx - count)
-                if self.Tablet.__len__() > 1:
-                    label = "Multiple Tablets detected; using the first one detected: %s (%s)" % \
-                        (self.Tablet[0].Name, self.Tablet[0].Model)
-                    w = QtGui.QMessageBox()
-                    QtGui.QMessageBox.warning(w, "Information", label)
-                    w.show()
-            self.Tablet = self.Tablet[0]
+                    item.devID = "generic"
+                    genericTablet = item
+
+            # Default index in the found Tablet array
+            idx = 0
+
+            tlen = self.Tablet.__len__()
+            if tlen == 0:
+                # we have a Wacom USB ID - but don't know about the tablet
+                # so we default to a 'generic' tablet
+                self.Tablet.append(genericTablet)
+            elif tlen != 1:
+                # we have multiple tablets, need to figure out which one we use
+                # Hack! - use zenity to prompt for a tablet to select
+                # needs to be replaced with QtPy code ...
+                cmd = "zenity  --list  --title \"Select Tablet to use\" --text \"Select Tablet to use\"  --radiolist  --column \"Select\" --column \"Tablet\" TRUE \"%s\" " % self.Tablet[0].Name
+                for x in range(1, tlen):
+                    cmd += "FALSE \"%s\" " % self.Tablet[x].Name
+                cmd += "2>/dev/null"
+                #print cmd
+                ret = os.popen(cmd).read().rstrip()
+                # if 'Cancel' was selected, then exit here
+                if ret == "":
+                    sys.exit(-1)
+
+                # find the selected tablet
+                for i,tablet in enumerate(self.Tablet):
+                    if tablet.Name == ret:
+                        idx = i
+                        break;
+
+            self.Tablet = self.Tablet[idx]
+            ProductId = self.Tablet.ProductId
+
             # on some tablets each 'device' has a different name ...
             # read in wacom devices into an dict
             deviceNames = {'eraser': None, 'stylus': None, 'cursor': None, 'pad': None, 'touch': None}
             foundDevs = False
+
+            # If we have multiple tablets, then we have to check that the
+            # Wacom devices found by 'xsetwacom --list' are for the tablet
+            # we have selected - this can be checked using the xsetwacom
+            # 'TabletID' option that returns the USB ProductId
+            # If the tablet is 'generic', then we just accept the devices
+            # as is - we use '0xFF' as the ProductId in this case
             with os.popen("xsetwacom --list devices") as f:
                 for line in f:
-                    deviceNames[line.strip().rsplit(" ", 1)[1].lower()] = line.split("\t")[0].strip().rsplit(" ", 1)[0].rstrip()
-                    foundDevs = True
+                    id = line.split("id:")[1].split()[0]
+                    cmd = "xsetwacom --get %s TabletID" % id
+                    ret = os.popen(cmd).read().rstrip()
+                    if ProductId == 0xFF or ProductId == int(ret):
+                        deviceNames[line.strip().rsplit(" ", 1)[1].lower()] = line.split("\t")[0].strip().rsplit(" ", 1)[0].rstrip()
+                        foundDevs = True
 
             if not foundDevs:
                 label = "Tablet not supported"

PTH-680 is actually PTH-860 - plus other 'model name' clean up

When I added support for the 'Intuos Pro 2 L', I made a mistake with its model - it should be 'PTH-860' not 'PTH-680' ...

The following patch fixes this - plus tidies up some other tablet names (to match those in libwacom-data):

--- ./wacom-gui/wacom_data.py.dist      2018-05-28 17:13:39.000000000 +0100
+++ ./wacom-gui/wacom_data.py   2018-06-05 11:06:08.196462746 +0100
@@ -67,10 +67,10 @@ class tabletidentities:
         self.Tablets.append(tablet("PTK-640", "Wacom Intuos4 6x9", 0xB9))
         self.Tablets.append(tablet("PTK-840", "Wacom Intuos4 8x13", 0xBA))
         self.Tablets.append(tablet("PTK-1240", "Wacom Intuos4 12x19", 0xBB))
-        self.Tablets.append(tablet("PTH-650", "Wacom Intuos5 touch M Pen", 0x27))
-        self.Tablets.append(tablet("PTH-651", "Wacom Intuos Pro M Pen", 0x315))
-        self.Tablets.append(tablet("PTH-660", "Wacom Intuos Pro M Pen", 0x357))
-        self.Tablets.append(tablet("PTH-680", "Wacom Intuos Pro L Pen", 0x358))
+        self.Tablets.append(tablet("PTH-650", "Wacom Intuos5 touch M", 0x27))
+        self.Tablets.append(tablet("PTH-651", "Wacom Intuos Pro M", 0x315))
+        self.Tablets.append(tablet("PTH-660", "Wacom Intuos Pro 2 M", 0x357))
+        self.Tablets.append(tablet("PTH-860", "Wacom Intuos Pro 2 L", 0x358))
         self.Tablets.append(tablet("CTH-460", "Wacom Bamboo Pen 6x4", 0xD1))
         self.Tablets.append(tablet("CTH-661", "Wacom BambooFun 2FG 6x8", 0xD3))

This also means the PTH-680.* files need to be renamed:

mv images/PTH-680.png images/PTH-860.png
mv images/pad/PTH-680.png images/pad/PTH-860.png
mv images/pad/PTH-680.xml images/pad/PTH-860.xml

SyntaxError: Missing parentheses in call to 'print'

I tried run with the step:

download the source, run wacom-gui.py from the wacom-gui directory

And I get:

./wacom-gui/wacom-gui/wacom-gui.py", line 194
    print e
          ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(e)?

Easy to solve of course, change the code print e to print(e)

'Restore Default Configuration' gives error with single screen

Selecting 'Other Setting -> Restore Default Configuration' gives the error:

Traceback (most recent call last):
  File "wacom-gui.py", line 109, in restoreDefaults
    self.options.resetDefaults()
  File "/tmp/wacom-gui-master/wacom-gui/options.py", line 203, in resetDefaults
    self.screenFull.setChecked(True)
AttributeError: 'otherOptions' object has no attribute 'screenFull'

I guess you need to check multiple screens are in use or self.screenFull exists before attempting self.screenFull.setChecked(True) ?

'tar' file in v0.2.0d SRPM is actually a 'zip' file

Not a major issue, as rpmbuild appears to cope with it OK, but the source file 'wacom-gui-0.2.0d.tar.gz' in the 0.2.0d SRPM is not a compressed tar file, but actually a zip file ... which is a bit confusing :-)

User settings not loaded when a Bluetooth tablet is connected

When powering on a PTH-660 connected over Bluetooth to CentOS 7, saved wacom-gui user settings are not loaded

This is because the file /etc/udev/rules.d/99-wacom-gui.rules will only trigger wacom-gui.service for tablets connected over USB

I managed to get this to work by adding the following line to /etc/udev/rules.d/99-wacom-gui.rules:

ENV{PRODUCT}=="5/56a/*/*" TAG+="systemd", ENV{SYSTEMD_WANTS}+="wacom-gui.service"

I have no idea is this is the 'best' way to do this ... I used a bit of trial-n-error based on the syntax in /usr/lib/udev/rules.d/65-libwacom.rules - but it appears to work for me

Unusable on smaller displays - 1366x768 - Linux Mint 19.3 w/ XFCE 4

Due to the size of the QT main window set at 900x900, several elements fall off the bottom of the screen, rendering this application unusable on smaller displays. This should be remedied by allowing the window to be resized, and either scaling some of the contents, or by putting everything into a scroll area.

In order to make it usable on my system, I have set the vertical size policy to "Preferred" and changed the minimum size to some arbitrary value smaller than my screen's vertical height. I then added a scroll area, and moved all the contents of the main window into it, playing with layout to make everything usable. The finished "product" is rather ugly due to my lack of knowledge and experience working with Qt and QtDesigner, thus why I am not submitting it as a pull request.

wacom-gui dies on RHEL 7.6 with a Cintiq Pro 24

Manually starting wacom-gui produces the following errors:

[root@sulawesi ~]# wacom-gui
local variable 'svg_write' referenced before assignment
Traceback (most recent call last):
File "/usr/local/wacom-gui/wacom-gui.py", line 741, in
main()
File "/usr/local/wacom-gui/wacom-gui.py", line 733, in main
form = WacomGui()
File "/usr/local/wacom-gui/wacom-gui.py", line 56, in init
self.tablet_data = Tablets()
File "/usr/local/wacom-gui/wacom_data.py", line 32, in init
self.get_connected_tablets()
File "/usr/local/wacom-gui/wacom_data.py", line 72, in get_connected_tablets
devID = self.device_data[dev_type]['devID']
KeyError: 'Wacom Express Key Remote Pad'

[root@sulawesi ~]# xsetwacom list
Wacom Express Key Remote Pad pad id: 14 type: PAD
Wacom Cintiq Pro 24 Pen stylus id: 15 type: STYLUS
Wacom Cintiq Pro 24 Pen eraser id: 17 type: ERASER

[root@sulawesi ~]# journalctl -u wacom-gui
-- Logs begin at Wed 2019-01-30 17:17:27 PST, end at Tue 2019-02-05 13:10:12 PST. --
Feb 05 11:45:57 sulawesi systemd[1]: Started Load user settings for Wacom tablets.
Feb 05 11:48:15 sulawesi systemd[1]: Started Load user settings for Wacom tablets.
Feb 05 11:48:16 sulawesi runuser[112694]: pam_unix(runuser:session): session opened for user dj7 by (uid=0)
Feb 05 11:48:16 sulawesi python[112695]: detected unhandled Python exception in '/usr/local/wacom-gui/wacom-gui.py'
Feb 05 11:48:16 sulawesi python[112695]: can't communicate with ABRT daemon, is it running? [Errno 2] No such file or directory
Feb 05 11:48:16 sulawesi runuser[112694]: pam_unix(runuser:session): session closed for user dj7

Disable/Enable all buttons?

Version 0.2.x had a 'Disable Buttons' toggle to disable/enable all pad buttons - could this be added to v0.3.x as well?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.