mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 04:30:06 +01:00
Merge branch 'wip/config-files'
This commit is contained in:
commit
000ac14c27
56 changed files with 4413 additions and 305 deletions
4
data/10-generic-keyboard.quirks
Normal file
4
data/10-generic-keyboard.quirks
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[Serial Keyboards]
|
||||
MatchUdevType=keyboard
|
||||
MatchBus=ps2
|
||||
AttrKeyboardIntegration=internal
|
||||
9
data/10-generic-lid.quirks
Normal file
9
data/10-generic-lid.quirks
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[Lid Switch Ct9]
|
||||
MatchName=*Lid Switch*
|
||||
MatchDMIModalias=dmi:*:ct9:*
|
||||
AttrLidSwitchReliability=reliable
|
||||
|
||||
[Lid Switch Ct10]
|
||||
MatchName=*Lid Switch*
|
||||
MatchDMIModalias=dmi:*:ct10:*
|
||||
AttrLidSwitchReliability=reliable
|
||||
3
data/10-generic-trackball.quirks
Normal file
3
data/10-generic-trackball.quirks
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[Trackball]
|
||||
MatchName=*Trackball*
|
||||
ModelTrackball=1
|
||||
5
data/30-vendor-aiptek.quirks
Normal file
5
data/30-vendor-aiptek.quirks
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[Aiptek No Tilt Tablet]
|
||||
MatchUdevType=tablet
|
||||
MatchBus=usb
|
||||
MatchVendor=0x08CA
|
||||
ModelTabletNoTilt=1
|
||||
9
data/30-vendor-alps.quirks
Normal file
9
data/30-vendor-alps.quirks
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[AlpsTouchpadDualPoint]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=*AlpsPS/2 ALPS DualPoint TouchPad
|
||||
ModelALPSTouchpad=1
|
||||
|
||||
[AlpsTouchpadGlidePoint]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=*AlpsPS/2 ALPS GlidePoint
|
||||
ModelALPSTouchpad=1
|
||||
3
data/30-vendor-cyapa.quirks
Normal file
3
data/30-vendor-cyapa.quirks
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[Cyapa Touchpads]
|
||||
MatchName=*Cypress APA Trackpad ?cyapa?
|
||||
AttrPressureRange=10:8
|
||||
4
data/30-vendor-elantech.quirks
Normal file
4
data/30-vendor-elantech.quirks
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[Elantech Touchpads]
|
||||
MatchName=*Elantech Touchpad*
|
||||
AttrResolutionHint=31x31
|
||||
AttrPressureRange=10:8
|
||||
12
data/30-vendor-huion.quirks
Normal file
12
data/30-vendor-huion.quirks
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# HUION PenTablet device. Some of these devices send a BTN_TOOL_PEN event
|
||||
# with value 1 on the first event received by the device but never send the
|
||||
# matching BTN_TOOL_PEN value 0 event. The device appears as if it was
|
||||
# permanently in proximity.
|
||||
#
|
||||
# HUION re-uses USB IDs for its devices, not every HUION tablet is
|
||||
# affected by this bug, libinput will auto-disable this feature
|
||||
[HUION PenTablet]
|
||||
MatchUdevType=tablet
|
||||
MatchBus=usb
|
||||
MatchVendor=0x256C
|
||||
ModelTabletNoProximityOut=1
|
||||
39
data/30-vendor-ibm.quirks
Normal file
39
data/30-vendor-ibm.quirks
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# IBM/Lenovo Scrollpoint mouse. Instead of a scroll wheel these mice
|
||||
# feature trackpoint-like sticks which generate a huge amount of scroll
|
||||
# events that need to be handled differently than scroll wheel events
|
||||
|
||||
[IBM ScrollPoint Mouse 3100]
|
||||
MatchUdevType=mouse
|
||||
MatchVendor=0x04B3
|
||||
MatchProduct=0x3100
|
||||
ModelLenovoScrollPoint=1
|
||||
|
||||
[IBM ScrollPoint Mouse 3103]
|
||||
MatchUdevType=mouse
|
||||
MatchVendor=0x04B3
|
||||
MatchProduct=0x3103
|
||||
ModelLenovoScrollPoint=1
|
||||
|
||||
[IBM ScrollPoint Mouse 3105]
|
||||
MatchUdevType=mouse
|
||||
MatchVendor=0x04B3
|
||||
MatchProduct=0x3105
|
||||
ModelLenovoScrollPoint=1
|
||||
|
||||
[IBM ScrollPoint Mouse 3108]
|
||||
MatchUdevType=mouse
|
||||
MatchVendor=0x04B3
|
||||
MatchProduct=0x3108
|
||||
ModelLenovoScrollPoint=1
|
||||
|
||||
[IBM ScrollPoint Mouse 3109]
|
||||
MatchUdevType=mouse
|
||||
MatchVendor=0x04B3
|
||||
MatchProduct=0x3109
|
||||
ModelLenovoScrollPoint=1
|
||||
|
||||
[IBM ScrollPoint Mouse 6049]
|
||||
MatchUdevType=mouse
|
||||
MatchVendor=0x17EF
|
||||
MatchProduct=0x6049
|
||||
ModelLenovoScrollPoint=1
|
||||
44
data/30-vendor-logitech.quirks
Normal file
44
data/30-vendor-logitech.quirks
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
[Logitech M570]
|
||||
MatchName=*Logitech M570*
|
||||
ModelTrackball=1
|
||||
|
||||
[Logitech Marble Mouse Trackball]
|
||||
MatchUdevType=mouse
|
||||
MatchBus=usb
|
||||
MatchVendor=0x46D
|
||||
MatchProduct=0xC408
|
||||
ModelLogitechMarbleMouse=1
|
||||
|
||||
[Logitech K400]
|
||||
MatchUdevType=mouse
|
||||
MatchBus=usb
|
||||
MatchVendor=0x046D
|
||||
MatchProduct=0x4024
|
||||
ModelBouncingKeys=1
|
||||
|
||||
[Logitech K400r]
|
||||
MatchUdevType=mouse
|
||||
MatchBus=usb
|
||||
MatchVendor=0x046D
|
||||
MatchProduct=0x404B
|
||||
ModelBouncingKeys=1
|
||||
|
||||
[Logitech K830]
|
||||
MatchUdevType=mouse
|
||||
MatchBus=usb
|
||||
MatchVendor=0x046D
|
||||
MatchProduct=0x404C
|
||||
ModelBouncingKeys=1
|
||||
|
||||
[Logitech K400Plus]
|
||||
MatchUdevType=mouse
|
||||
MatchBus=usb
|
||||
MatchVendor=0x046D
|
||||
MatchProduct=0x404D
|
||||
ModelBouncingKeys=1
|
||||
|
||||
[Logitech Wireless Touchpad]
|
||||
MatchBus=usb
|
||||
MatchVendor=0x046D
|
||||
MatchProduct=0x4011
|
||||
AttrPalmPressureThreshold=400
|
||||
16
data/30-vendor-microsoft.quirks
Normal file
16
data/30-vendor-microsoft.quirks
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[Microsoft Surface 3 Lid Switch]
|
||||
MatchName=*Lid Switch*
|
||||
MatchDMIModalias=dmi:*svnMicrosoftCorporation:pnSurface3:*
|
||||
AttrLidSwitchReliability=write_open
|
||||
|
||||
[Microsoft Surface 3 Type Cover Keyboard]
|
||||
MatchName=*Microsoft Surface Type Cover Keyboard*
|
||||
MatchDMIModalias=dmi:*svnMicrosoftCorporation:pnSurface3:*
|
||||
AttrKeyboardIntegration=internal
|
||||
|
||||
[Microsoft Nano Transceiver v2.0]
|
||||
MatchUdevType=mouse
|
||||
MatchBus=usb
|
||||
MatchVendor=0x045E
|
||||
MatchProduct=0x8000
|
||||
ModelBouncingKeys=1
|
||||
11
data/30-vendor-razer.quirks
Normal file
11
data/30-vendor-razer.quirks
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[Razer Blade Keyboard]
|
||||
MatchUdevType=keyboard
|
||||
MatchBus=usb
|
||||
MatchVendor=0x1532
|
||||
MatchProduct=0x0220
|
||||
AttrKeyboardIntegration=internal
|
||||
|
||||
[Razer Blade Lid Switch]
|
||||
MatchName=*Lid Switch*
|
||||
MatchDMIModalias=dmi:*svnRazer:pnBlade*
|
||||
AttrLidSwitchReliability=write_open
|
||||
6
data/30-vendor-synaptics.quirks
Normal file
6
data/30-vendor-synaptics.quirks
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[Synaptics Serial Touchpads]
|
||||
MatchUdevType=touchpad
|
||||
MatchBus=ps2
|
||||
MatchVendor=0x0002
|
||||
MatchProduct=0x0007
|
||||
ModelSynapticsSerialTouchpad=1
|
||||
12
data/30-vendor-wacom.quirks
Normal file
12
data/30-vendor-wacom.quirks
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[Wacom Touchpads]
|
||||
MatchUdevType=touchpad
|
||||
MatchBus=usb
|
||||
MatchVendor=0x056A
|
||||
ModelWacomTouchpad=1
|
||||
|
||||
[Wacom Intuos Pro PTH660]
|
||||
MatchUdevType=touchpad
|
||||
MatchBus=usb
|
||||
MatchVendor=0x056A
|
||||
MatchProduct=0x0357
|
||||
AttrPalmSizeThreshold=1
|
||||
48
data/50-system-apple.quirks
Normal file
48
data/50-system-apple.quirks
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
[Apple Touchpads USB]
|
||||
MatchVendor=0x05AC
|
||||
MatchBus=usb
|
||||
MatchUdevType=touchpad
|
||||
ModelAppleTouchpad=1
|
||||
AttrSizeHint=104x75
|
||||
AttrTouchSizeRange=150:130
|
||||
AttrPalmSizeThreshold=800
|
||||
|
||||
[Apple Touchpads Bluetooth]
|
||||
MatchVendor=0x05AC
|
||||
MatchBus=bluetooth
|
||||
MatchUdevType=touchpad
|
||||
ModelAppleTouchpad=1
|
||||
|
||||
[Apple Internal Keyboard]
|
||||
MatchName=*Apple Inc. Apple Internal Keyboard*
|
||||
AttrKeyboardIntegration=internal
|
||||
|
||||
[Apple MagicMouse]
|
||||
MatchUdevType=mouse
|
||||
MatchBus=bluetooth
|
||||
MatchVendor=0x05AC
|
||||
MatchProduct=0x030D
|
||||
ModelAppleMagicMouse=1
|
||||
|
||||
[Apple Magic Trackpad v1 (2010, clickpad)]
|
||||
MatchUdevType=touchpad
|
||||
MatchBus=bluetooth
|
||||
MatchVendor=0x5AC
|
||||
MatchProduct=0x030E
|
||||
AttrSizeHint=130x110
|
||||
AttrTouchSizeRange=20:10
|
||||
AttrPalmSizeThreshold=900
|
||||
|
||||
[Apple Touchpad OneButton]
|
||||
MatchUdevType=touchpad
|
||||
MatchBus=usb
|
||||
MatchVendor=0x5AC
|
||||
MatchProduct=0x021A
|
||||
ModelAppleTouchpadOneButton=1
|
||||
|
||||
[Apple Touchpad MacbookPro5,5]
|
||||
MatchUdevType=touchpad
|
||||
MatchBus=usb
|
||||
MatchVendor=0x05AC
|
||||
MatchProduct=0x0237
|
||||
AttrPalmSizeThreshold=1000
|
||||
9
data/50-system-asus.quirks
Normal file
9
data/50-system-asus.quirks
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[Asus X555LAB]
|
||||
MatchName=*ETPS/2 Elantech Touchpad*
|
||||
MatchDMIModalias=dmi:*svnASUSTeKCOMPUTERINC.:pnX555LAB:*
|
||||
ModelTouchpadVisibleMarker=1
|
||||
|
||||
[Asus UX21E]
|
||||
MatchName=*ETPS/2 Elantech Touchpad*
|
||||
MatchDMIModalias=dmi:*svnASUSTeKComputerInc.:pnUX21E:*
|
||||
AttrPressureRange=24:10
|
||||
7
data/50-system-chicony.quirks
Normal file
7
data/50-system-chicony.quirks
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Acer Hawaii Keyboard, uses Chicony VID
|
||||
[Acer Hawaii Keyboard]
|
||||
MatchUdevType=touchpad
|
||||
MatchBus=usb
|
||||
MatchVendor=0x4F2
|
||||
MatchProduct=0x1558
|
||||
AttrTPKComboLayout=below
|
||||
6
data/50-system-cyborg.quirks
Normal file
6
data/50-system-cyborg.quirks
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[Saitek Cyborg RAT5]
|
||||
MatchUdevType=mouse
|
||||
MatchBus=usb
|
||||
MatchVendor=0x06A3
|
||||
MatchProduct=0x0CD5
|
||||
ModelCyborgRat=1
|
||||
15
data/50-system-dell.quirks
Normal file
15
data/50-system-dell.quirks
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[Dell Touchpads]
|
||||
MatchName=* Touchpad
|
||||
MatchDMIModalias=dmi:*svnDellInc.:*
|
||||
ModelTouchpadVisibleMarker=1
|
||||
|
||||
[Dell Lattitude E6220]
|
||||
MatchName=*AlpsPS/2 ALPS GlidePoint
|
||||
MatchDMIModalias=dmi:*svnDellInc.:pnLatitudeE6220:*
|
||||
AttrPressureRange=100:90
|
||||
|
||||
[Dell XPS L322X]
|
||||
MatchName=*CyPS/2 Cypress Trackpad
|
||||
MatchDMIModalias=dmi:*svnDell*:XPSL322X*
|
||||
AttrPressureRange=32:20
|
||||
AttrPalmPressureThreshold=254
|
||||
86
data/50-system-google.quirks
Normal file
86
data/50-system-google.quirks
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
[Google Chromebook R13 CB5-312T]
|
||||
MatchName=*Elan Touchpad*
|
||||
MatchDeviceTree=*Chromebook R13 CB5-312T*
|
||||
AttrPressureRange=6:4
|
||||
|
||||
[Google Chromebook CB5-312T]
|
||||
MatchName=*Elan Touchpad*
|
||||
MatchDeviceTree=*CB5-312T*
|
||||
AttrPressureRange=6:4
|
||||
|
||||
[Google Chromebook Elm]
|
||||
MatchName=*Elan Touchpad*
|
||||
MatchDeviceTree=*Elm*
|
||||
AttrPressureRange=6:4
|
||||
|
||||
[Google Chromebook Falco]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=Cypress APA Trackpad ?cyapa?
|
||||
MatchDMIModalias=dmi:*pn*Falco*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook Mario]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*pn*Mario*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook Butterfly]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=Cypress APA Trackpad ?cyapa?
|
||||
MatchDMIModalias=dmi:*pn*Butterfly*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook Peppy]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=Cypress APA Trackpad ?cyapa?
|
||||
MatchDMIModalias=dmi:*pn*Peppy*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook ZGB]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*pn*ZGB*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook Parrot]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=Cypress APA Trackpad ?cyapa?
|
||||
MatchDMIModalias=dmi:*pn*Parrot*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook Leon]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=Cypress APA Trackpad ?cyapa?
|
||||
MatchDMIModalias=dmi:*bvn*coreboot*:pn*Leon*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook Wolf]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=Cypress APA Trackpad ?cyapa?
|
||||
MatchDMIModalias=dmi:*bvn*coreboot*:pn*Wolf*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook Link]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=Cypress APA Trackpad ?cyapa?
|
||||
MatchDMIModalias=dmi:*svn*GOOGLE*:pn*Link*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook Alex]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*pn*Alex*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook Lumpy]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=Cypress APA Trackpad ?cyapa?
|
||||
MatchDMIModalias=dmi:*svn*SAMSUNG*:pn*Lumpy*
|
||||
ModelChromebook=1
|
||||
|
||||
[Google Chromebook Samus]
|
||||
MatchUdevType=touchpad
|
||||
MatchName=Atmel maXTouch Touchpad
|
||||
MatchDMIModalias=dmi:*svn*GOOGLE*:pn*Samus*
|
||||
ModelChromebook=1
|
||||
24
data/50-system-hp.quirks
Normal file
24
data/50-system-hp.quirks
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
[HP Compaq 6910p]
|
||||
MatchName=*SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnHewlett-Packard:*pnHPCompaq6910p*
|
||||
ModelHP6910Touchpad=1
|
||||
|
||||
[HP Compaq 8510w]
|
||||
MatchName=*SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnHewlett-Packard:*pnHPCompaq8510w*
|
||||
ModelHP8510Touchpad=1
|
||||
|
||||
[HP Pavillion dmi4]
|
||||
MatchName=*SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnHewlett-Packard:*pnHPPaviliondm4NotebookPC*
|
||||
ModelHPPavilionDM4Touchpad=1
|
||||
|
||||
[HP Stream 11]
|
||||
MatchName=SYN1EDE:00 06CB:7442
|
||||
MatchDMIModalias=dmi:*svnHewlett-Packard:pnHPStreamNotebookPC11*
|
||||
ModelHPStream11Touchpad=1
|
||||
|
||||
[HP ZBook Studio G3]
|
||||
MatchName=AlpsPS/2 ALPS GlidePoint
|
||||
MatchDMIModalias=dmi:*svnHP:pnHPZBookStudioG3:*
|
||||
ModelHPZBookStudioG3=1
|
||||
78
data/50-system-lenovo.quirks
Normal file
78
data/50-system-lenovo.quirks
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
[Lenovo Thinkpad Touchpad]
|
||||
MatchName=*Synaptics*
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPad*:*
|
||||
AttrThumbPressureThreshold=100
|
||||
|
||||
[Lenovo x230 Touchpad]
|
||||
MatchName=*SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadX230*
|
||||
ModelLenovoX230=1
|
||||
|
||||
[Lenovo T440p Touchpad PS/2]
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT440p*
|
||||
ModelLenovoT450Touchpad=1
|
||||
|
||||
[Lenovo T440p Touchpad RMI4]
|
||||
MatchName=Synaptics tm2964-001
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT440p*
|
||||
ModelLenovoT450Touchpad=1
|
||||
|
||||
[Lenovo T440s Trackpoint]
|
||||
MatchName=TPPS/2 IBM TrackPoint
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT440s*
|
||||
AttrTrackpointRange=30
|
||||
|
||||
[Lenovo T440s Trackpoint]
|
||||
MatchName=TPPS/2 IBM TrackPoint
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT450s*
|
||||
AttrTrackpointRange=50
|
||||
|
||||
[Lenovo P50 Touchpad]
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadP50*:
|
||||
ModelLenovoT450Touchpad=1
|
||||
AttrPalmPressureThreshold=150
|
||||
|
||||
[Lenovo *50 Touchpad]
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPad??50*:
|
||||
ModelLenovoT450Touchpad=1
|
||||
AttrPalmPressureThreshold=150
|
||||
|
||||
[Lenovo *60 Touchpad]
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPad??60*:
|
||||
ModelLenovoT450Touchpad=1
|
||||
AttrPalmPressureThreshold=150
|
||||
|
||||
[Lenovo X1 Carbon 3rd Touchpad]
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadX1Carbon3rd:*
|
||||
ModelLenovoT450Touchpad=1
|
||||
AttrPalmPressureThreshold=150
|
||||
|
||||
[Lenovo ThinkPad Compact USB Keyboard with TrackPoint]
|
||||
MatchUdevType=keyboard
|
||||
MatchBus=usb
|
||||
MatchVendor=0x17EF
|
||||
MatchProduct=0x6047
|
||||
AttrKeyboardIntegration=external
|
||||
|
||||
[Lenovo X280 Trackpoint]
|
||||
MatchName=*ALPS TrackPoint*
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadX280:*
|
||||
AttrTrackpointRange=70
|
||||
|
||||
# Lenovo Thinkpad X1 Yoga disables the keyboard anyway but has the same device
|
||||
# use a windows key on the screen and volume rocker on the side (#103749)
|
||||
[Lenovo Thinkpad X1 Yoga]
|
||||
MatchName=AT Translated Set 2 keyboard
|
||||
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX1Yoga1st:*
|
||||
ModelTabletModeNoSuspend=1
|
||||
|
||||
# Lenovo Carbon X1 6th gen (RMI4 only, PS/2 is broken on this device)
|
||||
[Lenovo Carbon X1 6th gen]
|
||||
MatchName=Synaptics TM3288-010
|
||||
MatchDMIModalias=dmi:*svnLenovo:*pvrThinkPadX1Carbon6th:*
|
||||
ModelLenovoCarbonX16th=1
|
||||
19
data/50-system-system76.quirks
Normal file
19
data/50-system-system76.quirks
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[System76 Bonobo Professional]
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnSystem76*pvrbonp5*
|
||||
ModelSystem76Bonobo=1
|
||||
|
||||
[System76 Clevo]
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*pnW740SU*rnW740SU*
|
||||
ModelClevoW740SU=1
|
||||
|
||||
[System76 Galago Ultra Pro]
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnSystem76*pvrgalu1*
|
||||
ModelSystem76Galago=1
|
||||
|
||||
[System76 Kudu Professional]
|
||||
MatchName=SynPS/2 Synaptics TouchPad
|
||||
MatchDMIModalias=dmi:*svnSystem76*pvrkudp1*
|
||||
ModelSystem76Kudu=1
|
||||
77
data/README.md
Normal file
77
data/README.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
= libinput data file format =
|
||||
|
||||
This directory contains hardware quirks used by libinput to work around bugs
|
||||
in the hardware, device behavior and to supply information not obtained
|
||||
through the kernel device.
|
||||
|
||||
**THIS IS NOT STABLE API**
|
||||
|
||||
The data format may change at any time. If your data file is not part of the
|
||||
libinput git tree, do not expect it to work after an update. Absolutely no
|
||||
guarantees are made for backwards-compatibility.
|
||||
|
||||
**THIS IS NOT A CONFIGURATION API**
|
||||
|
||||
Use the `libinput_device_config_foo()` functions for device configuration.
|
||||
The quirks are hardware quirks only.
|
||||
|
||||
== Data file naming ==
|
||||
|
||||
Data files are read in versionsort order, read order determines how values
|
||||
override each other. A values read later override previously values. The
|
||||
current structure is 10-generic-foo.quirks for generic settings,
|
||||
30-vendor-foo.quirks for vendor-specific settings and 50-system-foo.quirks
|
||||
for system vendors. This is not a fixed naming scheme and may change at any
|
||||
time. It's an approximation only because some vendors are also system
|
||||
vendors, e.g. Microsoft makes devices and laptops.
|
||||
|
||||
Laptop-specific quirks should always go into the laptop vendor's file.
|
||||
|
||||
== Sections, matches and values ==
|
||||
|
||||
A data file must contain at least one section, each section must have at
|
||||
least one `Match` tag and at least one of either `Attr` or `Model`. Section
|
||||
names are free-form and may contain spaces.
|
||||
|
||||
```
|
||||
# This is a comment
|
||||
[Some touchpad]
|
||||
MatchBus=usb
|
||||
# No quotes around strings
|
||||
MatchName=*Synaptics Touchpad*
|
||||
AttrSizeHint=50x50
|
||||
ModelSynapticsTouchpad=1
|
||||
|
||||
[Apple touchpad]
|
||||
MatchVendor=0x5AC
|
||||
MatchProduct=0x123
|
||||
ModelAppleTouchpad=1
|
||||
```
|
||||
|
||||
Comments are lines starting with `#`.
|
||||
|
||||
All `Model` tags take a value of either `1` or `0`.
|
||||
|
||||
All `Attr` tag values are specific to that attribute.
|
||||
|
||||
== Parser errors ==
|
||||
|
||||
The following will cause parser errors and are considered invalid data
|
||||
files:
|
||||
|
||||
* Whitespace at the beginning of the line
|
||||
* Sections without at least one `Match*` entry
|
||||
* Sections with the same `Match*` entry repeated
|
||||
* Sections without at least one of `Model*` or `Attr` entries
|
||||
* A `Model` tag with a value other than `1` or `0`
|
||||
* A string property with enclosing quotes
|
||||
|
||||
== Debugging ==
|
||||
|
||||
When modifying a data file, use the `libinput list-quirks` tool to
|
||||
verify the changes. The tool can be pointed at the data directory to
|
||||
analyse, use `--verbose` to get more info. For example:
|
||||
|
||||
```
|
||||
libinput list-quirks --data-dir /path/to/git/repo/data/ --verbose /dev/input/event0
|
||||
```
|
||||
102
doc/device-quirks.dox
Normal file
102
doc/device-quirks.dox
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
@page device-quirks Device quirks
|
||||
|
||||
libinput requires extra information from devices that is not always readily
|
||||
available. For example, some touchpads are known to have jumping cursors
|
||||
under specific conditions. libinput ships a set of files containting the
|
||||
so-called model quirks to provide that information. Model quirks are usually
|
||||
installed under `/usr/share/libinput/<filename>.quirks` and are standard
|
||||
`.ini` files. A file may contain multiple section headers (`[some
|
||||
identifier]`) followed by one or more `MatchFoo=Bar` directives, followed by
|
||||
at least one of `ModelFoo=1` or `AttrFoo=bar` directive. See the
|
||||
`data/README.md` file in the libinput source repository for more details on
|
||||
their contents.
|
||||
|
||||
@note Model quirks are internal API and may change at any time. No
|
||||
backwards-compatibility is guaranteed.
|
||||
|
||||
For example, a quirks file may have this content to label all keyboards on
|
||||
the serial bus (PS/2) as internal keyboards:
|
||||
|
||||
@verbatim
|
||||
[Serial Keyboards]
|
||||
MatchUdevType=keyboard
|
||||
MatchBus=serial
|
||||
AttrKeyboardIntegration=internal
|
||||
@endverbatim
|
||||
|
||||
The model quirks are part of the source distribution and should never be
|
||||
modified locally. Updates to libinput may overwrite modifications or even
|
||||
stop parsing any property. For temporary local workarounds, see @ref
|
||||
device-quirks-local.
|
||||
|
||||
Device quirks are parsed on libinput initialization. A parsing error in the
|
||||
device quirks disables **all** device quirks and may negatively impact
|
||||
device behavior on the host. If the quirks cannot be loaded, an error
|
||||
message is posted to the log and users should use the information in @ref
|
||||
device-quirks-debugging to verify their quirks files.
|
||||
|
||||
@section device-quirks-local Installing temporary local device quirks
|
||||
|
||||
The model quirks are part of the source distribution and should never be
|
||||
modified. For temporary local workarounds, libinput reads the
|
||||
`/etc/libinput/local-overrides.quirks` file. Users may add a sections to
|
||||
this file to add a device quirk for a local device but beware that **any
|
||||
modification must be upstreamed** or it may cease to work at any time.
|
||||
|
||||
@note Model quirks are internal API and may change at any time. No
|
||||
backwards-compatibility is guaranteed. Local overrides should only be used
|
||||
until the distribution updates the libinput packages.
|
||||
|
||||
The `local-overrides.quirks` file usually needs to be created by the user.
|
||||
Once the required section has been added, use the information from section
|
||||
@ref device-quirks-debugging to validate and test the quirks.
|
||||
|
||||
@section device-quirks-debugging Debugging device quirks
|
||||
|
||||
libinput provides the `libinput list-quirks` tool to list and debug model
|
||||
quirks that apply to one or more local devices.
|
||||
|
||||
@verbatim
|
||||
$ libinput list-quirks /dev/input/event19
|
||||
Device has no quirks defined
|
||||
$ libinput list-quirks /dev/input/event0
|
||||
AttrLidSwitchReliability
|
||||
@endverbatim
|
||||
|
||||
When called with the `--verbose` argument, `libinput list-quirks` prints
|
||||
information about all files and its attempts to match the device:
|
||||
|
||||
@verbatim
|
||||
$ libinput list-quirks --verbose /dev/input/event0
|
||||
quirks debug: /usr/share/share/libinput is data root
|
||||
quirks debug: /usr/share/share/libinput/10-generic-keyboard.quirks
|
||||
quirks debug: /usr/share/share/libinput/10-generic-lid.quirks
|
||||
[...]
|
||||
quirks debug: /usr/share/etc/libinput/local-overrides.quirks
|
||||
quirks debug: /dev/input/event0: fetching quirks
|
||||
quirks debug: [Serial Keyboards] (10-generic-keyboard.quirks) wants MatchBus but we don't have that
|
||||
quirks debug: [Lid Switch Ct9] (10-generic-lid.quirks) matches for MatchName
|
||||
quirks debug: [Lid Switch Ct10] (10-generic-lid.quirks) matches for MatchName
|
||||
quirks debug: [Lid Switch Ct10] (10-generic-lid.quirks) matches for MatchDMIModalias
|
||||
quirks debug: [Lid Switch Ct10] (10-generic-lid.quirks) is full match
|
||||
quirks debug: property added: AttrLidSwitchReliability from [Lid Switch Ct10] (10-generic-lid.quirks)
|
||||
quirks debug: [Aiptek No Tilt Tablet] (30-vendor-aiptek.quirks) wants MatchBus but we don't have that
|
||||
[...]
|
||||
quirks debug: [HUION PenTablet] (30-vendor-huion.quirks) wants MatchBus but we don't have that
|
||||
quirks debug: [Logitech Marble Mouse Trackball] (30-vendor-logitech.quirks) wants MatchBus but we don't have that
|
||||
quirks debug: [Logitech K400] (30-vendor-logitech.quirks) wants MatchBus but we don't have that
|
||||
quirks debug: [Logitech K400r] (30-vendor-logitech.quirks) wants MatchBus but we don't have that
|
||||
quirks debug: [Logitech K830] (30-vendor-logitech.quirks) wants MatchBus but we don't have that
|
||||
quirks debug: [Logitech K400Plus] (30-vendor-logitech.quirks) wants MatchBus but we don't have that
|
||||
quirks debug: [Logitech Wireless Touchpad] (30-vendor-logitech.quirks) wants MatchBus but we don't have that
|
||||
quirks debug: [Microsoft Surface 3 Lid Switch] (30-vendor-microsoft.quirks) matches for MatchName
|
||||
[...]
|
||||
AttrLidSwitchReliability
|
||||
@endverbatim
|
||||
|
||||
Note that this is an example only, the output may change over time. The tool
|
||||
uses the same parser as libinput and any parsing errors will show up in the
|
||||
output.
|
||||
|
||||
*/
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
@page general General
|
||||
|
||||
- @subpage device-quirks
|
||||
- @subpage udev_config
|
||||
- @subpage seats
|
||||
- @subpage timestamps
|
||||
|
|
|
|||
79
meson.build
79
meson.build
|
|
@ -181,6 +181,57 @@ libfilter = static_library('filter', src_libfilter,
|
|||
include_directories : includes_include)
|
||||
dep_libfilter = declare_dependency(link_with : libfilter)
|
||||
|
||||
############ libquirks.a #############
|
||||
libinput_data_path = join_paths(get_option('prefix'), get_option('datadir'), 'libinput')
|
||||
libinput_data_override_path = join_paths(get_option('prefix'),
|
||||
get_option('sysconfdir'),
|
||||
'libinput',
|
||||
'local-overrides.quirks')
|
||||
config_h.set_quoted('LIBINPUT_DATA_DIR', libinput_data_path)
|
||||
config_h.set_quoted('LIBINPUT_DATA_OVERRIDE_FILE', libinput_data_override_path)
|
||||
|
||||
quirks_data = [
|
||||
'data/10-generic-keyboard.quirks',
|
||||
'data/10-generic-lid.quirks',
|
||||
'data/10-generic-trackball.quirks',
|
||||
'data/30-vendor-aiptek.quirks',
|
||||
'data/30-vendor-alps.quirks',
|
||||
'data/30-vendor-cyapa.quirks',
|
||||
'data/30-vendor-elantech.quirks',
|
||||
'data/30-vendor-huion.quirks',
|
||||
'data/30-vendor-ibm.quirks',
|
||||
'data/30-vendor-logitech.quirks',
|
||||
'data/30-vendor-microsoft.quirks',
|
||||
'data/30-vendor-razer.quirks',
|
||||
'data/30-vendor-synaptics.quirks',
|
||||
'data/30-vendor-wacom.quirks',
|
||||
'data/50-system-apple.quirks',
|
||||
'data/50-system-asus.quirks',
|
||||
'data/50-system-chicony.quirks',
|
||||
'data/50-system-cyborg.quirks',
|
||||
'data/50-system-dell.quirks',
|
||||
'data/50-system-google.quirks',
|
||||
'data/50-system-hp.quirks',
|
||||
'data/50-system-lenovo.quirks',
|
||||
'data/50-system-system76.quirks',
|
||||
]
|
||||
|
||||
config_h.set_quoted('LIBINPUT_DATA_FILES', ':'.join(quirks_data))
|
||||
config_h.set_quoted('LIBINPUT_DATA_SRCDIR', join_paths(meson.source_root(), 'data'))
|
||||
|
||||
install_data(quirks_data, install_dir : libinput_data_path)
|
||||
|
||||
src_libquirks = [
|
||||
'src/quirks.c',
|
||||
'src/quirks.h',
|
||||
]
|
||||
|
||||
deps_libquirks = [dep_udev, dep_libinput_util]
|
||||
libquirks = static_library('quirks', src_libquirks,
|
||||
dependencies : deps_libquirks,
|
||||
include_directories : includes_include)
|
||||
dep_libquirks = declare_dependency(link_with : libquirks)
|
||||
|
||||
############ libinput.so ############
|
||||
install_headers('src/libinput.h')
|
||||
src_libinput = src_libfilter + [
|
||||
|
|
@ -220,7 +271,8 @@ deps_libinput = [
|
|||
dep_lm,
|
||||
dep_rt,
|
||||
dep_libwacom,
|
||||
dep_libinput_util
|
||||
dep_libinput_util,
|
||||
dep_libquirks
|
||||
]
|
||||
|
||||
libinput_version_h_config = configuration_data()
|
||||
|
|
@ -317,6 +369,7 @@ if get_option('documentation')
|
|||
meson.source_root() + '/doc/clickpad-softbuttons.dox',
|
||||
meson.source_root() + '/doc/contributing.dox',
|
||||
meson.source_root() + '/doc/device-configuration-via-udev.dox',
|
||||
meson.source_root() + '/doc/device-quirks.dox',
|
||||
meson.source_root() + '/doc/faqs.dox',
|
||||
meson.source_root() + '/doc/gestures.dox',
|
||||
meson.source_root() + '/doc/middle-button-emulation.dox',
|
||||
|
|
@ -435,6 +488,26 @@ configure_file(input : 'tools/libinput-debug-events.man',
|
|||
install_dir : join_paths(get_option('mandir'), 'man1')
|
||||
)
|
||||
|
||||
libinput_list_quirks_sources = [ 'tools/libinput-list-quirks.c' ]
|
||||
libinput_list_quirks = executable('libinput-list-quirks',
|
||||
libinput_list_quirks_sources,
|
||||
dependencies : [dep_libquirks, dep_libinput],
|
||||
include_directories : [includes_src, includes_include],
|
||||
install_dir : libinput_tool_path,
|
||||
install : true
|
||||
)
|
||||
test('validate-quirks',
|
||||
libinput_list_quirks,
|
||||
args: ['--validate-only', '--data-dir=@0@'.format(join_paths(meson.source_root(), 'data'))]
|
||||
)
|
||||
|
||||
configure_file(input : 'tools/libinput-list-quirks.man',
|
||||
output : 'libinput-list-quirks.1',
|
||||
configuration : man_config,
|
||||
install : true,
|
||||
install_dir : join_paths(get_option('mandir'), 'man1')
|
||||
)
|
||||
|
||||
libinput_list_devices_sources = [ 'tools/libinput-list-devices.c' ]
|
||||
executable('libinput-list-devices',
|
||||
libinput_list_devices_sources,
|
||||
|
|
@ -697,6 +770,7 @@ if get_option('tests')
|
|||
dep_dl,
|
||||
dep_lm,
|
||||
dep_libsystemd,
|
||||
dep_libquirks,
|
||||
]
|
||||
|
||||
configure_file(input : 'udev/80-libinput-test-device.rules',
|
||||
|
|
@ -763,7 +837,8 @@ if get_option('tests')
|
|||
'test/test-keyboard.c',
|
||||
'test/test-device.c',
|
||||
'test/test-gestures.c',
|
||||
'test/test-switch.c'
|
||||
'test/test-switch.c',
|
||||
'test/test-quirks.c',
|
||||
]
|
||||
def_LT_VERSION = '-DLIBINPUT_LT_VERSION="@0@:@1@:@2@"'.format(libinput_lt_c, libinput_lt_r, libinput_lt_a)
|
||||
libinput_test_runner = executable('libinput-test-suite-runner',
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "quirks.h"
|
||||
#include "evdev-mt-touchpad.h"
|
||||
|
||||
#define DEFAULT_TRACKPOINT_ACTIVITY_TIMEOUT ms2us(300)
|
||||
|
|
@ -2841,16 +2842,25 @@ tp_dwt_config_get_default(struct libinput_device *device)
|
|||
static inline bool
|
||||
tp_is_tpkb_combo_below(struct evdev_device *device)
|
||||
{
|
||||
const char *prop;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
char *prop;
|
||||
enum tpkbcombo_layout layout = TPKBCOMBO_LAYOUT_UNKNOWN;
|
||||
int rc = false;
|
||||
|
||||
prop = udev_device_get_property_value(device->udev_device,
|
||||
"LIBINPUT_ATTR_TPKBCOMBO_LAYOUT");
|
||||
if (!prop)
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (!q)
|
||||
return false;
|
||||
|
||||
return parse_tpkbcombo_layout_poperty(prop, &layout) &&
|
||||
layout == TPKBCOMBO_LAYOUT_BELOW;
|
||||
if (quirks_get_string(q, QUIRK_ATTR_TPKBCOMBO_LAYOUT, &prop)) {
|
||||
rc = parse_tpkbcombo_layout_poperty(prop, &layout) &&
|
||||
layout == TPKBCOMBO_LAYOUT_BELOW;
|
||||
}
|
||||
|
||||
quirks_unref(q);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
|
@ -2917,19 +2927,20 @@ static int
|
|||
tp_read_palm_pressure_prop(struct tp_dispatch *tp,
|
||||
const struct evdev_device *device)
|
||||
{
|
||||
struct udev_device *udev_device = device->udev_device;
|
||||
const char *prop;
|
||||
int threshold;
|
||||
const int default_palm_threshold = 130;
|
||||
uint32_t threshold = default_palm_threshold;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
|
||||
prop = udev_device_get_property_value(udev_device,
|
||||
"LIBINPUT_ATTR_PALM_PRESSURE_THRESHOLD");
|
||||
if (!prop)
|
||||
return default_palm_threshold;
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (!q)
|
||||
return threshold;
|
||||
|
||||
threshold = parse_palm_pressure_property(prop);
|
||||
quirks_get_uint32(q, QUIRK_ATTR_PALM_PRESSURE_THRESHOLD, &threshold);
|
||||
quirks_unref(q);
|
||||
|
||||
return threshold > 0 ? threshold : default_palm_threshold;
|
||||
return threshold;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
@ -2953,24 +2964,26 @@ static inline void
|
|||
tp_init_palmdetect_size(struct tp_dispatch *tp,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
const char *prop;
|
||||
int threshold;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
uint32_t threshold;
|
||||
|
||||
prop = udev_device_get_property_value(device->udev_device,
|
||||
"LIBINPUT_ATTR_PALM_SIZE_THRESHOLD");
|
||||
if (!prop)
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (!q)
|
||||
return;
|
||||
|
||||
threshold = parse_palm_size_property(prop);
|
||||
if (threshold == 0) {
|
||||
evdev_log_bug_client(device,
|
||||
"palm: ignoring invalid threshold %s\n",
|
||||
prop);
|
||||
return;
|
||||
if (quirks_get_uint32(q, QUIRK_ATTR_PALM_SIZE_THRESHOLD, &threshold)) {
|
||||
if (threshold == 0) {
|
||||
evdev_log_bug_client(device,
|
||||
"palm: ignoring invalid threshold %d\n",
|
||||
threshold);
|
||||
} else {
|
||||
tp->palm.use_size = true;
|
||||
tp->palm.size_threshold = threshold;
|
||||
}
|
||||
}
|
||||
|
||||
tp->palm.use_size = true;
|
||||
tp->palm.size_threshold = threshold;
|
||||
quirks_unref(q);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
@ -3045,25 +3058,6 @@ tp_init_sendevents(struct tp_dispatch *tp,
|
|||
tp_keyboard_timeout, tp);
|
||||
}
|
||||
|
||||
static int
|
||||
tp_read_thumb_pressure_prop(struct tp_dispatch *tp,
|
||||
const struct evdev_device *device)
|
||||
{
|
||||
struct udev_device *udev_device = device->udev_device;
|
||||
const char *prop;
|
||||
int threshold;
|
||||
const int default_thumb_threshold = 0;
|
||||
|
||||
prop = udev_device_get_property_value(udev_device,
|
||||
"LIBINPUT_ATTR_THUMB_PRESSURE_THRESHOLD");
|
||||
if (!prop)
|
||||
return default_thumb_threshold;
|
||||
|
||||
threshold = parse_thumb_pressure_property(prop);
|
||||
|
||||
return threshold > 0 ? threshold : default_thumb_threshold;
|
||||
}
|
||||
|
||||
static void
|
||||
tp_init_thumb(struct tp_dispatch *tp)
|
||||
{
|
||||
|
|
@ -3072,7 +3066,9 @@ tp_init_thumb(struct tp_dispatch *tp)
|
|||
double w = 0.0, h = 0.0;
|
||||
struct device_coords edges;
|
||||
struct phys_coords mm = { 0.0, 0.0 };
|
||||
int threshold;
|
||||
uint32_t threshold;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
|
||||
if (!tp->buttons.is_clickpad)
|
||||
return;
|
||||
|
|
@ -3101,11 +3097,13 @@ tp_init_thumb(struct tp_dispatch *tp)
|
|||
if (!abs)
|
||||
goto out;
|
||||
|
||||
threshold = tp_read_thumb_pressure_prop(tp, device);
|
||||
if (threshold == 0)
|
||||
goto out;
|
||||
|
||||
tp->thumb.threshold = threshold;
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (quirks_get_uint32(q,
|
||||
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
|
||||
&threshold))
|
||||
tp->thumb.threshold = threshold;
|
||||
quirks_unref(q);
|
||||
|
||||
out:
|
||||
evdev_log_debug(device,
|
||||
|
|
@ -3203,7 +3201,9 @@ tp_init_pressure(struct tp_dispatch *tp,
|
|||
{
|
||||
const struct input_absinfo *abs;
|
||||
unsigned int code;
|
||||
const char *prop;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
struct quirk_range r;
|
||||
int hi, lo;
|
||||
|
||||
code = tp->has_mt ? ABS_MT_PRESSURE : ABS_PRESSURE;
|
||||
|
|
@ -3215,20 +3215,16 @@ tp_init_pressure(struct tp_dispatch *tp,
|
|||
abs = libevdev_get_abs_info(device->evdev, code);
|
||||
assert(abs);
|
||||
|
||||
prop = udev_device_get_property_value(device->udev_device,
|
||||
"LIBINPUT_ATTR_PRESSURE_RANGE");
|
||||
if (prop) {
|
||||
if (!parse_range_property(prop, &hi, &lo)) {
|
||||
evdev_log_bug_client(device,
|
||||
"discarding invalid pressure range '%s'\n",
|
||||
prop);
|
||||
return;
|
||||
}
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (q && quirks_get_range(q, QUIRK_ATTR_PRESSURE_RANGE, &r)) {
|
||||
hi = r.upper;
|
||||
lo = r.lower;
|
||||
|
||||
if (hi == 0 && lo == 0) {
|
||||
evdev_log_info(device,
|
||||
"pressure-based touch detection disabled\n");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
unsigned int range = abs->maximum - abs->minimum;
|
||||
|
|
@ -3238,12 +3234,13 @@ tp_init_pressure(struct tp_dispatch *tp,
|
|||
lo = abs->minimum + 0.10 * range;
|
||||
}
|
||||
|
||||
|
||||
if (hi > abs->maximum || hi < abs->minimum ||
|
||||
lo > abs->maximum || lo < abs->minimum) {
|
||||
evdev_log_bug_libinput(device,
|
||||
"discarding out-of-bounds pressure range %d:%d\n",
|
||||
hi, lo);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tp->pressure.use_pressure = true;
|
||||
|
|
@ -3254,14 +3251,19 @@ tp_init_pressure(struct tp_dispatch *tp,
|
|||
"using pressure-based touch detection (%d:%d)\n",
|
||||
lo,
|
||||
hi);
|
||||
out:
|
||||
quirks_unref(q);
|
||||
}
|
||||
|
||||
static bool
|
||||
tp_init_touch_size(struct tp_dispatch *tp,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
const char *prop;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
struct quirk_range r;
|
||||
int lo, hi;
|
||||
int rc = false;
|
||||
|
||||
if (!libevdev_has_event_code(device->evdev,
|
||||
EV_ABS,
|
||||
|
|
@ -3269,28 +3271,25 @@ tp_init_touch_size(struct tp_dispatch *tp,
|
|||
return false;
|
||||
}
|
||||
|
||||
prop = udev_device_get_property_value(device->udev_device,
|
||||
"LIBINPUT_ATTR_TOUCH_SIZE_RANGE");
|
||||
if (!prop)
|
||||
return false;
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (q && quirks_get_range(q, QUIRK_ATTR_TOUCH_SIZE_RANGE, &r)) {
|
||||
hi = r.upper;
|
||||
lo = r.lower;
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (libevdev_get_num_slots(device->evdev) < 5) {
|
||||
evdev_log_bug_libinput(device,
|
||||
"Expected 5+ slots for touch size detection\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_range_property(prop, &hi, &lo)) {
|
||||
evdev_log_bug_client(device,
|
||||
"discarding invalid touch size range '%s'\n",
|
||||
prop);
|
||||
return false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hi == 0 && lo == 0) {
|
||||
evdev_log_info(device,
|
||||
"touch size based touch detection disabled\n");
|
||||
return false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Thresholds apply for both major or minor */
|
||||
|
|
@ -3302,7 +3301,10 @@ tp_init_touch_size(struct tp_dispatch *tp,
|
|||
"using size-based touch detection (%d:%d)\n",
|
||||
hi, lo);
|
||||
|
||||
return true;
|
||||
rc = true;
|
||||
out:
|
||||
quirks_unref(q);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
155
src/evdev.c
155
src/evdev.c
|
|
@ -43,6 +43,7 @@
|
|||
#include "evdev.h"
|
||||
#include "filter.h"
|
||||
#include "libinput-private.h"
|
||||
#include "quirks.h"
|
||||
|
||||
#if HAVE_LIBWACOM
|
||||
#include <libwacom/libwacom.h>
|
||||
|
|
@ -410,7 +411,9 @@ static void
|
|||
evdev_tag_keyboard(struct evdev_device *device,
|
||||
struct udev_device *udev_device)
|
||||
{
|
||||
const char *prop;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
char *prop;
|
||||
int code;
|
||||
|
||||
if (!libevdev_has_event_type(device->evdev, EV_KEY))
|
||||
|
|
@ -423,10 +426,9 @@ evdev_tag_keyboard(struct evdev_device *device,
|
|||
return;
|
||||
}
|
||||
|
||||
/* This should eventually become ID_INPUT_KEYBOARD_INTEGRATION */
|
||||
prop = udev_device_get_property_value(udev_device,
|
||||
"LIBINPUT_ATTR_KEYBOARD_INTEGRATION");
|
||||
if (prop) {
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (q && quirks_get_string(q, QUIRK_ATTR_KEYBOARD_INTEGRATION, &prop)) {
|
||||
if (streq(prop, "internal")) {
|
||||
evdev_tag_keyboard_internal(device);
|
||||
} else if (streq(prop, "external")) {
|
||||
|
|
@ -438,6 +440,8 @@ evdev_tag_keyboard(struct evdev_device *device,
|
|||
}
|
||||
}
|
||||
|
||||
quirks_unref(q);
|
||||
|
||||
device->tags |= EVDEV_TAG_KEYBOARD;
|
||||
}
|
||||
|
||||
|
|
@ -796,12 +800,16 @@ evdev_is_fake_mt_device(struct evdev_device *device)
|
|||
enum switch_reliability
|
||||
evdev_read_switch_reliability_prop(struct evdev_device *device)
|
||||
{
|
||||
const char *prop;
|
||||
enum switch_reliability r;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
char *prop;
|
||||
|
||||
prop = udev_device_get_property_value(device->udev_device,
|
||||
"LIBINPUT_ATTR_LID_SWITCH_RELIABILITY");
|
||||
if (!parse_switch_reliability_property(prop, &r)) {
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (!q || !quirks_get_string(q, QUIRK_ATTR_LID_SWITCH_RELIABILITY, &prop)) {
|
||||
r = RELIABILITY_UNKNOWN;
|
||||
} else if (!parse_switch_reliability_property(prop, &r)) {
|
||||
evdev_log_error(device,
|
||||
"%s: switch reliability set to unknown value '%s'\n",
|
||||
device->devname,
|
||||
|
|
@ -811,6 +819,8 @@ evdev_read_switch_reliability_prop(struct evdev_device *device)
|
|||
evdev_log_info(device, "will write switch open events\n");
|
||||
}
|
||||
|
||||
quirks_unref(q);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -1169,22 +1179,17 @@ evdev_read_wheel_tilt_props(struct evdev_device *device)
|
|||
static inline int
|
||||
evdev_get_trackpoint_range(struct evdev_device *device)
|
||||
{
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
const char *prop;
|
||||
int range = DEFAULT_TRACKPOINT_RANGE;
|
||||
uint32_t range = DEFAULT_TRACKPOINT_RANGE;
|
||||
|
||||
if (!(device->tags & EVDEV_TAG_TRACKPOINT))
|
||||
return DEFAULT_TRACKPOINT_RANGE;
|
||||
|
||||
prop = udev_device_get_property_value(device->udev_device,
|
||||
"LIBINPUT_ATTR_TRACKPOINT_RANGE");
|
||||
if (prop) {
|
||||
if (!safe_atoi(prop, &range) || range < 0.0) {
|
||||
evdev_log_error(device,
|
||||
"trackpoint range property is present but invalid, "
|
||||
"using %d instead\n",
|
||||
DEFAULT_TRACKPOINT_RANGE);
|
||||
range = DEFAULT_TRACKPOINT_RANGE;
|
||||
}
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (q && quirks_get_uint32(q, QUIRK_ATTR_TRACKPOINT_RANGE, &range)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -1215,6 +1220,8 @@ evdev_get_trackpoint_range(struct evdev_device *device)
|
|||
}
|
||||
|
||||
out:
|
||||
quirks_unref(q);
|
||||
|
||||
if (range == 0) {
|
||||
evdev_log_bug_libinput(device, "trackpoint range is zero\n");
|
||||
range = DEFAULT_TRACKPOINT_RANGE;
|
||||
|
|
@ -1256,12 +1263,11 @@ static inline uint32_t
|
|||
evdev_read_model_flags(struct evdev_device *device)
|
||||
{
|
||||
const struct model_map {
|
||||
const char *property;
|
||||
enum quirk quirk;
|
||||
enum evdev_device_model model;
|
||||
} model_map[] = {
|
||||
#define MODEL(name) { "LIBINPUT_MODEL_" #name, EVDEV_MODEL_##name }
|
||||
#define MODEL(name) { QUIRK_MODEL_##name, EVDEV_MODEL_##name }
|
||||
MODEL(LENOVO_X230),
|
||||
MODEL(LENOVO_X220_TOUCHPAD_FW81),
|
||||
MODEL(CHROMEBOOK),
|
||||
MODEL(SYSTEM76_BONOBO),
|
||||
MODEL(SYSTEM76_GALAGO),
|
||||
|
|
@ -1290,29 +1296,62 @@ evdev_read_model_flags(struct evdev_device *device)
|
|||
MODEL(LENOVO_CARBON_X1_6TH),
|
||||
MODEL(LENOVO_SCROLLPOINT),
|
||||
#undef MODEL
|
||||
{ "ID_INPUT_TRACKBALL", EVDEV_MODEL_TRACKBALL },
|
||||
{ NULL, EVDEV_MODEL_DEFAULT },
|
||||
{ 0, 0 },
|
||||
};
|
||||
const struct model_map *m = model_map;
|
||||
uint32_t model_flags = 0;
|
||||
uint32_t all_model_flags = 0;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
|
||||
while (q && m->quirk) {
|
||||
bool is_set;
|
||||
|
||||
while (m->property) {
|
||||
/* Check for flag re-use */
|
||||
if (strneq("LIBINPUT_MODEL_", m->property, 15)) {
|
||||
assert((all_model_flags & m->model) == 0);
|
||||
all_model_flags |= m->model;
|
||||
assert((all_model_flags & m->model) == 0);
|
||||
all_model_flags |= m->model;
|
||||
|
||||
if (quirks_get_bool(q, m->quirk, &is_set)) {
|
||||
if (is_set) {
|
||||
evdev_log_debug(device,
|
||||
"tagged as %s\n",
|
||||
quirk_get_name(m->quirk));
|
||||
model_flags |= m->model;
|
||||
} else {
|
||||
evdev_log_debug(device,
|
||||
"untagged as %s\n",
|
||||
quirk_get_name(m->quirk));
|
||||
model_flags &= ~m->model;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_udev_flag(device,
|
||||
device->udev_device,
|
||||
m->property)) {
|
||||
evdev_log_debug(device, "tagged as %s\n", m->property);
|
||||
model_flags |= m->model;
|
||||
}
|
||||
m++;
|
||||
}
|
||||
|
||||
quirks_unref(q);
|
||||
|
||||
if (parse_udev_flag(device,
|
||||
device->udev_device,
|
||||
"ID_INPUT_TRACKBALL")) {
|
||||
evdev_log_debug(device, "tagged as trackball\n");
|
||||
model_flags |= EVDEV_MODEL_TRACKBALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Device is 6 years old at the time of writing this and this was
|
||||
* one of the few udev properties that wasn't reserved for private
|
||||
* usage, so we need to keep this for backwards compat.
|
||||
*/
|
||||
if (parse_udev_flag(device,
|
||||
device->udev_device,
|
||||
"LIBINPUT_MODEL_LENOVO_X220_TOUCHPAD_FW81")) {
|
||||
evdev_log_debug(device, "tagged as trackball\n");
|
||||
model_flags |= EVDEV_MODEL_LENOVO_X220_TOUCHPAD_FW81;
|
||||
}
|
||||
|
||||
return model_flags;
|
||||
}
|
||||
|
||||
|
|
@ -1321,16 +1360,25 @@ evdev_read_attr_res_prop(struct evdev_device *device,
|
|||
size_t *xres,
|
||||
size_t *yres)
|
||||
{
|
||||
struct udev_device *udev;
|
||||
const char *res_prop;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
struct quirk_dimensions dim;
|
||||
bool rc = false;
|
||||
|
||||
udev = device->udev_device;
|
||||
res_prop = udev_device_get_property_value(udev,
|
||||
"LIBINPUT_ATTR_RESOLUTION_HINT");
|
||||
if (!res_prop)
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (!q)
|
||||
return false;
|
||||
|
||||
return parse_dimension_property(res_prop, xres, yres);
|
||||
rc = quirks_get_dimensions(q, QUIRK_ATTR_RESOLUTION_HINT, &dim);
|
||||
if (rc) {
|
||||
*xres = dim.x;
|
||||
*yres = dim.y;
|
||||
}
|
||||
|
||||
quirks_unref(q);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
|
@ -1338,16 +1386,25 @@ evdev_read_attr_size_prop(struct evdev_device *device,
|
|||
size_t *size_x,
|
||||
size_t *size_y)
|
||||
{
|
||||
struct udev_device *udev;
|
||||
const char *size_prop;
|
||||
struct quirks_context *quirks;
|
||||
struct quirks *q;
|
||||
struct quirk_dimensions dim;
|
||||
bool rc = false;
|
||||
|
||||
udev = device->udev_device;
|
||||
size_prop = udev_device_get_property_value(udev,
|
||||
"LIBINPUT_ATTR_SIZE_HINT");
|
||||
if (!size_prop)
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (!q)
|
||||
return false;
|
||||
|
||||
return parse_dimension_property(size_prop, size_x, size_y);
|
||||
rc = quirks_get_dimensions(q, QUIRK_ATTR_SIZE_HINT, &dim);
|
||||
if (rc) {
|
||||
*size_x = dim.x;
|
||||
*size_y = dim.y;
|
||||
}
|
||||
|
||||
quirks_unref(q);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Return 1 if the device is set to the fake resolution or 0 otherwise */
|
||||
|
|
|
|||
|
|
@ -140,6 +140,9 @@ struct libinput {
|
|||
struct list device_group_list;
|
||||
|
||||
uint64_t last_event_time;
|
||||
|
||||
bool quirks_initialized;
|
||||
struct quirks_context *quirks;
|
||||
};
|
||||
|
||||
typedef void (*libinput_seat_destroy_func) (struct libinput_seat *seat);
|
||||
|
|
@ -427,6 +430,9 @@ libinput_init(struct libinput *libinput,
|
|||
const struct libinput_interface_backend *interface_backend,
|
||||
void *user_data);
|
||||
|
||||
void
|
||||
libinput_init_quirks(struct libinput *libinput);
|
||||
|
||||
struct libinput_source *
|
||||
libinput_add_fd(struct libinput *libinput,
|
||||
int fd,
|
||||
|
|
|
|||
|
|
@ -61,6 +61,20 @@ list_insert(struct list *list, struct list *elm)
|
|||
elm->next->prev = elm;
|
||||
}
|
||||
|
||||
void
|
||||
list_append(struct list *list, struct list *elm)
|
||||
{
|
||||
assert((list->next != NULL && list->prev != NULL) ||
|
||||
!"list->next|prev is NULL, possibly missing list_init()");
|
||||
assert(((elm->next == NULL && elm->prev == NULL) || list_empty(elm)) ||
|
||||
!"elm->next|prev is not NULL, list node used twice?");
|
||||
|
||||
elm->next = list;
|
||||
elm->prev = list->prev;
|
||||
list->prev = elm;
|
||||
elm->prev->next = elm;
|
||||
}
|
||||
|
||||
void
|
||||
list_remove(struct list *elm)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ struct list {
|
|||
|
||||
void list_init(struct list *list);
|
||||
void list_insert(struct list *list, struct list *elm);
|
||||
void list_append(struct list *list, struct list *elm);
|
||||
void list_remove(struct list *elm);
|
||||
bool list_empty(const struct list *list);
|
||||
|
||||
|
|
@ -518,6 +519,36 @@ safe_atoi(const char *str, int *val)
|
|||
return safe_atoi_base(str, val, 10);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
safe_atou_base(const char *str, unsigned int *val, int base)
|
||||
{
|
||||
char *endptr;
|
||||
unsigned long v;
|
||||
|
||||
assert(base == 10 || base == 16 || base == 8);
|
||||
|
||||
errno = 0;
|
||||
v = strtoul(str, &endptr, base);
|
||||
if (errno > 0)
|
||||
return false;
|
||||
if (str == endptr)
|
||||
return false;
|
||||
if (*str != '\0' && *endptr != '\0')
|
||||
return false;
|
||||
|
||||
if (v > UINT_MAX)
|
||||
return false;
|
||||
|
||||
*val = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
safe_atou(const char *str, unsigned int *val)
|
||||
{
|
||||
return safe_atou_base(str, val, 10);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
safe_atod(const char *str, double *val)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "libinput-private.h"
|
||||
#include "evdev.h"
|
||||
#include "timer.h"
|
||||
#include "quirks.h"
|
||||
|
||||
#define require_event_type(li_, type_, retval_, ...) \
|
||||
if (type_ == LIBINPUT_EVENT_NONE) abort(); \
|
||||
|
|
@ -1720,6 +1721,46 @@ libinput_init(struct libinput *libinput,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
libinput_init_quirks(struct libinput *libinput)
|
||||
{
|
||||
const char *data_path,
|
||||
*override_file = NULL;
|
||||
struct quirks_context *quirks;
|
||||
|
||||
if (libinput->quirks_initialized)
|
||||
return;
|
||||
|
||||
/* If we fail, we'll fail next time too */
|
||||
libinput->quirks_initialized = true;
|
||||
|
||||
data_path = getenv("LIBINPUT_DATA_DIR");
|
||||
if (!data_path) {
|
||||
data_path = LIBINPUT_DATA_DIR;
|
||||
override_file = LIBINPUT_DATA_OVERRIDE_FILE;
|
||||
}
|
||||
|
||||
quirks = quirks_init_subsystem(data_path,
|
||||
override_file,
|
||||
log_msg_va,
|
||||
libinput,
|
||||
QLOG_LIBINPUT_LOGGING);
|
||||
if (!quirks) {
|
||||
log_error(libinput,
|
||||
"Failed to load the device quirks from %s%s%s. "
|
||||
"This will negatively affect device behavior. "
|
||||
"See %sdevice-quirks.html for details.\n",
|
||||
data_path,
|
||||
override_file ? " and " : "",
|
||||
override_file ? override_file : "",
|
||||
HTTP_DOC_LINK
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
libinput->quirks = quirks;
|
||||
}
|
||||
|
||||
static void
|
||||
libinput_device_destroy(struct libinput_device *device);
|
||||
|
||||
|
|
@ -1791,6 +1832,7 @@ libinput_unref(struct libinput *libinput)
|
|||
|
||||
libinput_timer_subsys_destroy(libinput);
|
||||
libinput_drop_destroyed_sources(libinput);
|
||||
quirks_context_unref(libinput->quirks);
|
||||
close(libinput->epoll_fd);
|
||||
free(libinput);
|
||||
|
||||
|
|
|
|||
|
|
@ -337,6 +337,13 @@ libinput_path_add_device(struct libinput *libinput,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* We cannot do this during path_create_context because the log
|
||||
* handler isn't set up there but we really want to log to the right
|
||||
* place if the quirks run into parser errors. So we have to do it
|
||||
* on the first call to add_device.
|
||||
*/
|
||||
libinput_init_quirks(libinput);
|
||||
|
||||
udev_device = udev_device_from_devnode(libinput, udev, path);
|
||||
if (!udev_device) {
|
||||
log_bug_client(libinput, "Invalid path %s\n", path);
|
||||
|
|
|
|||
1494
src/quirks.c
Normal file
1494
src/quirks.c
Normal file
File diff suppressed because it is too large
Load diff
273
src/quirks.h
Normal file
273
src/quirks.h
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright © 2018 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
#include "libinput.h"
|
||||
|
||||
/**
|
||||
* Handle to the quirks context.
|
||||
*/
|
||||
struct quirks_context;
|
||||
|
||||
/**
|
||||
* Contains all quirks set for a single device.
|
||||
*/
|
||||
struct quirks;
|
||||
|
||||
struct quirk_dimensions {
|
||||
size_t x, y;
|
||||
};
|
||||
|
||||
struct quirk_range {
|
||||
int lower, upper;
|
||||
};
|
||||
|
||||
/**
|
||||
* Quirks known to libinput
|
||||
*/
|
||||
enum quirk {
|
||||
QUIRK_MODEL_ALPS_TOUCHPAD = 100,
|
||||
QUIRK_MODEL_APPLE_TOUCHPAD,
|
||||
QUIRK_MODEL_APPLE_MAGICMOUSE,
|
||||
QUIRK_MODEL_TABLET_NO_TILT,
|
||||
QUIRK_MODEL_APPLE_TOUCHPAD_ONEBUTTON,
|
||||
QUIRK_MODEL_TOUCHPAD_VISIBLE_MARKER,
|
||||
QUIRK_MODEL_CYBORG_RAT,
|
||||
QUIRK_MODEL_CHROMEBOOK,
|
||||
QUIRK_MODEL_HP6910_TOUCHPAD,
|
||||
QUIRK_MODEL_HP8510_TOUCHPAD,
|
||||
QUIRK_MODEL_HP_PAVILION_DM4_TOUCHPAD,
|
||||
QUIRK_MODEL_HP_STREAM11_TOUCHPAD,
|
||||
QUIRK_MODEL_HP_ZBOOK_STUDIO_G3,
|
||||
QUIRK_MODEL_TABLET_NO_PROXIMITY_OUT,
|
||||
QUIRK_MODEL_LENOVO_SCROLLPOINT,
|
||||
QUIRK_MODEL_LENOVO_X230,
|
||||
QUIRK_MODEL_LENOVO_T450_TOUCHPAD,
|
||||
QUIRK_MODEL_TABLET_MODE_NO_SUSPEND,
|
||||
QUIRK_MODEL_LENOVO_CARBON_X1_6TH,
|
||||
QUIRK_MODEL_TRACKBALL,
|
||||
QUIRK_MODEL_LOGITECH_MARBLE_MOUSE,
|
||||
QUIRK_MODEL_BOUNCING_KEYS,
|
||||
QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD,
|
||||
QUIRK_MODEL_SYSTEM76_BONOBO,
|
||||
QUIRK_MODEL_CLEVO_W740SU,
|
||||
QUIRK_MODEL_SYSTEM76_GALAGO,
|
||||
QUIRK_MODEL_SYSTEM76_KUDU,
|
||||
QUIRK_MODEL_WACOM_TOUCHPAD,
|
||||
QUIRK_MODEL_JUMPING_SEMI_MT,
|
||||
|
||||
|
||||
QUIRK_ATTR_SIZE_HINT = 300,
|
||||
QUIRK_ATTR_TOUCH_SIZE_RANGE,
|
||||
QUIRK_ATTR_PALM_SIZE_THRESHOLD,
|
||||
QUIRK_ATTR_LID_SWITCH_RELIABILITY,
|
||||
QUIRK_ATTR_KEYBOARD_INTEGRATION,
|
||||
QUIRK_ATTR_TPKBCOMBO_LAYOUT,
|
||||
QUIRK_ATTR_PRESSURE_RANGE,
|
||||
QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
|
||||
QUIRK_ATTR_RESOLUTION_HINT,
|
||||
QUIRK_ATTR_TRACKPOINT_RANGE,
|
||||
QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a printable name for the quirk. This name is for developer
|
||||
* tools, not user consumption. Do not display this in a GUI.
|
||||
*/
|
||||
const char*
|
||||
quirk_get_name(enum quirk which);
|
||||
|
||||
/**
|
||||
* Log priorities used if custom logging is enabled.
|
||||
*/
|
||||
enum quirks_log_priorities {
|
||||
QLOG_NOISE,
|
||||
QLOG_DEBUG = LIBINPUT_LOG_PRIORITY_DEBUG,
|
||||
QLOG_INFO = LIBINPUT_LOG_PRIORITY_INFO,
|
||||
QLOG_ERROR = LIBINPUT_LOG_PRIORITY_ERROR,
|
||||
QLOG_PARSER_ERROR,
|
||||
};
|
||||
|
||||
/**
|
||||
* Log type to be used for logging. Use the libinput logging to hook up a
|
||||
* libinput log handler. This will cause the quirks to reduce the noise and
|
||||
* only provide useful messages.
|
||||
*
|
||||
* QLOG_CUSTOM_LOG_PRIORITIES enables more fine-grained and verbose logging,
|
||||
* allowing debugging tools to be more useful.
|
||||
*/
|
||||
enum quirks_log_type {
|
||||
QLOG_LIBINPUT_LOGGING,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES,
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the quirks subsystem. This function must be called
|
||||
* before anything else.
|
||||
*
|
||||
* If log_type is QLOG_CUSTOM_LOG_PRIORITIES, the log handler is called with
|
||||
* the custom QLOG_* log priorities. Otherwise, the log handler only uses
|
||||
* the libinput log priorities.
|
||||
*
|
||||
* @param data_path The directory containing the various data files
|
||||
* @param override_file A file path containing custom overrides
|
||||
* @param log_handler The libinput log handler called for debugging output
|
||||
* @param libinput The libinput struct passed to the log handler
|
||||
*
|
||||
* @return an opaque handle to the context
|
||||
*/
|
||||
struct quirks_context *
|
||||
quirks_init_subsystem(const char *data_path,
|
||||
const char *override_file,
|
||||
libinput_log_handler log_handler,
|
||||
struct libinput *libinput,
|
||||
enum quirks_log_type log_type);
|
||||
|
||||
/**
|
||||
* Clean up after ourselves. This function must be called
|
||||
* as the last call to the quirks subsystem.
|
||||
*
|
||||
* All quirks returned to the caller in quirks_fetch_for_device() must be
|
||||
* unref'd before this call.
|
||||
*
|
||||
* @return Always NULL
|
||||
*/
|
||||
struct quirks_context *
|
||||
quirks_context_unref(struct quirks_context *ctx);
|
||||
|
||||
struct quirks_context *
|
||||
quirks_context_ref(struct quirks_context *ctx);
|
||||
|
||||
/**
|
||||
* Fetch the quirks for a given device. If no quirks are defined, this
|
||||
* function returns NULL.
|
||||
*
|
||||
* @return A new quirks struct, use quirks_unref() to release
|
||||
*/
|
||||
struct quirks *
|
||||
quirks_fetch_for_device(struct quirks_context *ctx,
|
||||
struct udev_device *device);
|
||||
|
||||
/**
|
||||
* Reduce the refcount by one. When the refcount reaches zero, the
|
||||
* associated struct is released.
|
||||
*
|
||||
* @return Always NULL
|
||||
*/
|
||||
struct quirks *
|
||||
quirks_unref(struct quirks *q);
|
||||
|
||||
/**
|
||||
* Returns true if the given quirk applies is in this quirk list.
|
||||
*/
|
||||
bool
|
||||
quirks_has_quirk(struct quirks *q, enum quirk which);
|
||||
|
||||
/**
|
||||
* Get the value of the given quirk, as unsigned integer.
|
||||
* This function will assert if the quirk type does not match the
|
||||
* requested type. If the quirk is not set for this device, val is
|
||||
* unchanged.
|
||||
*
|
||||
* @return true if the quirk value is valid, false otherwise.
|
||||
*/
|
||||
bool
|
||||
quirks_get_uint32(struct quirks *q,
|
||||
enum quirk which,
|
||||
uint32_t *val);
|
||||
|
||||
/**
|
||||
* Get the value of the given quirk, as signed integer.
|
||||
* This function will assert if the quirk type does not match the
|
||||
* requested type. If the quirk is not set for this device, val is
|
||||
* unchanged.
|
||||
*
|
||||
* @return true if the quirk value is valid, false otherwise.
|
||||
*/
|
||||
bool
|
||||
quirks_get_int32(struct quirks *q,
|
||||
enum quirk which,
|
||||
int32_t *val);
|
||||
|
||||
/**
|
||||
* Get the value of the given quirk, as string.
|
||||
* This function will assert if the quirk type does not match the
|
||||
* requested type. If the quirk is not set for this device, val is
|
||||
* unchanged.
|
||||
*
|
||||
* val is set to the string, do not modify or free it. The lifetime of the
|
||||
* returned string is bound to the lifetime of the quirk.
|
||||
*
|
||||
* @return true if the quirk value is valid, false otherwise.
|
||||
*/
|
||||
bool
|
||||
quirks_get_string(struct quirks *q,
|
||||
enum quirk which,
|
||||
char **val);
|
||||
|
||||
/**
|
||||
* Get the value of the given quirk, as bool.
|
||||
* This function will assert if the quirk type does not match the
|
||||
* requested type. If the quirk is not set for this device, val is
|
||||
* unchanged.
|
||||
*
|
||||
* @return true if the quirk value is valid, false otherwise.
|
||||
*/
|
||||
bool
|
||||
quirks_get_bool(struct quirks *q,
|
||||
enum quirk which,
|
||||
bool *val);
|
||||
|
||||
/**
|
||||
* Get the value of the given quirk, as dimension.
|
||||
* This function will assert if the quirk type does not match the
|
||||
* requested type. If the quirk is not set for this device, val is
|
||||
* unchanged.
|
||||
*
|
||||
* @return true if the quirk value is valid, false otherwise.
|
||||
*/
|
||||
bool
|
||||
quirks_get_dimensions(struct quirks *q,
|
||||
enum quirk which,
|
||||
struct quirk_dimensions *val);
|
||||
|
||||
/**
|
||||
* Get the value of the given quirk, as range.
|
||||
* This function will assert if the quirk type does not match the
|
||||
* requested type. If the quirk is not set for this device, val is
|
||||
* unchanged.
|
||||
*
|
||||
* @return true if the quirk value is valid, false otherwise.
|
||||
*/
|
||||
bool
|
||||
quirks_get_range(struct quirks *q,
|
||||
enum quirk which,
|
||||
struct quirk_range *val);
|
||||
|
|
@ -382,6 +382,13 @@ libinput_udev_assign_seat(struct libinput *libinput,
|
|||
{
|
||||
struct udev_input *input = (struct udev_input*)libinput;
|
||||
|
||||
/* We cannot do this during udev_create_context because the log
|
||||
* handler isn't set up there but we really want to log to the right
|
||||
* place if the quirks run into parser errors. So we have to do it
|
||||
* here since we can expect the log handler to be set up by now.
|
||||
*/
|
||||
libinput_init_quirks(libinput);
|
||||
|
||||
if (!seat_id)
|
||||
return -1;
|
||||
|
||||
|
|
|
|||
|
|
@ -103,15 +103,10 @@ static struct input_absinfo absinfo[] = {
|
|||
{ .value = -1 }
|
||||
};
|
||||
|
||||
static const char udev_rule[] =
|
||||
"ACTION==\"remove\", GOTO=\"touchpad_end\"\n"
|
||||
"KERNEL!=\"event*\", GOTO=\"touchpad_end\"\n"
|
||||
"ENV{ID_INPUT_TOUCHPAD}==\"\", GOTO=\"touchpad_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest AlpsPS/2 ALPS DualPoint TouchPad\","
|
||||
" ENV{LIBINPUT_MODEL_TOUCHPAD_VISIBLE_MARKER}=\"1\"\n"
|
||||
"\n"
|
||||
"LABEL=\"touchpad_end\"";
|
||||
static const char quirk_file[] =
|
||||
"[litest ALPS Touchpad]\n"
|
||||
"MatchName=litest AlpsPS/2 ALPS DualPoint TouchPad\n"
|
||||
"ModelTouchpadVisibleMarker=1\n";
|
||||
|
||||
TEST_DEVICE("alps-dualpoint",
|
||||
.type = LITEST_ALPS_DUALPOINT,
|
||||
|
|
@ -122,5 +117,5 @@ TEST_DEVICE("alps-dualpoint",
|
|||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_rule = udev_rule,
|
||||
.quirk_file = quirk_file,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -83,15 +83,10 @@ static struct input_absinfo absinfo[] = {
|
|||
{ .value = -1 }
|
||||
};
|
||||
|
||||
static const char udev_rule[] =
|
||||
"ACTION==\"remove\", GOTO=\"touchpad_end\"\n"
|
||||
"KERNEL!=\"event*\", GOTO=\"touchpad_end\"\n"
|
||||
"ENV{ID_INPUT_TOUCHPAD}==\"\", GOTO=\"touchpad_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest appletouch\","
|
||||
" ENV{LIBINPUT_MODEL_APPLE_TOUCHPAD_ONEBUTTON}=\"1\"\n"
|
||||
"\n"
|
||||
"LABEL=\"touchpad_end\"";
|
||||
static const char quirk_file[] =
|
||||
"[litest ALPS Touchpad]\n"
|
||||
"MatchName=litest appletouch\n"
|
||||
"ModelAppleTouchpadOneButton=1\n";
|
||||
|
||||
TEST_DEVICE("appletouch",
|
||||
.type = LITEST_APPLETOUCH,
|
||||
|
|
@ -102,5 +97,5 @@ TEST_DEVICE("appletouch",
|
|||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_rule = udev_rule,
|
||||
.quirk_file = quirk_file,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -47,11 +47,15 @@ static const char udev_rule[] =
|
|||
"KERNEL!=\"event*\", GOTO=\"switch_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest gpio-keys*\",\\\n"
|
||||
" ENV{ID_INPUT_SWITCH}=\"1\",\\\n"
|
||||
" ENV{LIBINPUT_ATTR_LID_SWITCH_RELIABILITY}=\"reliable\"\n"
|
||||
" ENV{ID_INPUT_SWITCH}=\"1\"\n"
|
||||
"\n"
|
||||
"LABEL=\"switch_end\"";
|
||||
|
||||
static const char quirk_file[] =
|
||||
"[litest gpio quirk]\n"
|
||||
"MatchName=litest gpio-keys\n"
|
||||
"AttrLidSwitchReliability=reliable\n";
|
||||
|
||||
TEST_DEVICE("gpio-keys",
|
||||
.type = LITEST_GPIO_KEYS,
|
||||
.features = LITEST_SWITCH,
|
||||
|
|
@ -63,4 +67,5 @@ TEST_DEVICE("gpio-keys",
|
|||
.absinfo = NULL,
|
||||
|
||||
.udev_rule = udev_rule,
|
||||
.quirk_file = quirk_file,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -88,15 +88,10 @@ static int events[] = {
|
|||
-1, -1,
|
||||
};
|
||||
|
||||
static const char udev_rule[] =
|
||||
"ACTION==\"remove\", GOTO=\"huion_end\"\n"
|
||||
"KERNEL!=\"event*\", GOTO=\"huion_end\"\n"
|
||||
"ENV{ID_INPUT_TABLET}==\"\", GOTO=\"huion_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest HUION PenTablet Pen\","
|
||||
" ENV{LIBINPUT_MODEL_TABLET_NO_PROXIMITY_OUT}=\"1\"\n"
|
||||
"\n"
|
||||
"LABEL=\"huion_end\"";
|
||||
static const char quirk_file[] =
|
||||
"[litest HUION tablet]\n"
|
||||
"MatchName=litest HUION PenTablet Pen\n"
|
||||
"ModelTabletNoProximityOut=1\n";
|
||||
|
||||
TEST_DEVICE("huion-tablet",
|
||||
.type = LITEST_HUION_TABLET,
|
||||
|
|
@ -107,5 +102,5 @@ TEST_DEVICE("huion-tablet",
|
|||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_rule = udev_rule,
|
||||
.quirk_file = quirk_file,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -43,11 +43,15 @@ static const char udev_rule[] =
|
|||
"KERNEL!=\"event*\", GOTO=\"switch_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest Lid Switch Surface3*\",\\\n"
|
||||
" ENV{ID_INPUT_SWITCH}=\"1\",\\\n"
|
||||
" ENV{LIBINPUT_ATTR_LID_SWITCH_RELIABILITY}=\"write_open\"\n"
|
||||
" ENV{ID_INPUT_SWITCH}=\"1\"\n"
|
||||
"\n"
|
||||
"LABEL=\"switch_end\"";
|
||||
|
||||
static const char quirk_file[] =
|
||||
"[litest Surface Lid]\n"
|
||||
"MatchName=litest Lid Switch Surface3\n"
|
||||
"AttrLidSwitchReliability=write_open\n";
|
||||
|
||||
TEST_DEVICE("lid-switch-surface3",
|
||||
.type = LITEST_LID_SWITCH_SURFACE3,
|
||||
.features = LITEST_SWITCH,
|
||||
|
|
@ -59,4 +63,5 @@ TEST_DEVICE("lid-switch-surface3",
|
|||
.absinfo = NULL,
|
||||
|
||||
.udev_rule = udev_rule,
|
||||
.quirk_file = quirk_file,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -42,11 +42,15 @@ static const char udev_rule[] =
|
|||
"KERNEL!=\"event*\", GOTO=\"switch_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest Lid Switch\",\\\n"
|
||||
" ENV{ID_INPUT_SWITCH}=\"1\",\\\n"
|
||||
" ENV{LIBINPUT_ATTR_LID_SWITCH_RELIABILITY}=\"reliable\"\n"
|
||||
" ENV{ID_INPUT_SWITCH}=\"1\"\n"
|
||||
"\n"
|
||||
"LABEL=\"switch_end\"";
|
||||
|
||||
static const char quirk_file[] =
|
||||
"[litest Lid Switch]\n"
|
||||
"MatchName=litest Lid Switch\n"
|
||||
"AttrLidSwitchReliability=reliable\n";
|
||||
|
||||
TEST_DEVICE("lid-switch",
|
||||
.type = LITEST_LID_SWITCH,
|
||||
.features = LITEST_SWITCH,
|
||||
|
|
@ -58,4 +62,5 @@ TEST_DEVICE("lid-switch",
|
|||
.absinfo = NULL,
|
||||
|
||||
.udev_rule = udev_rule,
|
||||
.quirk_file = quirk_file,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -79,15 +79,10 @@ static struct input_absinfo absinfo[] = {
|
|||
{ .value = -1 }
|
||||
};
|
||||
|
||||
static const char udev_rule[] =
|
||||
"ACTION==\"remove\", GOTO=\"touchpad_end\"\n"
|
||||
"KERNEL!=\"event*\", GOTO=\"touchpad_end\"\n"
|
||||
"ENV{ID_INPUT_TOUCHPAD}==\"\", GOTO=\"touchpad_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest DLL0704:01 06CB:76AD Touchpad\","
|
||||
" ENV{LIBINPUT_MODEL_TOUCHPAD_VISIBLE_MARKER}=\"1\"\n"
|
||||
"\n"
|
||||
"LABEL=\"touchpad_end\"";
|
||||
static const char quirk_file[] =
|
||||
"[litest Synaptics i2c Touchpad]\n"
|
||||
"MatchName=litest DLL0704:01 06CB:76AD Touchpad\n"
|
||||
"ModelTouchpadVisibleMarker=1\n";
|
||||
|
||||
TEST_DEVICE("synaptics-i2c",
|
||||
.type = LITEST_SYNAPTICS_I2C,
|
||||
|
|
@ -98,5 +93,5 @@ TEST_DEVICE("synaptics-i2c",
|
|||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_rule = udev_rule,
|
||||
.quirk_file = quirk_file,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -105,15 +105,10 @@ static struct input_absinfo absinfo[] = {
|
|||
{ .value = -1 }
|
||||
};
|
||||
|
||||
static const char udev_rule[] =
|
||||
"ACTION==\"remove\", GOTO=\"touchpad_end\"\n"
|
||||
"KERNEL!=\"event*\", GOTO=\"touchpad_end\"\n"
|
||||
"ENV{ID_INPUT_TOUCHPAD}==\"\", GOTO=\"touchpad_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest SynPS/2 Synaptics TouchPad X1C3rd\","
|
||||
" ENV{LIBINPUT_MODEL_LENOVO_T450_TOUCHPAD}=\"1\"\n"
|
||||
"\n"
|
||||
"LABEL=\"touchpad_end\"";
|
||||
static const char quirk_file[] =
|
||||
"[litest Synaptics X1 Carbon 3rd Touchpad]\n"
|
||||
"MatchName=litest SynPS/2 Synaptics TouchPad X1C3rd\n"
|
||||
"ModelLenovoT450Touchpad=1\n";
|
||||
|
||||
TEST_DEVICE("synaptics-carbon3rd",
|
||||
.type = LITEST_SYNAPTICS_TRACKPOINT_BUTTONS,
|
||||
|
|
@ -124,5 +119,5 @@ TEST_DEVICE("synaptics-carbon3rd",
|
|||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_rule = udev_rule,
|
||||
.quirk_file = quirk_file,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -220,15 +220,10 @@ static int events[] = {
|
|||
-1, -1,
|
||||
};
|
||||
|
||||
static const char udev_rule[] =
|
||||
"ACTION==\"remove\", GOTO=\"waltop_end\"\n"
|
||||
"KERNEL!=\"event*\", GOTO=\"waltop_end\"\n"
|
||||
"ENV{ID_INPUT_TABLET}==\"\", GOTO=\"waltop_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest WALTOP Batteryless Tablet*\",\\\n"
|
||||
" ENV{LIBINPUT_ATTR_SIZE_HINT}=\"200x200\"\n"
|
||||
"\n"
|
||||
"LABEL=\"waltop_end\"";
|
||||
static const char quirk_file[] =
|
||||
"[litest Waltop Tablet]\n"
|
||||
"MatchName=litest WALTOP Batteryless Tablet*\n"
|
||||
"AttrSizeHint=200x200\n";
|
||||
|
||||
TEST_DEVICE("waltop-tablet",
|
||||
.type = LITEST_WALTOP,
|
||||
|
|
@ -239,5 +234,5 @@ TEST_DEVICE("waltop-tablet",
|
|||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_rule = udev_rule,
|
||||
.quirk_file = quirk_file,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ struct litest_test_device {
|
|||
struct litest_device_interface *interface;
|
||||
|
||||
const char *udev_rule;
|
||||
const char *quirk_file;
|
||||
};
|
||||
|
||||
struct litest_device_interface {
|
||||
|
|
|
|||
129
test/litest.c
129
test/litest.c
|
|
@ -55,6 +55,7 @@
|
|||
#include "litest.h"
|
||||
#include "litest-int.h"
|
||||
#include "libinput-util.h"
|
||||
#include "quirks.h"
|
||||
|
||||
#include <linux/kd.h>
|
||||
|
||||
|
|
@ -76,6 +77,7 @@ static int verbose = 0;
|
|||
const char *filter_test = NULL;
|
||||
const char *filter_device = NULL;
|
||||
const char *filter_group = NULL;
|
||||
static struct quirks_context *quirks_context;
|
||||
|
||||
struct created_file {
|
||||
struct list link;
|
||||
|
|
@ -87,6 +89,7 @@ struct list created_files_list; /* list of all files to remove at the end of
|
|||
|
||||
static void litest_init_udev_rules(struct list *created_files_list);
|
||||
static void litest_remove_udev_rules(struct list *created_files_list);
|
||||
static char *litest_install_quirks(struct list *created_files_list);
|
||||
|
||||
/* defined for the litest selftest */
|
||||
#ifndef LITEST_DISABLE_BACKTRACE_LOGGING
|
||||
|
|
@ -741,6 +744,7 @@ litest_signal(int sig)
|
|||
list_for_each_safe(f, tmp, &created_files_list, link) {
|
||||
list_remove(&f->link);
|
||||
unlink(f->path);
|
||||
rmdir(f->path);
|
||||
/* in the sighandler, we can't free */
|
||||
}
|
||||
|
||||
|
|
@ -788,6 +792,19 @@ litest_free_test_list(struct list *tests)
|
|||
}
|
||||
}
|
||||
|
||||
LIBINPUT_ATTRIBUTE_PRINTF(3, 0)
|
||||
static inline void
|
||||
quirk_log_handler(struct libinput *unused,
|
||||
enum libinput_log_priority priority,
|
||||
const char *format,
|
||||
va_list args)
|
||||
{
|
||||
if (priority < LIBINPUT_LOG_PRIORITY_ERROR)
|
||||
return;
|
||||
|
||||
vfprintf(stderr, format, args);
|
||||
}
|
||||
|
||||
static int
|
||||
litest_run_suite(struct list *tests, int which, int max, int error_fd)
|
||||
{
|
||||
|
|
@ -803,6 +820,12 @@ litest_run_suite(struct list *tests, int which, int max, int error_fd)
|
|||
struct name *n, *tmp;
|
||||
struct list testnames;
|
||||
|
||||
quirks_context = quirks_init_subsystem(getenv("LIBINPUT_DATA_DIR"),
|
||||
NULL,
|
||||
quirk_log_handler,
|
||||
NULL,
|
||||
QLOG_LIBINPUT_LOGGING);
|
||||
|
||||
/* Check just takes the suite/test name pointers but doesn't strdup
|
||||
* them - we have to keep them around */
|
||||
list_init(&testnames);
|
||||
|
|
@ -887,6 +910,8 @@ out:
|
|||
free(n);
|
||||
}
|
||||
|
||||
quirks_context_unref(quirks_context);
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
|
|
@ -998,6 +1023,7 @@ litest_run(int argc, char **argv)
|
|||
{
|
||||
int failed = 0;
|
||||
int inhibit_lock_fd;
|
||||
char *quirks_dir;
|
||||
|
||||
list_init(&created_files_list);
|
||||
|
||||
|
|
@ -1011,6 +1037,10 @@ litest_run(int argc, char **argv)
|
|||
verbose = 1;
|
||||
|
||||
litest_init_udev_rules(&created_files_list);
|
||||
quirks_dir = litest_install_quirks(&created_files_list);
|
||||
|
||||
setenv("LIBINPUT_DATA_DIR", quirks_dir, 1);
|
||||
free(quirks_dir);
|
||||
|
||||
litest_setup_sighandler(SIGINT);
|
||||
|
||||
|
|
@ -1104,13 +1134,20 @@ litest_copy_file(const char *dest, const char *src, const char *header)
|
|||
{
|
||||
int in, out, length;
|
||||
struct created_file *file;
|
||||
int suffixlen;
|
||||
|
||||
file = zalloc(sizeof(*file));
|
||||
file->path = safe_strdup(dest);
|
||||
|
||||
suffixlen = file->path + strlen(file->path) - rindex(file->path, '.');
|
||||
out = mkstemps(file->path, suffixlen);
|
||||
if (strstr(dest, "XXXXXX")) {
|
||||
int suffixlen;
|
||||
|
||||
suffixlen = file->path +
|
||||
strlen(file->path) -
|
||||
rindex(file->path, '.');
|
||||
out = mkstemps(file->path, suffixlen);
|
||||
} else {
|
||||
out = open(file->path, O_CREAT|O_WRONLY);
|
||||
}
|
||||
if (out == -1)
|
||||
litest_abort_msg("Failed to write to file %s (%s)\n",
|
||||
file->path,
|
||||
|
|
@ -1169,6 +1206,86 @@ litest_install_model_quirks(struct list *created_files_list)
|
|||
list_insert(created_files_list, &file->link);
|
||||
}
|
||||
|
||||
static char *
|
||||
litest_init_device_quirk_file(const char *data_dir,
|
||||
struct litest_test_device *dev)
|
||||
{
|
||||
int fd;
|
||||
FILE *f;
|
||||
char path[PATH_MAX];
|
||||
static int count;
|
||||
|
||||
if (!dev->quirk_file)
|
||||
return NULL;
|
||||
|
||||
snprintf(path, sizeof(path),
|
||||
"%s/99-%03d-%s.quirks",
|
||||
data_dir,
|
||||
++count,
|
||||
dev->shortname);
|
||||
fd = open(path, O_CREAT|O_WRONLY, 0644);
|
||||
litest_assert_int_ne(fd, -1);
|
||||
f = fdopen(fd, "w");
|
||||
litest_assert_notnull(f);
|
||||
litest_assert_int_ge(fputs(dev->quirk_file, f), 0);
|
||||
fclose(f);
|
||||
|
||||
return safe_strdup(path);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
litest_install_quirks(struct list *created_files_list)
|
||||
{
|
||||
struct litest_test_device **dev = devices;
|
||||
struct created_file *file;
|
||||
char dirname[PATH_MAX] = "/run/litest-XXXXXX";
|
||||
char **quirks, **q;
|
||||
|
||||
litest_assert_notnull(mkdtemp(dirname));
|
||||
litest_assert_int_ne(chmod(dirname, 0755), -1);
|
||||
|
||||
quirks = strv_from_string(LIBINPUT_DATA_FILES, ":");
|
||||
litest_assert(quirks);
|
||||
|
||||
q = quirks;
|
||||
while (*q) {
|
||||
char *filename;
|
||||
char dest[PATH_MAX];
|
||||
char src[PATH_MAX];
|
||||
|
||||
litest_assert(strneq(*q, "data/", 5));
|
||||
filename = &(*q)[5];
|
||||
|
||||
snprintf(src, sizeof(src), "%s/%s", LIBINPUT_DATA_SRCDIR, filename);
|
||||
snprintf(dest, sizeof(dest), "%s/%s", dirname, filename);
|
||||
file = litest_copy_file(dest, src, NULL);
|
||||
list_append(created_files_list, &file->link);
|
||||
q++;
|
||||
}
|
||||
strv_free(quirks);
|
||||
|
||||
/* Now add the per-device special config files */
|
||||
|
||||
while (*dev) {
|
||||
char *path;
|
||||
|
||||
path = litest_init_device_quirk_file(dirname, *dev);
|
||||
if (path) {
|
||||
struct created_file *file = zalloc(sizeof(*file));
|
||||
file->path = path;
|
||||
list_insert(created_files_list, &file->link);
|
||||
}
|
||||
dev++;
|
||||
}
|
||||
|
||||
file = zalloc(sizeof *file);
|
||||
file->path = safe_strdup(dirname);
|
||||
list_append(created_files_list, &file->link);
|
||||
|
||||
return safe_strdup(dirname);
|
||||
}
|
||||
|
||||
static inline void
|
||||
mkdir_p(const char *dir)
|
||||
{
|
||||
|
|
@ -1212,6 +1329,7 @@ litest_remove_udev_rules(struct list *created_files_list)
|
|||
list_for_each_safe(f, tmp, created_files_list, link) {
|
||||
list_remove(&f->link);
|
||||
unlink(f->path);
|
||||
rmdir(f->path);
|
||||
free(f->path);
|
||||
free(f);
|
||||
}
|
||||
|
|
@ -1399,6 +1517,9 @@ litest_add_device_with_overrides(struct libinput *libinput,
|
|||
|
||||
d->libinput = libinput;
|
||||
d->libinput_device = libinput_path_add_device(d->libinput, path);
|
||||
d->quirks = quirks_fetch_for_device(quirks_context,
|
||||
libinput_device_get_udev_device(d->libinput_device));
|
||||
|
||||
litest_assert(d->libinput_device != NULL);
|
||||
libinput_device_ref(d->libinput_device);
|
||||
|
||||
|
|
@ -1522,6 +1643,8 @@ litest_delete_device(struct litest_device *d)
|
|||
|
||||
litest_assert_int_eq(d->skip_ev_syn, 0);
|
||||
|
||||
quirks_unref(d->quirks);
|
||||
|
||||
if (d->libinput_device) {
|
||||
libinput_path_remove_device(d->libinput_device);
|
||||
libinput_device_unref(d->libinput_device);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "libinput-util.h"
|
||||
#include "quirks.h"
|
||||
|
||||
struct test_device {
|
||||
const char *name;
|
||||
|
|
@ -345,6 +346,7 @@ struct litest_device {
|
|||
struct libevdev *evdev;
|
||||
struct libevdev_uinput *uinput;
|
||||
struct libinput *libinput;
|
||||
struct quirks *quirks;
|
||||
bool owns_context;
|
||||
struct libinput_device *libinput_device;
|
||||
struct litest_device_interface *interface;
|
||||
|
|
|
|||
|
|
@ -1141,87 +1141,6 @@ START_TEST(device_accelerometer)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_udev_tag_alps)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
struct udev_device *d;
|
||||
const char *prop;
|
||||
|
||||
d = libinput_device_get_udev_device(device);
|
||||
prop = udev_device_get_property_value(d,
|
||||
"LIBINPUT_MODEL_ALPS_TOUCHPAD");
|
||||
|
||||
if (strstr(libinput_device_get_name(device), "ALPS"))
|
||||
ck_assert_notnull(prop);
|
||||
else
|
||||
ck_assert(prop == NULL);
|
||||
|
||||
udev_device_unref(d);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_udev_tag_wacom)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
struct udev_device *d;
|
||||
const char *prop;
|
||||
|
||||
d = libinput_device_get_udev_device(device);
|
||||
prop = udev_device_get_property_value(d,
|
||||
"LIBINPUT_MODEL_WACOM_TOUCHPAD");
|
||||
|
||||
if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM)
|
||||
ck_assert_notnull(prop);
|
||||
else
|
||||
ck_assert(prop == NULL);
|
||||
|
||||
udev_device_unref(d);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_udev_tag_apple)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
struct udev_device *d;
|
||||
const char *prop;
|
||||
|
||||
d = libinput_device_get_udev_device(device);
|
||||
prop = udev_device_get_property_value(d,
|
||||
"LIBINPUT_MODEL_APPLE_TOUCHPAD");
|
||||
|
||||
if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_APPLE)
|
||||
ck_assert_notnull(prop);
|
||||
else
|
||||
ck_assert(prop == NULL);
|
||||
|
||||
udev_device_unref(d);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_udev_tag_synaptics_serial)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
struct udev_device *d;
|
||||
const char *prop;
|
||||
|
||||
d = libinput_device_get_udev_device(device);
|
||||
prop = udev_device_get_property_value(d,
|
||||
"LIBINPUT_MODEL_SYNAPTICS_SERIAL_TOUCHPAD");
|
||||
|
||||
if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_SYNAPTICS_SERIAL &&
|
||||
libevdev_get_id_product(dev->evdev) == PRODUCT_ID_SYNAPTICS_SERIAL)
|
||||
ck_assert_notnull(prop);
|
||||
else
|
||||
ck_assert(prop == NULL);
|
||||
|
||||
udev_device_unref(d);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_udev_tag_wacom_tablet)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -1627,10 +1546,6 @@ TEST_COLLECTION(device)
|
|||
litest_add("device:wheel", device_wheel_only, LITEST_WHEEL, LITEST_RELATIVE|LITEST_ABSOLUTE|LITEST_TABLET);
|
||||
litest_add_no_device("device:accelerometer", device_accelerometer);
|
||||
|
||||
litest_add("device:udev tags", device_udev_tag_alps, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("device:udev tags", device_udev_tag_wacom, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("device:udev tags", device_udev_tag_apple, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("device:udev tags", device_udev_tag_synaptics_serial, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("device:udev tags", device_udev_tag_wacom_tablet, LITEST_TABLET, LITEST_ANY);
|
||||
|
||||
litest_add_no_device("device:invalid rel events", device_nonpointer_rel);
|
||||
|
|
|
|||
179
test/test-misc.c
179
test/test-misc.c
|
|
@ -1198,6 +1198,118 @@ START_TEST(safe_atoi_base_8_test)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
struct atou_test {
|
||||
char *str;
|
||||
bool success;
|
||||
unsigned int val;
|
||||
};
|
||||
|
||||
START_TEST(safe_atou_test)
|
||||
{
|
||||
struct atou_test tests[] = {
|
||||
{ "10", true, 10 },
|
||||
{ "20", true, 20 },
|
||||
{ "-1", false, 0 },
|
||||
{ "2147483647", true, 2147483647 },
|
||||
{ "-2147483648", false, 0},
|
||||
{ "4294967295", true, 4294967295 },
|
||||
{ "0x0", false, 0 },
|
||||
{ "-10x10", false, 0 },
|
||||
{ "1x-99", false, 0 },
|
||||
{ "", false, 0 },
|
||||
{ "abd", false, 0 },
|
||||
{ "xabd", false, 0 },
|
||||
{ "0xaf", false, 0 },
|
||||
{ "0x0x", false, 0 },
|
||||
{ "x10", false, 0 },
|
||||
{ NULL, false, 0 }
|
||||
};
|
||||
unsigned int v;
|
||||
bool success;
|
||||
|
||||
for (int i = 0; tests[i].str != NULL; i++) {
|
||||
v = 0xad;
|
||||
success = safe_atou(tests[i].str, &v);
|
||||
ck_assert(success == tests[i].success);
|
||||
if (success)
|
||||
ck_assert_int_eq(v, tests[i].val);
|
||||
else
|
||||
ck_assert_int_eq(v, 0xad);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(safe_atou_base_16_test)
|
||||
{
|
||||
struct atou_test tests[] = {
|
||||
{ "10", true, 0x10 },
|
||||
{ "20", true, 0x20 },
|
||||
{ "-1", false, 0 },
|
||||
{ "0x10", true, 0x10 },
|
||||
{ "0xff", true, 0xff },
|
||||
{ "abc", true, 0xabc },
|
||||
{ "-10", false, 0 },
|
||||
{ "0x0", true, 0 },
|
||||
{ "0", true, 0 },
|
||||
{ "0x-99", false, 0 },
|
||||
{ "0xak", false, 0 },
|
||||
{ "0x", false, 0 },
|
||||
{ "x10", false, 0 },
|
||||
{ NULL, false, 0 }
|
||||
};
|
||||
|
||||
unsigned int v;
|
||||
bool success;
|
||||
|
||||
for (int i = 0; tests[i].str != NULL; i++) {
|
||||
v = 0xad;
|
||||
success = safe_atou_base(tests[i].str, &v, 16);
|
||||
ck_assert(success == tests[i].success);
|
||||
if (success)
|
||||
ck_assert_int_eq(v, tests[i].val);
|
||||
else
|
||||
ck_assert_int_eq(v, 0xad);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(safe_atou_base_8_test)
|
||||
{
|
||||
struct atou_test tests[] = {
|
||||
{ "7", true, 07 },
|
||||
{ "10", true, 010 },
|
||||
{ "20", true, 020 },
|
||||
{ "-1", false, 0 },
|
||||
{ "010", true, 010 },
|
||||
{ "0ff", false, 0 },
|
||||
{ "abc", false, 0},
|
||||
{ "0xabc", false, 0},
|
||||
{ "-10", false, 0 },
|
||||
{ "0", true, 0 },
|
||||
{ "00", true, 0 },
|
||||
{ "0x0", false, 0 },
|
||||
{ "0x-99", false, 0 },
|
||||
{ "0xak", false, 0 },
|
||||
{ "0x", false, 0 },
|
||||
{ "x10", false, 0 },
|
||||
{ NULL, false, 0 }
|
||||
};
|
||||
|
||||
unsigned int v;
|
||||
bool success;
|
||||
|
||||
for (int i = 0; tests[i].str != NULL; i++) {
|
||||
v = 0xad;
|
||||
success = safe_atou_base(tests[i].str, &v, 8);
|
||||
ck_assert(success == tests[i].success);
|
||||
if (success)
|
||||
ck_assert_int_eq(v, tests[i].val);
|
||||
else
|
||||
ck_assert_int_eq(v, 0xad);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
struct atod_test {
|
||||
char *str;
|
||||
bool success;
|
||||
|
|
@ -1583,6 +1695,67 @@ START_TEST(timer_flush)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(list_test_insert)
|
||||
{
|
||||
struct list_test {
|
||||
int val;
|
||||
struct list node;
|
||||
} tests[] = {
|
||||
{ .val = 1 },
|
||||
{ .val = 2 },
|
||||
{ .val = 3 },
|
||||
{ .val = 4 },
|
||||
};
|
||||
struct list_test *t;
|
||||
struct list head;
|
||||
int val;
|
||||
|
||||
list_init(&head);
|
||||
|
||||
ARRAY_FOR_EACH(tests, t) {
|
||||
list_insert(&head, &t->node);
|
||||
}
|
||||
|
||||
val = 4;
|
||||
list_for_each(t, &head, node) {
|
||||
ck_assert_int_eq(t->val, val);
|
||||
val--;
|
||||
}
|
||||
|
||||
ck_assert_int_eq(val, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(list_test_append)
|
||||
{
|
||||
struct list_test {
|
||||
int val;
|
||||
struct list node;
|
||||
} tests[] = {
|
||||
{ .val = 1 },
|
||||
{ .val = 2 },
|
||||
{ .val = 3 },
|
||||
{ .val = 4 },
|
||||
};
|
||||
struct list_test *t;
|
||||
struct list head;
|
||||
int val;
|
||||
|
||||
list_init(&head);
|
||||
|
||||
ARRAY_FOR_EACH(tests, t) {
|
||||
list_append(&head, &t->node);
|
||||
}
|
||||
|
||||
val = 1;
|
||||
list_for_each(t, &head, node) {
|
||||
ck_assert_int_eq(t->val, val);
|
||||
val++;
|
||||
}
|
||||
ck_assert_int_eq(val, 5);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
TEST_COLLECTION(misc)
|
||||
{
|
||||
litest_add_no_device("events:conversion", event_conversion_device_notify);
|
||||
|
|
@ -1617,6 +1790,9 @@ TEST_COLLECTION(misc)
|
|||
litest_add_no_device("misc:parser", safe_atoi_test);
|
||||
litest_add_no_device("misc:parser", safe_atoi_base_16_test);
|
||||
litest_add_no_device("misc:parser", safe_atoi_base_8_test);
|
||||
litest_add_no_device("misc:parser", safe_atou_test);
|
||||
litest_add_no_device("misc:parser", safe_atou_base_16_test);
|
||||
litest_add_no_device("misc:parser", safe_atou_base_8_test);
|
||||
litest_add_no_device("misc:parser", safe_atod_test);
|
||||
litest_add_no_device("misc:parser", strsplit_test);
|
||||
litest_add_no_device("misc:parser", kvsplit_double_test);
|
||||
|
|
@ -1626,4 +1802,7 @@ TEST_COLLECTION(misc)
|
|||
litest_add_no_device("misc:fd", fd_no_event_leak);
|
||||
|
||||
litest_add_no_device("misc:library_version", library_version);
|
||||
|
||||
litest_add_no_device("misc:list", list_test_insert);
|
||||
litest_add_no_device("misc:list", list_test_append);
|
||||
}
|
||||
|
|
|
|||
956
test/test-quirks.c
Normal file
956
test/test-quirks.c
Normal file
|
|
@ -0,0 +1,956 @@
|
|||
/*
|
||||
* Copyright © 2018 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <check.h>
|
||||
#include <libinput.h>
|
||||
|
||||
#include "libinput-util.h"
|
||||
#include "litest.h"
|
||||
#include "quirks.h"
|
||||
|
||||
static void
|
||||
log_handler(struct libinput *this_is_null,
|
||||
enum libinput_log_priority priority,
|
||||
const char *format,
|
||||
va_list args)
|
||||
{
|
||||
#if 0
|
||||
vprintf(format, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct data_dir {
|
||||
char *dirname;
|
||||
char *filename;
|
||||
};
|
||||
|
||||
static struct data_dir
|
||||
make_data_dir(const char *file_content)
|
||||
{
|
||||
struct data_dir dir = {0};
|
||||
char dirname[PATH_MAX] = "/run/litest-quirk-test-XXXXXX";
|
||||
char *filename;
|
||||
FILE *fp;
|
||||
int rc;
|
||||
|
||||
litest_assert_notnull(mkdtemp(dirname));
|
||||
dir.dirname = safe_strdup(dirname);
|
||||
|
||||
if (file_content) {
|
||||
rc = xasprintf(&filename, "%s/testfile.quirks", dirname);
|
||||
litest_assert_int_eq(rc, (int)(strlen(dirname) + 16));
|
||||
|
||||
fp = fopen(filename, "w+");
|
||||
rc = fputs(file_content, fp);
|
||||
fclose(fp);
|
||||
litest_assert_int_ge(rc, 0);
|
||||
dir.filename = filename;
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_data_dir(struct data_dir dd)
|
||||
{
|
||||
if (dd.filename) {
|
||||
unlink(dd.filename);
|
||||
free(dd.filename);
|
||||
}
|
||||
if (dd.dirname) {
|
||||
rmdir(dd.dirname);
|
||||
free(dd.dirname);
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(quirks_invalid_dir)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
|
||||
ctx = quirks_init_subsystem("/does-not-exist",
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_LIBINPUT_LOGGING);
|
||||
ck_assert(ctx == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_empty_dir)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
struct data_dir dd = make_data_dir(NULL);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_LIBINPUT_LOGGING);
|
||||
ck_assert(ctx == NULL);
|
||||
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_section_empty)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] = "[Empty Section]";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_section_double)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] = "[Section name]";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_section_missing_match)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"AttrSizeHint=10x10\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_section_missing_attr)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_section_match_after_attr)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"AttrSizeHint=10x10\n"
|
||||
"MatchName=mouse\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_section_duplicate_match)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"AttrSizeHint=10x10\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_section_duplicate_attr)
|
||||
{
|
||||
/* This shouldn't be allowed but the current parser
|
||||
is happy with it */
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"AttrSizeHint=10x10\n"
|
||||
"AttrSizeHint=10x10\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_error_section)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section Missing Bracket\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"AttrSizeHint=10x10\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_error_trailing_whitespace)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse \n"
|
||||
"AttrSizeHint=10x10\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_error_unknown_match)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"Matchblahblah=mouse\n"
|
||||
"AttrSizeHint=10x10\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_error_unknown_attr)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"Attrblahblah=10x10\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_error_unknown_model)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"Modelblahblah=1\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_error_model_not_one)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"ModelAppleTouchpad=true\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_comment_inline)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name] # some inline comment\n"
|
||||
"MatchUdevType=mouse\t # another inline comment\n"
|
||||
"ModelAppleTouchpad=1#\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_comment_empty)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"#\n"
|
||||
" #\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"ModelAppleTouchpad=1\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_bustype)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchBus=usb\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchBus=bluetooth\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchBus=i2c\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchBus=rmi\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchBus=ps2\n"
|
||||
"ModelAppleTouchpad=1\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_bustype_invalid)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchBustype=venga\n"
|
||||
"ModelAppleTouchpad=1\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_vendor)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchVendor=0x0000\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchVendor=0x0001\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchVendor=0x2343\n"
|
||||
"ModelAppleTouchpad=1\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_vendor_invalid)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char *quirks_file[] = {
|
||||
"[Section name]\n"
|
||||
"MatchVendor=-1\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchVendor=abc\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchVendor=0xFFFFF\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchVendor=123\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
};
|
||||
const char **qf;
|
||||
|
||||
ARRAY_FOR_EACH(quirks_file, qf) {
|
||||
struct data_dir dd = make_data_dir(*qf);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_product)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchProduct=0x0000\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchProduct=0x0001\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchProduct=0x2343\n"
|
||||
"ModelAppleTouchpad=1\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_product_invalid)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char *quirks_file[] = {
|
||||
"[Section name]\n"
|
||||
"MatchProduct=-1\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchProduct=abc\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchProduct=0xFFFFF\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchProduct=123\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
};
|
||||
const char **qf;
|
||||
|
||||
ARRAY_FOR_EACH(quirks_file, qf) {
|
||||
struct data_dir dd = make_data_dir(*qf);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_name)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchName=1235\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchName=abc\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchName=*foo\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchName=foo*\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchName=foo[]\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchName=*foo*\n"
|
||||
"ModelAppleTouchpad=1\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_name_invalid)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char *quirks_file[] = {
|
||||
"[Section name]\n"
|
||||
"MatchName=\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
};
|
||||
const char **qf;
|
||||
|
||||
ARRAY_FOR_EACH(quirks_file, qf) {
|
||||
struct data_dir dd = make_data_dir(*qf);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_udev)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=touchpad\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=pointingstick\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=tablet\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=tablet-pad\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=keyboard\n"
|
||||
"ModelAppleTouchpad=1\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_udev_invalid)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char *quirks_file[] = {
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=blah\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=123\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
};
|
||||
const char **qf;
|
||||
|
||||
ARRAY_FOR_EACH(quirks_file, qf) {
|
||||
struct data_dir dd = make_data_dir(*qf);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_dmi)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchDMIModalias=dmi:*\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchDMIModalias=dmi:*svn*pn*:\n"
|
||||
"ModelAppleTouchpad=1\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_dmi_invalid)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char *quirks_file[] = {
|
||||
"[Section name]\n"
|
||||
"MatchDMIModalias=\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchDMIModalias=*pn*\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchDMIModalias=dmi*pn*\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
"[Section name]\n"
|
||||
"MatchDMIModalias=foo\n"
|
||||
"ModelAppleTouchpad=1\n",
|
||||
};
|
||||
const char **qf;
|
||||
|
||||
ARRAY_FOR_EACH(quirks_file, qf) {
|
||||
struct data_dir dd = make_data_dir(*qf);
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert(ctx == NULL);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_model_one)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct udev_device *ud = libinput_device_get_udev_device(dev->libinput_device);
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"ModelAppleTouchpad=1\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
struct quirks *q;
|
||||
bool isset;
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
|
||||
q = quirks_fetch_for_device(ctx, ud);
|
||||
ck_assert_notnull(q);
|
||||
|
||||
ck_assert(quirks_get_bool(q, QUIRK_MODEL_APPLE_TOUCHPAD, &isset));
|
||||
ck_assert(isset == true);
|
||||
|
||||
quirks_unref(q);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_model_zero)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct udev_device *ud = libinput_device_get_udev_device(dev->libinput_device);
|
||||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchUdevType=mouse\n"
|
||||
"ModelAppleTouchpad=0\n";
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
struct quirks *q;
|
||||
bool isset;
|
||||
|
||||
ctx = quirks_init_subsystem(dd.dirname,
|
||||
NULL,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
ck_assert_notnull(ctx);
|
||||
|
||||
q = quirks_fetch_for_device(ctx, ud);
|
||||
ck_assert_notnull(q);
|
||||
|
||||
ck_assert(quirks_get_bool(q, QUIRK_MODEL_APPLE_TOUCHPAD, &isset));
|
||||
ck_assert(isset == false);
|
||||
|
||||
quirks_unref(q);
|
||||
quirks_context_unref(ctx);
|
||||
cleanup_data_dir(dd);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_model_alps)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
struct quirks *q;
|
||||
bool exists, value;
|
||||
|
||||
q = dev->quirks;
|
||||
exists = quirks_get_bool(q, QUIRK_MODEL_ALPS_TOUCHPAD, &value);
|
||||
|
||||
if (strstr(libinput_device_get_name(device), "ALPS")) {
|
||||
ck_assert(exists);
|
||||
ck_assert(value);
|
||||
} else {
|
||||
ck_assert(!exists);
|
||||
ck_assert(!value);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_model_wacom)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct quirks *q;
|
||||
bool exists, value;
|
||||
|
||||
q = dev->quirks;
|
||||
exists = quirks_get_bool(q, QUIRK_MODEL_WACOM_TOUCHPAD, &value);
|
||||
|
||||
if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM) {
|
||||
ck_assert(exists);
|
||||
ck_assert(value);
|
||||
} else {
|
||||
ck_assert(!exists);
|
||||
ck_assert(!value);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_model_apple)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct quirks *q;
|
||||
bool exists, value;
|
||||
|
||||
q = dev->quirks;
|
||||
exists = quirks_get_bool(q, QUIRK_MODEL_APPLE_TOUCHPAD, &value);
|
||||
|
||||
if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_APPLE) {
|
||||
ck_assert(exists);
|
||||
ck_assert(value);
|
||||
} else {
|
||||
ck_assert(!exists);
|
||||
ck_assert(!value);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_model_synaptics_serial)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct quirks *q;
|
||||
bool exists, value;
|
||||
|
||||
q = dev->quirks;
|
||||
exists = quirks_get_bool(q, QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD, &value);
|
||||
|
||||
if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_SYNAPTICS_SERIAL &&
|
||||
libevdev_get_id_product(dev->evdev) == PRODUCT_ID_SYNAPTICS_SERIAL) {
|
||||
ck_assert(exists);
|
||||
ck_assert(value);
|
||||
} else {
|
||||
ck_assert(!exists);
|
||||
ck_assert(!value);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
TEST_COLLECTION(quirks)
|
||||
{
|
||||
litest_add_for_device("quirks:datadir", quirks_invalid_dir, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:datadir", quirks_empty_dir, LITEST_MOUSE);
|
||||
|
||||
litest_add_for_device("quirks:structure", quirks_section_empty, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:structure", quirks_section_double, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:structure", quirks_section_missing_match, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:structure", quirks_section_missing_attr, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:structure", quirks_section_match_after_attr, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:structure", quirks_section_duplicate_match, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:structure", quirks_section_duplicate_attr, LITEST_MOUSE);
|
||||
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_error_section, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_error_trailing_whitespace, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_error_unknown_match, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_error_unknown_attr, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_error_unknown_model, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_error_model_not_one, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_comment_inline, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_comment_empty, LITEST_MOUSE);
|
||||
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_bustype, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_bustype_invalid, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_vendor, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_vendor_invalid, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_product, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_product_invalid, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_name, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_name_invalid, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_udev, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_udev_invalid, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_dmi, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:parsing", quirks_parse_dmi_invalid, LITEST_MOUSE);
|
||||
|
||||
litest_add_for_device("quirks:model", quirks_model_one, LITEST_MOUSE);
|
||||
litest_add_for_device("quirks:model", quirks_model_zero, LITEST_MOUSE);
|
||||
|
||||
litest_add("quirks:devices", quirks_model_alps, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("quirks:devices", quirks_model_wacom, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("quirks:devices", quirks_model_apple, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("quirks:devices", quirks_model_synaptics_serial, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
}
|
||||
|
|
@ -143,16 +143,15 @@ END_TEST
|
|||
static bool
|
||||
lid_switch_is_reliable(struct litest_device *dev)
|
||||
{
|
||||
struct udev_device *udev_device;
|
||||
const char *prop;
|
||||
char *prop;
|
||||
bool is_reliable = false;
|
||||
|
||||
udev_device = libinput_device_get_udev_device(dev->libinput_device);
|
||||
prop = udev_device_get_property_value(udev_device,
|
||||
"LIBINPUT_ATTR_LID_SWITCH_RELIABILITY");
|
||||
if (quirks_get_string(dev->quirks,
|
||||
QUIRK_ATTR_LID_SWITCH_RELIABILITY,
|
||||
&prop)) {
|
||||
is_reliable = streq(prop, "reliable");
|
||||
}
|
||||
|
||||
is_reliable = prop && streq(prop, "reliable");
|
||||
udev_device_unref(udev_device);
|
||||
|
||||
return is_reliable;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,19 +293,13 @@ END_TEST
|
|||
static inline bool
|
||||
tablet_has_proxout_quirk(struct litest_device *dev)
|
||||
{
|
||||
struct udev_device *udev_device;
|
||||
bool has_quirk;
|
||||
bool is_set = false;
|
||||
if (!quirks_get_bool(dev->quirks,
|
||||
QUIRK_MODEL_TABLET_NO_PROXIMITY_OUT,
|
||||
&is_set))
|
||||
return false;
|
||||
|
||||
udev_device = libinput_device_get_udev_device(dev->libinput_device);
|
||||
|
||||
has_quirk = !!udev_device_get_property_value(udev_device,
|
||||
"LIBINPUT_MODEL_TABLET_NO_PROXIMITY_OUT");
|
||||
if (!has_quirk)
|
||||
has_quirk = !libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_PEN);
|
||||
|
||||
udev_device_unref(udev_device);
|
||||
|
||||
return has_quirk;
|
||||
return is_set;
|
||||
}
|
||||
|
||||
START_TEST(tip_up_prox_out)
|
||||
|
|
|
|||
261
tools/libinput-list-quirks.c
Normal file
261
tools/libinput-list-quirks.c
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* Copyright © 2018 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "libinput-util.h"
|
||||
#include "quirks.h"
|
||||
|
||||
static bool verbose = false;
|
||||
|
||||
static void
|
||||
log_handler(struct libinput *this_is_null,
|
||||
enum libinput_log_priority priority,
|
||||
const char *format,
|
||||
va_list args)
|
||||
{
|
||||
FILE *out = stdout;
|
||||
enum quirks_log_priorities p = priority;
|
||||
char buf[256] = {0};
|
||||
const char *prefix = "";
|
||||
|
||||
switch (p) {
|
||||
case QLOG_NOISE:
|
||||
case QLOG_DEBUG:
|
||||
if (!verbose)
|
||||
return;
|
||||
prefix = "quirks debug";
|
||||
break;
|
||||
case QLOG_INFO:
|
||||
prefix = "quirks info";
|
||||
break;
|
||||
case QLOG_ERROR:
|
||||
out = stderr;
|
||||
prefix = "quirks error";
|
||||
break;
|
||||
case QLOG_PARSER_ERROR:
|
||||
out = stderr;
|
||||
prefix = "quirks parser error";
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s: %s", prefix, format);
|
||||
vfprintf(out, buf, args);
|
||||
}
|
||||
|
||||
static void
|
||||
list_device_quirks(struct quirks_context *ctx, struct udev_device *device)
|
||||
{
|
||||
struct quirks *quirks;
|
||||
|
||||
quirks = quirks_fetch_for_device(ctx, device);
|
||||
if (!quirks) {
|
||||
printf("Device has no quirks defined\n");
|
||||
} else {
|
||||
enum quirk qlist[] = {
|
||||
QUIRK_MODEL_ALPS_TOUCHPAD,
|
||||
QUIRK_MODEL_APPLE_TOUCHPAD,
|
||||
QUIRK_MODEL_APPLE_MAGICMOUSE,
|
||||
QUIRK_MODEL_TABLET_NO_TILT,
|
||||
QUIRK_MODEL_APPLE_TOUCHPAD_ONEBUTTON,
|
||||
QUIRK_MODEL_TOUCHPAD_VISIBLE_MARKER,
|
||||
QUIRK_MODEL_CYBORG_RAT,
|
||||
QUIRK_MODEL_CHROMEBOOK,
|
||||
QUIRK_MODEL_HP6910_TOUCHPAD,
|
||||
QUIRK_MODEL_HP8510_TOUCHPAD,
|
||||
QUIRK_MODEL_HP_PAVILION_DM4_TOUCHPAD,
|
||||
QUIRK_MODEL_HP_STREAM11_TOUCHPAD,
|
||||
QUIRK_MODEL_HP_ZBOOK_STUDIO_G3,
|
||||
QUIRK_MODEL_TABLET_NO_PROXIMITY_OUT,
|
||||
QUIRK_MODEL_LENOVO_SCROLLPOINT,
|
||||
QUIRK_MODEL_LENOVO_X230,
|
||||
QUIRK_MODEL_LENOVO_T450_TOUCHPAD,
|
||||
QUIRK_MODEL_TABLET_MODE_NO_SUSPEND,
|
||||
QUIRK_MODEL_LENOVO_CARBON_X1_6TH,
|
||||
QUIRK_MODEL_TRACKBALL,
|
||||
QUIRK_MODEL_LOGITECH_MARBLE_MOUSE,
|
||||
QUIRK_MODEL_BOUNCING_KEYS,
|
||||
QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD,
|
||||
QUIRK_MODEL_SYSTEM76_BONOBO,
|
||||
QUIRK_MODEL_CLEVO_W740SU,
|
||||
QUIRK_MODEL_SYSTEM76_GALAGO,
|
||||
QUIRK_MODEL_SYSTEM76_KUDU,
|
||||
QUIRK_MODEL_WACOM_TOUCHPAD,
|
||||
|
||||
|
||||
QUIRK_ATTR_SIZE_HINT,
|
||||
QUIRK_ATTR_TOUCH_SIZE_RANGE,
|
||||
QUIRK_ATTR_PALM_SIZE_THRESHOLD,
|
||||
QUIRK_ATTR_LID_SWITCH_RELIABILITY,
|
||||
QUIRK_ATTR_KEYBOARD_INTEGRATION,
|
||||
QUIRK_ATTR_TPKBCOMBO_LAYOUT,
|
||||
QUIRK_ATTR_PRESSURE_RANGE,
|
||||
QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
|
||||
QUIRK_ATTR_RESOLUTION_HINT,
|
||||
QUIRK_ATTR_TRACKPOINT_RANGE,
|
||||
};
|
||||
enum quirk *q;
|
||||
|
||||
ARRAY_FOR_EACH(qlist, q) {
|
||||
if (!quirks_has_quirk(quirks, *q))
|
||||
continue;
|
||||
|
||||
printf("%s\n", quirk_get_name(*q));
|
||||
}
|
||||
}
|
||||
|
||||
quirks_unref(quirks);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
printf("Usage:\n"
|
||||
" %s [--data-dir /path/to/data/dir] /dev/input/event0\n"
|
||||
" Print the quirks for the given device\n"
|
||||
"\n",
|
||||
program_invocation_short_name);
|
||||
printf(" %s [--data-dir /path/to/data/dir] --validate-only\n"
|
||||
" Validate the database\n",
|
||||
program_invocation_short_name);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct udev *udev = NULL;
|
||||
struct udev_device *device = NULL;
|
||||
const char *path;
|
||||
const char *data_path = NULL,
|
||||
*override_file = NULL;
|
||||
int rc = 1;
|
||||
struct quirks_context *quirks;
|
||||
bool validate = false;
|
||||
|
||||
while (1) {
|
||||
int c;
|
||||
int option_index = 0;
|
||||
enum {
|
||||
OPT_VERBOSE,
|
||||
OPT_DATADIR,
|
||||
OPT_VALIDATE,
|
||||
};
|
||||
static struct option opts[] = {
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ "verbose", no_argument, 0, OPT_VERBOSE },
|
||||
{ "data-dir", required_argument, 0, OPT_DATADIR },
|
||||
{ "validate-only", no_argument, 0, OPT_VALIDATE },
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "h", opts, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch(c) {
|
||||
case '?':
|
||||
exit(1);
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
exit(0);
|
||||
break;
|
||||
case OPT_VERBOSE:
|
||||
verbose = true;
|
||||
break;
|
||||
case OPT_DATADIR:
|
||||
data_path = optarg;
|
||||
break;
|
||||
case OPT_VALIDATE:
|
||||
validate = true;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc && !validate) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Overriding the data dir means no custom override file */
|
||||
if (!data_path) {
|
||||
data_path = LIBINPUT_DATA_DIR;
|
||||
override_file = LIBINPUT_DATA_OVERRIDE_FILE;
|
||||
}
|
||||
|
||||
quirks = quirks_init_subsystem(data_path,
|
||||
override_file,
|
||||
log_handler,
|
||||
NULL,
|
||||
QLOG_CUSTOM_LOG_PRIORITIES);
|
||||
if (!quirks) {
|
||||
fprintf(stderr,
|
||||
"Failed to initialize the device quirks. "
|
||||
"Please see the above errors "
|
||||
"and/or re-run with --verbose for more details\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (validate) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
udev = udev_new();
|
||||
path = argv[optind];
|
||||
if (strneq(path, "/sys/", 5)) {
|
||||
device = udev_device_new_from_syspath(udev, path);
|
||||
} else {
|
||||
struct stat st;
|
||||
if (stat(path, &st) < 0) {
|
||||
fprintf(stderr, "Error: %s: %m\n", path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
|
||||
}
|
||||
if (device) {
|
||||
list_device_quirks(quirks, device);
|
||||
rc = 0;
|
||||
} else {
|
||||
usage();
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
udev_device_unref(device);
|
||||
out:
|
||||
udev_unref(udev);
|
||||
|
||||
quirks_context_unref(quirks);
|
||||
|
||||
return rc;
|
||||
}
|
||||
36
tools/libinput-list-quirks.man
Normal file
36
tools/libinput-list-quirks.man
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
.TH libinput-list-quirks "1" "" "libinput @LIBINPUT_VERSION@" "libinput Manual"
|
||||
.SH NAME
|
||||
libinput\-list\-quirks \- quirk debug helper for libinput
|
||||
.SH SYNOPSIS
|
||||
.B libinput list\-quirks [\-\-data\-dir /path/to/dir] [\-\-verbose\fB] \fI/dev/input/event0\fB
|
||||
.br
|
||||
.B libinput list\-quirks [\-\-data\-dir /path/to/dir] [\-\-verbose\fB] \-\-validate\-only
|
||||
.br
|
||||
.B libinput list\-quirks [\-\-help]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The
|
||||
.B "libinput list\-quirks"
|
||||
tool parses the quirks file in \fIdata\-dir\fR and prints all quirks applied
|
||||
to the given device.
|
||||
.PP
|
||||
This is a debugging tool only, its output and behavior may change at any
|
||||
time. Do not rely on the output.
|
||||
.SH OPTIONS
|
||||
.TP 8
|
||||
.B \-\-data\-dir \fI/path/to/dir\fR
|
||||
Use the given directory as data directory for quirks files.
|
||||
.TP 8
|
||||
.B \-\-help
|
||||
Print help
|
||||
.TP 8
|
||||
.B \-\-validate\-only
|
||||
Only validate that the quirks files can be parsed. When this option is
|
||||
given, no device file should be supplied.
|
||||
.TP 8
|
||||
.B \-\-verbose
|
||||
Use verbose output, useful for debugging.
|
||||
.SH LIBINPUT
|
||||
Part of the
|
||||
.B libinput(1)
|
||||
suite
|
||||
Loading…
Add table
Reference in a new issue