===== Synaptics Touchpad ===== ===== Introduction ===== The Synaptics Touchpad is a pointing device found on many laptops and supported since %%FreeBSD%% 8. By default, it is recognized and configured as a 3-buttons mouse. Additional features can be enabled with the ''%%hw.psm.synaptics_support%%'' sysctl tunable. Also check out [[https://docs.freebsd.org/en/books/faq/#x-and-synaptic|FreeBSD FAQ: My laptop has a Synaptics Touchpad. Can I use it in X?]] ===== Features ===== * Improved movement smoothing. It's comparable to the Microsoft Windows driver from Synaptics, except when the finger reaches touchpad borders where the movement becomes chaotic. * Tap detection with one (left click), two (right click), or three (middle click) finger tap support. * Tap-hold detection with one, two, or three fingers. * Virtual scrolling. For now, an area must be dedicated to virtual scrolling; typically, one on the right (vertical scrolling) and one at the bottom (horizontal scrolling). Also, a patch must be applied to xf86-input-mouse to handle horizontal scrolling from sysmouse. Later, virtual scrolling with two fingers will be re-added, as found on Apple %%MacBook%%. ===== Setup ===== To enable psm(4) Synaptics support, add the following line to ''%%/boot/loader.conf%%'' hw.psm.synaptics_support="1" Enable moused(8). Add the following to ''%%/etc/rc.conf%%'' moused_enable="YES" To use it within X.Org, disable the X.Org-specific Synaptics driver, and configure a sysmouse mouse. Here's an example section for ''%%/etc/X11/xorg.conf%%'' Section "InputDevice" Identifier "Mouse0" Driver "mouse" Option "Protocol" "auto" Option "Device" "/dev/sysmouse" Option "ZAxisMapping" "4 5 6 7" EndSection Horizontal scrolling is disabled by default. To enable it, add the following to ''%%/etc/sysctl.conf%%'' hw.psm.synaptics.vscroll_hor_area=1300 ===== Touchpad Configuration ===== ==== Palm Detection ==== === Finger Pressure === hw.psm.synaptics.min_pressure: 16 hw.psm.synaptics.max_pressure: 220 If the pressure is less than ''%%min_pressure%%'' or above ''%%max_pressure%%'', the packet is ignored but the current action isn't terminated. The pressure is comprised between 0 and 255. Here are some meaningful values, as stated by Synaptics specifications: * z = 0: no finger contact * z = 10: finger hovering near the pad * z = 30: very light finger contact * z = 80: normal finger contact * z = 110: very heavy finger contact * z = 200: finger lying flat on pad surface * z = 255: maximum reportable Z === Finger Width === hw.psm.synaptics.max_width: 10 If the finger width is above ''%%max_width%%'', the packet is ignored but the current action isn't terminated. The width is comprised between 4 and 15. Here are some meningful values, as stated by Synaptics specifications: * w = 4-7: finger of normal width (capPalmDetect needed) * w = 8-14: very wide finger or palm (capPalmDetect needed) * w = 15: maximum reportable width (capPalmDetect needed ==== Movement Smoothing ==== For movement smoothing, we use a weighted average then a division where both the weight and the divisor vary, depending on the movement speed. See "How it works". hw.psm.synaptics.weight_current: 3 hw.psm.synaptics.weight_previous: 6 hw.psm.synaptics.weight_previous_na: 20 hw.psm.synaptics.weight_len_squared: 2000 ''%%weight_current%%'' and ''%%weight_previous%%'' define the range of weights to use when calculating the average. ''%%weight_previous_na%%'' is used instead of ''%%weight_previous%%'' when the finger is inside the noisy area (see "Touchpad borders"). TODO: explain ''%%weight_len_squared%%''. hw.psm.synaptics.div_min: 9 hw.psm.synaptics.div_max: 17 hw.psm.synaptics.div_max_na: 30 hw.psm.synaptics.div_len: 100 ''%%div_min%%'' and ''%%div_max%%'' define the range of divisors to when calculating the final delta for x & y. ''%%div_max_na%%'' is used instead of ''%%div_max%%'' when the finger is inside the noisy area (see "Touchpad borders"). TODO: explain ''%%div_len%%''. hw.psm.synaptics.multiplicator: 10000 This multiplicator is used during averages and divisions to increase the precision. === How Movement Smoothing Works === The smoothing is based on a weighted average: average = (weight_current * delta + weight_previous * average) / (weight_current + weight_preivous) where : * ''%%average%%'' is the previous average, which is kept between each packet. * ''%%delta%%'' is the relative movement. * ''%%weight_current%%'' and ''%%weight_previous%%'' are configurable weights. This average is calculated for each axis (x & y) separately. The problem with a simple weighted average as above is that the user has to choose between a smooth but laggy movement (''%%weight_previous%%'' greater then ''%%weight_current%%'') or a sharp but imprecise movement at slow speed (''%%weight_previous%%'' smaller or equal to ''%%weight_current%%''). The idea is then to change ''%%weight_previous%%'' based on the last packets: * If the movement is slow, we keep ''%%weight_previous%%'' at its original value. * If the movement is fast, ''%%weight_previous%%'' decreases and may reach 0 for the fastest movements. Internaly, the driver keeps the last 10 packets. Here is the simplified algorithm: dx = abs(new_x - older_x) + 1; /* +1: to avoid a division by zero below. */ dy = abs(new_y - older_y) + 1; /* "len" is really the length squared. */ len = (dx * dx) + (dy * dy); /* "sysctl_weight_len_squared" is the length squared at which the * "weight_previous" will start to decrease. */ weight_previous = sysctl_weight_len_squared * weight_previous / len; weight_previous = imin(weight_previous, sysctl_weight_previous); The driver will do almost the same with the divisor to calculate the acceleration. The rest of the division is also kept between each packet; otherwise, with slow movements, the pointer doesn't reproduce well what the finger is doing. ==== Touchpad Borders (Margins) ==== Touchpad edges (borders) can generate a lot of noise in reported coordinates. There are two sets of sysctl tunables that control this area: hw.psm.synaptics.margin_top: 200 hw.psm.synaptics.margin_right: 200 hw.psm.synaptics.margin_bottom: 200 hw.psm.synaptics.margin_left: 200 These margins act as a high-pass filter: for instance, the point [50; 170] will be reported as [200;200]. hw.psm.synaptics.na_top: 1783 hw.psm.synaptics.na_right: 563 hw.psm.synaptics.na_bottom: 1408 hw.psm.synaptics.na_left: 1600 ''%%na%%'' stands for noisy area. Movements inside these larger margins will be smoothed using different max weight and divisor. See "Movement Smoothing". ==== Points History ==== hw.psm.synaptics.window_min: 4 hw.psm.synaptics.window_max: 10 ''%%window_min%%'' indicates the minimum number of packets to receive before an action is considered to be real and wanted. ''%%window_max%%'' is the maximum number of packets to use in calculations. ==== Tap and Tap-hold ==== hw.psm.synaptics.tap_max_delta: 80 hw.psm.synaptics.tap_min_queue: 2 ''%%tap_max_delta%%'' is the maximum delta between points to treat the action as a tap. This is to prevent any unwanted click. ''%%tap_min_queue%%'' is the minimum number of packets needed to consider a tap. hw.psm.synaptics.taphold_timeout: 125000 ''%%taphold_timeout%%'' is the time (in microseconds) between two taps to consider a tap-hols action. ==== Virtual Scrolling ==== hw.psm.synaptics.vscroll_hor_area: 1300 hw.psm.synaptics.vscroll_ver_area: -600 hw.psm.synaptics.vscroll_min_delta: 50 hw.psm.synaptics.vscroll_div_min: 100 hw.psm.synaptics.vscroll_div_max: 150 An area must be dedicated to virtual scrolling for now. This area is defined by ''%%vscroll_hor_area%%'' (positive for an area at the bottom, negative for an area at the top) for horizontal scrolling and ''%%vscroll_ver_area%%'' (positive for an area on the left, negative for an area on the right) for vertical scrolling. ''%%vscroll_min_delta%%'' is the minimum delta between points to consider a scrolling action. This is to prevent unwanted scrolling when tapping for instance. ''%%vscroll_div_min%%'' and ''%%vscroll_div_max%%'' are the divisors used instead of ''%%div_min%%'' and ''%%div_max%%'' respectively. ===== Toggling Synaptics Touchpad with devd ===== Although touchpads can support palm detection, it is sometimes desirable to disable them if a USB mouse is plugged in. These instructions assume a USB wired or wireless mouse. For a mouse that connects via Bluetooth, you will also need to identify your mouse ''%%device-name%%''. ==== Setup ==== We will be triggering a script from devd in order to toggle synaptics. Create a new script in /usr/local/bin named "synaptics-hotplug". In this script, paste the following: #!/bin/sh trackpad_disable(){ /sbin/sysctl hw.psm.synaptics.min_pressure=220 } trackpad_enable(){ /sbin/kldunload ums /sbin/sysctl hw.psm.synaptics.min_pressure=32 } synaptics_$1 Then you will want to make the script executable. chmod +x synaptics-hotplug Next you will want to open /etc/devd/usb.conf and navigate to line 5686, it should look like the following: nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; match "intclass" "0x03"; match "intsubclass" "0x01"; match "intprotocol" "0x02"; action "kldload -n ums"; }; That last line in the block, 'action' is what runs everytime we plug in our USB mouse, edit it so it runs our script: action "kldload -n ums && /usr/local/bin/synaptics-hotplug disable"; Now everytime we plug in our USB mouse, it will run our script with the "disable" argument variable which runs our script's "synaptics_disable" function, this changes our synaptics trackpad minimal pressure to 220, disabling it. Next open /etc/devd.conf as root and put the following at the end of the file(or anywhere): detach 100 { device-name "ums[0-9]+"; action "/usr/local/bin/synaptics-hotplug enable"; }; With this done, the only thing you'll need to do is restart devd service devd restart Once devd is restarted, the synaptics trackpad should turn off and on depending whether your USB mouse is plugged in. Credit for scripted synpatics toggle via devd goes to SamuelGogarty. ===== Other Resources ===== * [[https://www.freshports.org/sysutils/iichid/|FreeBSD Port: sysutils/iichid -- Generic FreeBSD HID layer for I2C and USB devices]] ---- {{tag>HowTo}} {{tag>Laptop}}