chiark / gitweb /
Button zones: Provide BottomEdgeZonesEnable
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 23 Apr 2016 19:18:53 +0000 (20:18 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 26 Apr 2016 19:42:32 +0000 (20:42 +0100)
Many modern laptops have a clickpad, with some faint legend on the
surface suggesting that the bottom portion is a pair (usually) of
buttons.

Some users who are used to laptops which had separate physical buttons
below the trackpad have developed the habit of putting one finger on
the physical button, and using another finger to mouse.

This user behaviour can be supported if we:
 - ignore touches in the "button" area for all purposes, except
 - decide which button was pressed, if the user clicks the clickpad,
   by looking at which touch(es) are present in the button area

This is a novel combination of the behaviours of the BottomEdge and
ButtonZones options.  Provide a new BottomEdgeZonesEnable option,
(including documentation and static configuration).

The current code does not support users who have a habit of generating
and using chorded button events on mice with physical buttons.  (That
is, users who have configured application(s) to process simultaneous
clicks of different buttons meaningfully differently to single-button
clicks.)  I think this should be regarded as a bug in the
implementation I am introducing in this patch.  Fixing this would be
feasible without new config options or changes to other semantics but
would involve more rework of the zone processing in gestures.c than I
currently have time for.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
README.md
include/mconfig.h
src/gestures.c
src/mconfig.c

index 5063eae..c65eef1 100644 (file)
--- a/README.md
+++ b/README.md
@@ -128,6 +128,15 @@ those ClickFinger values that are enabled. So setting ClickFinger1 to 0 and
 enabling the other two will create two zones, one for ClickFinger2 and one for
 ClickFinger3. Boolean value. Defaults to false.
 
+**BottomEdgeZonesEnable** -
+Whether to enable button zones in the bottom edge.  If this feature is
+enabled then touches in the BottomEdge region determine which button
+is sent.  The vertical division of the zones is as for
+ButtonZonesEnable.  If there is no touch in the bottom edge, then
+button 0 will be sent (or the button according to ButtonZonesEnable,
+if that is enabled).  This is particularly useful for clickpads with
+integrated buttons. Defaults to false.
+
 **ButtonTouchExpire** - 
 How long (in ms) to consider a touching finger as part of button emulation. A
 value of 0 will not expire touches. Integer value. Defaults to 100.
index 6cead2a..2c3c86f 100644 (file)
@@ -38,6 +38,7 @@
 #define DEFAULT_BUTTON_ENABLE 1
 #define DEFAULT_BUTTON_INTEGRATED 1
 #define DEFAULT_BUTTON_ZONES 0
+#define DEFAULT_BOTTOM_EDGE_ZONES 0
 #define DEFAULT_BUTTON_1TOUCH 3
 #define DEFAULT_BUTTON_2TOUCH 2
 #define DEFAULT_BUTTON_3TOUCH 0
@@ -119,6 +120,7 @@ struct MConfig {
        int button_integrated;  // Is the button under the touchpad? 0 or 1
        int button_expire;              // How long to consider a touch for button emulation. >= 0
        int button_zones;               // Use button zones for emulation?
+       int bottom_edge_zones;          // Use bottom edge zones for emulation?
        int button_1touch;              // What button to emulate when one finger is on the
                                                        // pad or the first zone is clicked? 0 to 32
        int button_2touch;              // What button to emulate when two fingers are on the
index 5922c00..22a94ac 100644 (file)
@@ -215,6 +215,21 @@ static void buttons_update(struct Gestures* gs,
                        if (cfg->button_zones && earliest >= 0) {
                                pos = ms->touch[earliest].x;
                        }
+                       if (cfg->bottom_edge_zones) {
+                               int latest_bottom = -1;
+                               foreach_bit(i, ms->touch_used) {
+                                       if (!GETBIT(ms->touch[i].state, MT_BOTTOM_EDGE))
+                                               continue;
+                                       if (GETBIT(ms->touch[i].state, MT_PALM) && cfg->ignore_palm)
+                                               continue;
+                                       /* we deliberately don't ignore thumbs for bottom button zones */
+
+                                       if (latest_bottom == -1 || timercmp(&ms->touch[i].down, &ms->touch[latest_bottom].down, >))
+                                               latest_bottom = i;
+                               }
+                               if (latest_bottom >= 0)
+                                       pos = ms->touch[latest_bottom].x;
+                       }
 
                        if (pos >= 0) {
                                int zones, left, right;
index 4ecbd87..761b9a1 100644 (file)
@@ -41,6 +41,7 @@ void mconfig_defaults(struct MConfig* cfg)
        cfg->button_integrated = DEFAULT_BUTTON_INTEGRATED;
        cfg->button_expire = DEFAULT_BUTTON_EXPIRE;
        cfg->button_zones = DEFAULT_BUTTON_ZONES;
+       cfg->bottom_edge_zones = DEFAULT_BOTTOM_EDGE_ZONES;
        cfg->button_1touch = DEFAULT_BUTTON_1TOUCH;
        cfg->button_2touch = DEFAULT_BUTTON_2TOUCH;
        cfg->button_3touch = DEFAULT_BUTTON_3TOUCH;
@@ -137,6 +138,7 @@ void mconfig_configure(struct MConfig* cfg,
        cfg->button_integrated = xf86SetBoolOption(opts, "ButtonIntegrated", DEFAULT_BUTTON_INTEGRATED);
        cfg->button_expire = MAXVAL(xf86SetIntOption(opts, "ButtonTouchExpire", DEFAULT_BUTTON_EXPIRE), 0);
        cfg->button_zones = xf86SetBoolOption(opts, "ButtonZonesEnable", DEFAULT_BUTTON_ZONES);
+       cfg->bottom_edge_zones = xf86SetBoolOption(opts, "BottomEdgeZonesEnable", DEFAULT_BOTTOM_EDGE_ZONES);
        cfg->button_1touch = CLAMPVAL(xf86SetIntOption(opts, "ClickFinger1", DEFAULT_BUTTON_1TOUCH), 0, 32);
        cfg->button_2touch = CLAMPVAL(xf86SetIntOption(opts, "ClickFinger2", DEFAULT_BUTTON_2TOUCH), 0, 32);
        cfg->button_3touch = CLAMPVAL(xf86SetIntOption(opts, "ClickFinger3", DEFAULT_BUTTON_3TOUCH), 0, 32);