Add additional ways to recognize an external stylus

Recognize a keyboard device as an external stylus if it can produce any
of the stylus key codes.

Additionally, add the ability to configure an input device as an
external stylus using an IDC file. This will be necessary to classify
external styluses that report buttons as custom HID usages, since we
don't have a way to tell which HID usages a device supports from
userspace yet.

Bug: 246394583
Test: atest inputflinger_tests
Test: manual, with a Lenovo Precision Pen 3
Change-Id: Ief22aac9537cd168dd43d2a9d63bc0a65f6ba3dc
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index eaa6f5c..0aaef53 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -149,6 +149,14 @@
     return out;
 }
 
+/* The set of all Android key codes that correspond to buttons (bit-switches) on a stylus. */
+static constexpr std::array<int32_t, 4> STYLUS_BUTTON_KEYCODES = {
+        AKEYCODE_STYLUS_BUTTON_PRIMARY,
+        AKEYCODE_STYLUS_BUTTON_SECONDARY,
+        AKEYCODE_STYLUS_BUTTON_TERTIARY,
+        AKEYCODE_STYLUS_BUTTON_TAIL,
+};
+
 /**
  * Return true if name matches "v4l-touch*"
  */
@@ -2189,11 +2197,13 @@
         device->classes |= InputDeviceClass::CURSOR;
     }
 
-    // See if this is a rotary encoder type device.
+    // See if the device is specially configured to be of a certain type.
     std::string deviceType;
     if (device->configuration && device->configuration->tryGetProperty("device.type", deviceType)) {
         if (deviceType == "rotaryEncoder") {
             device->classes |= InputDeviceClass::ROTARY_ENCODER;
+        } else if (deviceType == "externalStylus") {
+            device->classes |= InputDeviceClass::EXTERNAL_STYLUS;
         }
     }
 
@@ -2298,6 +2308,16 @@
                 break;
             }
         }
+
+        // See if this device has any stylus buttons that we would want to fuse with touch data.
+        if (!device->classes.any(InputDeviceClass::TOUCH | InputDeviceClass::TOUCH_MT)) {
+            for (int32_t keycode : STYLUS_BUTTON_KEYCODES) {
+                if (device->hasKeycodeLocked(keycode)) {
+                    device->classes |= InputDeviceClass::EXTERNAL_STYLUS;
+                    break;
+                }
+            }
+        }
     }
 
     // If the device isn't recognized as something we handle, don't monitor it.