<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Philipp</title>
    <description>The latest articles on DEV Community by Philipp (@xarantolus).</description>
    <link>https://dev.to/xarantolus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F74862%2F3f3c61ce-6dd2-4da2-897e-42c9b9e4be35.png</url>
      <title>DEV Community: Philipp</title>
      <link>https://dev.to/xarantolus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xarantolus"/>
    <language>en</language>
    <item>
      <title>How to tap the Android screen from the underlying Linux system</title>
      <dc:creator>Philipp</dc:creator>
      <pubDate>Tue, 18 May 2021 12:23:56 +0000</pubDate>
      <link>https://dev.to/xarantolus/how-to-tap-the-android-screen-from-the-underlying-linux-system-34jf</link>
      <guid>https://dev.to/xarantolus/how-to-tap-the-android-screen-from-the-underlying-linux-system-34jf</guid>
      <description>&lt;p&gt;In recent years phone screens seem to only have gotten bigger. This is great because it allows you to see more on your screen, but it also has some drawbacks. One of them has been very annoying to me: I can no longer reach buttons at the top left of the screen in a comfortable way.&lt;/p&gt;

&lt;p&gt;In a way, I would divide the screen in three areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Easy to reach&lt;/strong&gt;: the area can be reached with the thumb while holding the phone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not comfortable&lt;/strong&gt;: you &lt;em&gt;can&lt;/em&gt; reach the area, but it's not as comfortable as the previously mentioned one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unreachable&lt;/strong&gt;: this area is not in the reach of my thumb without repositioning my hand at the edge of the phone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HHww3rkC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://xarantolus.github.io/blog/assets/taptap/Phone-Reachable-Areas.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HHww3rkC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://xarantolus.github.io/blog/assets/taptap/Phone-Reachable-Areas.png" alt="Here is a screenshot with an overlay that shows which areas are easy to reach with a thumb"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So to me the most annoying buttons are those at the top left. While those on the top right can still be reached with a little effort, the ones in the top left corner require more effort. &lt;/p&gt;

&lt;h3&gt;
  
  
  So how do we solve this problem?
&lt;/h3&gt;

&lt;p&gt;The best way I came up with to solve this problem was a simple idea: What if there was a way to tap the top left corner without leaving the "Easy to reach" category?&lt;/p&gt;

&lt;p&gt;My phone has a fingerprint scanner at the back that is very easy to reach. This scanner also doesn't have any functionality when the phone is unlocked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detecting a finger on the sensor
&lt;/h3&gt;

&lt;p&gt;So I took a look at the Android system log and found the following lines when putting the finger on and off the sensor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fpc_fingerprint_hal: report_input_event - Reporting event type: 1, code: 96, value:1
fpc_fingerprint_hal: report_input_event - Reporting event type: 1, code: 96, value:0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only relevant difference between these lines is the number at the end -- &lt;code&gt;1&lt;/code&gt; for "finger down", &lt;code&gt;0&lt;/code&gt; for "finger up".&lt;/p&gt;

&lt;p&gt;So that was easy -- just write a program that scans the &lt;code&gt;logcat&lt;/code&gt; output, detects these lines and then runs the &lt;code&gt;input tap x y&lt;/code&gt; shell command to tap a specific point. Right? &lt;/p&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;h3&gt;
  
  
  It's so slow
&lt;/h3&gt;

&lt;p&gt;The input command seemed very slow to me. It took quite some time from tapping the sensor to a reaction to the click. While testing it appeared to take at least 300ms, often worse with about 400ms. &lt;/p&gt;

&lt;p&gt;According to a lot of &lt;a href="https://stackoverflow.com/questions/536300/what-is-the-shortest-perceivable-application-response-delay"&gt;anecdotal evidence&lt;/a&gt;, actions that take 100ms or less are perceived as instant. So this command definitely fails all expectations of "instant" (it was probably not designed to be fast, anyway). But why is that?&lt;/p&gt;

&lt;h3&gt;
  
  
  The "input" command
&lt;/h3&gt;

&lt;p&gt;Android comes with a lot of different commands in &lt;code&gt;/system/bin&lt;/code&gt;. Most of them are to be expected in a typical Linux environment (like &lt;code&gt;tail&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt; etc.) and some of them are specific to Android.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;input&lt;/code&gt; command, to my surprise, was just a shell script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/system/bin/sh&lt;/span&gt;
&lt;span class="c"&gt;# Script to start "input" on the device, which has a very rudimentary&lt;/span&gt;
&lt;span class="c"&gt;# shell.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/system
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLASSPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$base&lt;/span&gt;/framework/input.jar
&lt;span class="nb"&gt;exec &lt;/span&gt;app_process &lt;span class="nv"&gt;$base&lt;/span&gt;/bin com.android.commands.input.Input &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I read that correctly, it basically starts a &lt;a href="https://android.googlesource.com/platform/frameworks/base/+/master/cmds/input/src/com/android/commands/input/Input.java"&gt;Java program&lt;/a&gt; that can simulate a tap. There are also other actions it can do but for this post I don't care.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reducing the delay
&lt;/h2&gt;

&lt;p&gt;One method to not have the long, noticeable delay is -- quite simply -- not relying on the &lt;code&gt;input&lt;/code&gt; command. It just writes some data, that shouldn't be too hard to copy. So instead of starting a script that starts a program that writes a small piece of data, we can just write it ourselves.&lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;what&lt;/strong&gt; should we write and &lt;strong&gt;where&lt;/strong&gt; should the data be written?&lt;/p&gt;

&lt;p&gt;I don't know exactly why, but I never really looked at &lt;a href="https://source.android.com/devices/input/touch-devices"&gt;the documentation&lt;/a&gt; (also &lt;a href="https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt"&gt;this&lt;/a&gt; now makes a lot more sense) and started reverse-engineering this... open source protocol. Yea... anyway.&lt;/p&gt;

&lt;p&gt;The first step when trying to reproduce a behavior is watching it. So how can we watch taps on the screen as they happen?&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://source.android.com/devices/input/getevent"&gt;&lt;code&gt;getevent&lt;/code&gt;&lt;/a&gt; utility allows us to watch certain events happen in real time. It also makes it easy to list device files associated with those events.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;getevent -pl&lt;/code&gt; (in a root shell on the phone) we can get a nice overview of devices, their events and device file paths: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chiron:/ $ getevent -pl
add device 1: /dev/input/event6
name:     "msm8998-tasha-snd-card Button Jack"
events:
    KEY (0001): KEY_VOLUMEDOWN        KEY_VOLUMEUP          KEY_MEDIA             BTN_3
                BTN_4                 BTN_5
input props:
    INPUT_PROP_ACCELEROMETER
add device 2: /dev/input/event5
name:     "msm8998-tasha-snd-card Headset Jack"
events:
    SW  (0005): SW_HEADPHONE_INSERT   SW_MICROPHONE_INSERT  SW_LINEOUT_INSERT     SW_JACK_PHYSICAL_INS
                SW_PEN_INSERTED       0010                  0011                  0012
input props:
    &amp;lt;none&amp;gt;
add device 3: /dev/input/event4
name:     "uinput-fpc"
events:
    KEY (0001): KEY_KPENTER           KEY_UP                KEY_LEFT              KEY_RIGHT
                KEY_DOWN              BTN_GAMEPAD           BTN_EAST              BTN_C
                BTN_NORTH             BTN_WEST
input props:
    &amp;lt;none&amp;gt;
add device 4: /dev/input/event3
name:     "gpio-keys"
events:
    KEY (0001): KEY_VOLUMEUP
    SW  (0005): SW_LID
input props:
    &amp;lt;none&amp;gt;
add device 5: /dev/input/event0
name:     "qpnp_pon"
events:
    KEY (0001): KEY_VOLUMEDOWN        KEY_POWER
input props:
    &amp;lt;none&amp;gt;
add device 6: /dev/input/event2
name:     "uinput-goodix"
events:
    KEY (0001): KEY_HOME
input props:
    &amp;lt;none&amp;gt;
add device 7: /dev/input/event1
name:     "synaptics_dsx"
events:
    KEY (0001): KEY_WAKEUP            BTN_TOOL_FINGER       BTN_TOUCH
    ABS (0003): ABS_X                 : value 0, min 0, max 1079, fuzz 0, flat 0, resolution 0
                ABS_Y                 : value 0, min 0, max 2159, fuzz 0, flat 0, resolution 0
                ABS_MT_SLOT           : value 9, min 0, max 9, fuzz 0, flat 0, resolution 0
                ABS_MT_TOUCH_MAJOR    : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                ABS_MT_TOUCH_MINOR    : value 0, min 0, max 255, fuzz 0, flat 0, resolution 0
                ABS_MT_POSITION_X     : value 0, min 0, max 1079, fuzz 0, flat 0, resolution 0
                ABS_MT_POSITION_Y     : value 0, min 0, max 2159, fuzz 0, flat 0, resolution 0
                ABS_MT_TRACKING_ID    : value 0, min 0, max 65535, fuzz 0, flat 0, resolution 0
input props:
    INPUT_PROP_DIRECT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It looks confusing at first, but especially the last device is interesting: It has all kinds of events that are associated with a multitouch device. That's our screen. So now we know &lt;strong&gt;where&lt;/strong&gt; to write data, the device file &lt;code&gt;/dev/input/event1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The question &lt;strong&gt;what&lt;/strong&gt; we should write can be answered by watching the &lt;code&gt;getevent -l&lt;/code&gt; output:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/dev/input/event1: EV_ABS       ABS_MT_TRACKING_ID   0000504c
/dev/input/event1: EV_KEY       BTN_TOUCH            DOWN
/dev/input/event1: EV_KEY       BTN_TOOL_FINGER      DOWN
/dev/input/event1: EV_ABS       ABS_MT_POSITION_X    00000037
/dev/input/event1: EV_ABS       ABS_MT_POSITION_Y    0000008d
/dev/input/event1: EV_SYN       SYN_REPORT           00000000
/dev/input/event1: EV_ABS       ABS_MT_TOUCH_MAJOR   00000006
/dev/input/event1: EV_SYN       SYN_REPORT           00000000
/dev/input/event1: EV_ABS       ABS_MT_TRACKING_ID   ffffffff
/dev/input/event1: EV_KEY       BTN_TOUCH            UP
/dev/input/event1: EV_KEY       BTN_TOOL_FINGER      UP
/dev/input/event1: EV_SYN       SYN_REPORT           00000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is the output when doing a single tap in the top left corner of the display. Note that the numbers next to &lt;code&gt;ABS_MT_POSITION_{X,Y}&lt;/code&gt; are the coordinates I just tapped. So the question is: how do we translate this? Not at all, we just remove the &lt;code&gt;-l&lt;/code&gt; ("label event types and names in plain text") option to get a more "raw" data stream:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/dev/input/event1: 0003 0039 0000504d        # ABS_MT_TRACKING_ID  
/dev/input/event1: 0001 014a 00000001        # BTN_TOUCH           
/dev/input/event1: 0001 0145 00000001        # BTN_TOOL_FINGER     
/dev/input/event1: 0003 0035 00000037        # ABS_MT_POSITION_X   
/dev/input/event1: 0003 0036 0000008d        # ABS_MT_POSITION_Y   
/dev/input/event1: 0000 0000 00000000        # SYN_REPORT          
/dev/input/event1: 0003 0030 00000006        # ABS_MT_TOUCH_MAJOR  
/dev/input/event1: 0000 0000 00000000        # SYN_REPORT          
/dev/input/event1: 0003 0039 ffffffff        # ABS_MT_TRACKING_ID  
/dev/input/event1: 0001 014a 00000000        # BTN_TOUCH           
/dev/input/event1: 0001 0145 00000000        # BTN_TOOL_FINGER     
/dev/input/event1: 0000 0000 00000000        # SYN_REPORT          
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;OK, so that is the data. And we know where to write it. But still... how?&lt;br&gt;
Let's take a look at the source code of the &lt;a href="https://android.googlesource.com/platform/system/core/+/froyo-release/toolbox/sendevent.c"&gt;&lt;code&gt;sendevent&lt;/code&gt;&lt;/a&gt; command. It seems to basically be a lower-level version of the &lt;code&gt;input&lt;/code&gt; command (not really, but still kind of).&lt;/p&gt;

&lt;p&gt;The most interesting part is the &lt;code&gt;input_event&lt;/code&gt; struct, which is filled with data and then written to a device file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;input_event&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;timeval&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;__u16&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;__u16&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;__s32&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So before we had three columns with numbers in our output, and now we have three unsigned integers we want to fill with data: &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt;. The &lt;code&gt;getevent&lt;/code&gt; command outputs hex numbers, so we have to make sure we don't accidentally use the wrong number format when specifying them in a program (definitely never happened to me...sure ;)).&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting it all together
&lt;/h3&gt;

&lt;p&gt;Now all we have to do is write the twelve events we observed previously in sequence to the device file and then test the program.&lt;/p&gt;

&lt;p&gt;While implementing this is possible in any language, I chose &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; for the task because of the ability to easily cross-compile from Windows to Arm64 Android. It also made it extra easy to define the events needed for a single tap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Define the input_event struct, but in Go&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;InputEvent&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Time&lt;/span&gt;  &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Timeval&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt;  &lt;span class="n"&gt;EventType&lt;/span&gt;
    &lt;span class="n"&gt;Code&lt;/span&gt;  &lt;span class="n"&gt;EventCode&lt;/span&gt;
    &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Some const definitions, names are from the getevent output&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;EventType&lt;/span&gt; &lt;span class="kt"&gt;uint16&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;EV_ABS&lt;/span&gt; &lt;span class="n"&gt;EventType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x0003&lt;/span&gt;
    &lt;span class="n"&gt;EV_KEY&lt;/span&gt; &lt;span class="n"&gt;EventType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x0001&lt;/span&gt;
    &lt;span class="n"&gt;EV_SYN&lt;/span&gt; &lt;span class="n"&gt;EventType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x0000&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Known event codes for a touch sequence&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;EventCode&lt;/span&gt; &lt;span class="kt"&gt;uint16&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ABS_MT_TRACKING_ID&lt;/span&gt; &lt;span class="n"&gt;EventCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x0039&lt;/span&gt;
    &lt;span class="n"&gt;BTN_TOUCH&lt;/span&gt;          &lt;span class="n"&gt;EventCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x014a&lt;/span&gt;
    &lt;span class="n"&gt;BTN_TOOL_FINGER&lt;/span&gt;    &lt;span class="n"&gt;EventCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x0145&lt;/span&gt;
    &lt;span class="n"&gt;ABS_MT_POSITION_X&lt;/span&gt;  &lt;span class="n"&gt;EventCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x0035&lt;/span&gt;
    &lt;span class="n"&gt;ABS_MT_POSITION_Y&lt;/span&gt;  &lt;span class="n"&gt;EventCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x0036&lt;/span&gt;
    &lt;span class="n"&gt;ABS_MT_TOUCH_MAJOR&lt;/span&gt; &lt;span class="n"&gt;EventCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x0030&lt;/span&gt;
    &lt;span class="n"&gt;SYN_REPORT&lt;/span&gt;         &lt;span class="n"&gt;EventCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x0000&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Value field of BTN_TOUCH, BTN_TOOL_FINGER&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;TOUCH_VALUE_DOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x00000001&lt;/span&gt;
    &lt;span class="n"&gt;TOUCH_VALUE_UP&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0x00000000&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// This event happens more often; marks the start/end of a sequence&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;eventSynReport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InputEvent&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EV_SYN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;SYN_REPORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0x00000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// touch is the whole sequence of events that simulates a single tap&lt;/span&gt;
&lt;span class="c"&gt;// While testing it seemed like not all SYN_REPORT events are necessary,&lt;/span&gt;
&lt;span class="c"&gt;// but we will just use the same sequence as observed above&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;InputEvent&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EV_ABS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;ABS_MT_TRACKING_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0x0000e800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// Touch tracking ID, seems like we don't need to care about it&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c"&gt;// Pretend to put the finger down&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EV_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;BTN_TOUCH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TOUCH_VALUE_DOWN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EV_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;BTN_TOOL_FINGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TOUCH_VALUE_DOWN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c"&gt;// Top right corner&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EV_ABS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;ABS_MT_POSITION_X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0x00000071&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EV_ABS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;ABS_MT_POSITION_Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0x000000a3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;eventSynReport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EV_ABS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;ABS_MT_TOUCH_MAJOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0x00000005&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;eventSynReport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EV_ABS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;ABS_MT_TRACKING_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0xffffffff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c"&gt;// Now put the finger up again&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EV_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;BTN_TOUCH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TOUCH_VALUE_UP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;EV_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;BTN_TOOL_FINGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TOUCH_VALUE_UP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;eventSynReport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we just write our sequence to the device file &lt;code&gt;f&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Assumption: f is the opened display device file /dev/input/event1&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ievent&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LittleEndian&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ievent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"writing input event: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;```



Now we just write our sequence to the device file `&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s"&gt;`:



```&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="c"&gt;// Assumption: f is the opened display device file /dev/input/event1&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ievent&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LittleEndian&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ievent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"writing input event: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find the whole program &lt;a href="https://github.com/xarantolus/backtap/blob/main/cmd/singletap/main.go"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One interesting detail about the sequence is that it doesn't always have to be the same. Sometimes, there are more &lt;code&gt;SYN_REPORT&lt;/code&gt; events in a sequence, but interestingly they do not appear to change the result. According to the &lt;a href="https://www.kernel.org/doc/html/v4.15/input/event-codes.html#ev-syn"&gt;documentation&lt;/a&gt;, if no &lt;code&gt;SYN_REPORT&lt;/code&gt; has been sent between two events, they are seen as sent in the same moment of time; so this event type acts as a separator.&lt;/p&gt;

&lt;p&gt;Now that we have the code for a single tap, we can of course adjust the code to be able to tap any position by simply changing the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;In my tests this program has been &lt;strong&gt;a lot&lt;/strong&gt; faster than the method with the &lt;code&gt;input&lt;/code&gt; command, which was a nice outcome.&lt;/p&gt;

&lt;h3&gt;
  
  
  Actually using it
&lt;/h3&gt;

&lt;p&gt;Now that we have done all the work to get a working tap program, we only need to integrate it into a program that detects the fingerprint press, then sends those events. I'll spare you the details on that, you can see the whole program on &lt;a href="https://github.com/xarantolus/backtap"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's basically a daemon that runs in the background and detects the aforementioned log lines to react with a tap. It also has a few more commands, but they are not as technically interesting as the tap.&lt;/p&gt;

&lt;p&gt;I also packaged the program into a &lt;a href="https://github.com/topjohnwu/Magisk"&gt;Magisk&lt;/a&gt; (root solution with addons) module as that allows me to easily run it on boot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further ideas
&lt;/h3&gt;

&lt;p&gt;One could use &lt;code&gt;getevent&lt;/code&gt; and this method of writing events to create an event recorder that can accurately replay sequences of events. So if you want to automatically input a pin on the lock screen, that should be possible (the screen device file doesn't have any restrictions on &lt;em&gt;when&lt;/em&gt; the tap can happen, I think the &lt;code&gt;input&lt;/code&gt; command is limited to an unlocked phone only, no lock screen access).&lt;/p&gt;

&lt;h3&gt;
  
  
  Thanks
&lt;/h3&gt;

&lt;p&gt;If you found this interesting and want to create something like this or adapt the program for your phone, take a look at the &lt;a href="https://github.com/xarantolus/backtap"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If there are any mistakes in this post please feel free to point them out. Thank you :)&lt;/p&gt;

</description>
      <category>android</category>
      <category>linux</category>
      <category>magisk</category>
      <category>misc</category>
    </item>
  </channel>
</rss>
