Search TheCodeArtist

Loading...

Simulating keypress events on Android

Modern day smart-phones have already begun to migrate from the traditional "a-button-for-every-need" approach to the "huge-display-cum-touchscreen" form-factors. Android phones  are no exception. But, traditional buttons are still reqd. for a few oft used functions (power,back,home,menu etc.) And smart-phones continue to have them alongwith the primary touch-based-UI.

Android-OS provides a very easy method to simulate key/button press/release events via software. You might ask why do we need a software to generate the events when a hardware button is already present on the device. Here's why:
  • During development/testing of the button-drivers itself.
  • To implement automated rigorous tests. ( MonkeyTest? )
  • To implement/interface additional custom software keyboards.
  • Just because we can!
The reason why i am doing it today is REASON NUMBER 4.

Now, the basic goal of this exercise is extremely simple:
Q. How to generate a hardware-button-press event
    WITHOUT actually pressing any key on the device?

Let us first understand what happens when a hardware button is pressed. Here is what happens when you press a button on an Android device:
  1. The h/w button triggers an interrupt.
  2. The ISR of the corresponding driver gets called (in kernel).
  3. In the ISR, the driver generates an input-event.
  4. Android-framework (in userspace) gets the notification of the event.
  5. Android reads the input-event code & type.
  6. Compares it with the proper "keymap/keylayout" file.
  7. The proper button is identified.

To simulate button presses we enter this procedure at STEP3.
Instead of the regular driver generating the input-event, we generate an input-event ourselves using a pre-built userspace binary. This will then be notified to the Android-framework and the rest continues as above.

So now all depends on the the pre-built userspace binary, which is...
[ drum-roll... ]
...Input. (How convenient!) The syntax of input is as follows:
input keyevent <event_code>

Now, before we try to send any keyevent, we need to find out the event-code that maps to the h/w key we want to simulate. The following table summarizes all the supported keycodes in Android:


Additionally we can look up the keylayout (.kl) file on the device. Personally, I find keylayout a misnomer, as we are not talking about different keyboards here, but different mappings of an input-event-value to its functionality.

Anyways you can always find the file in system/usr/keylayout/xyz.kl
NOTE: For each keyboard device xyz, the android.keylayout.xyz system property must be set. If a keylayout file is not specified, Android will default to /system/usr/keylayout/qwerty.kl

Now to generate a event of a specific keycode, we simply execute this on the terminal/serial console:
input keyevent <keycode>

The value of keycode can be any of the integer values from the above table. In case a serial-console is NOT available on your device, you can always run the command via adb as follows:
adb shell input keyevent <keycode>

That's how a hardware-button-press is simulated in software!!



Further Reading:

60 comments :

  1. Awesome! Are there any way to detect foreground App to send accurate key events?

    ReplyDelete
  2. Have no problem using KEYCODE_CALL but no luck to hang-up with KEYCODE_ENDCALL.

    ReplyDelete
  3. @sj314 KEYCODE_ENDCALL CANNOT be intercepted by apps. Also since it is handled lower than the input queue, injecting it via adb may not work as expected.

    More info here:
    http://groups.google.com/group/android-platform/browse_thread/thread/c6e2de4b0cdbecd7/21b7cf4ee06a7005

    ReplyDelete
  4. Is there a way to send a key press event for long press (The one that generally opens a context menu)

    ReplyDelete
  5. @tagmaster Any character/string literals can be sent directly using "input text" command.

    For example to send a colon,

    adb shell input text ":"

    ReplyDelete
  6. Hi,

    still sending a text string with spaces is not supported.

    Or at least not on my device
    adb shell input text "a b c"
    Will only print 'a' to the device screen

    Workarounds are not so hard, just split the text on spaces and do 'adb shell input key SPACE' but it would be more convenient to have the adb to accept strings with spaces in them from the beginning

    Cheers Johan

    ReplyDelete
  7. Can i simulate the power on event when the battery is off? I want my phone to power on as soon as a charger is connected . My specific requirement will not allow me to press power on button to start the android phone . Can any one has any idea whether this can be done? Iphone automatically starts itself if battery is drained off and put to charge . I want similar functionality in android phone. Please let me know if this is possible at all or not? Can we actually simulate power on button event when phone is off completely?Is it through alarm interrupt?if yes then details please.
    Thanks in advance.

    ReplyDelete
    Replies
    1. Short answer: No.

      Long answer: The technique described in the above post requires Android to be booted-up on the device and adb setup properly between the device and the host-machine. Powering-on the device when charger is connected depends on how the bootloader is configured on it. When powered-off and connected to a charger, most Android devices just start charging and do NOT power-on until the power button is explicitly pressed.

      Delete
    2. Autobooting a tablet is very possible in fact but it requires modifications inside the kernel initramfs to hotswap the charger binaries.

      Generally this means, compiling android from source (including a proper charging binary) and injecting that into the kernel as seen fit.

      Have done it before. Worked fine.

      Delete
    3. If we have access to the source, then the simplest way to get this working is to modify the boot-loader code. During boot-up the boot-loader checks if the power button was pressed, and if not then just keeps charging (often displaying a rudimentary charging UI) and does not load the Linux kernel.

      Simply commenting the check and loading the Linux kernel unconditionally all the time should produce the desired behaviour.

      Delete
  8. The keylayout table you listed is working fine, but I tried to search for it on the system and didn't find it under /system/usr/keylayout in any "*.kl" file their. For example in your able the power keycode is 26 which is working on my device, but the power keycode in all my "*.kl" files are 116. I am confused.

    ReplyDelete
    Replies
    1. Here is the complete list of paths on the device where keylayout files can be stored.

      Also the various paths listed in the above link are in order of priority. i.e. the system starts scanning for a .kl file in the path at the top of the list and continues down the list.

      The first relevant .kl file found is used by the device.

      Multiple .kl files can exist on a device. This is usually done to handle different input-devices like external-keyboards & joysticks. The input-device can generally be identified by the names of the .kl files.

      Irrelevant keycodes can be listed in some .kl files. For example a joystick's .kl file could contain a (possibly wrong) keymap for the "power" button. Such codes do NOT affect the system behaviour as long as that particular input-device never generates that keycode.

      It also could be done intentionally to provide similar functionality from multiple interfaces. For example, a particular button on the joystick can be configured to act as a power button for the Android device.

      One can verify any .kl file using the Validate Keymaps tool (available as part of Android source code).

      Delete
  9. This works great when I use terminal emulator, but when I log in via ssh or telnet and issue the same command (i.e. input keyevent 82), I get a "Segmentation Fault" error.

    Anyway to run this with ssh and have the gui on the screen respond?

    Thanks!

    ReplyDelete
    Replies
    1. Not being able to run system commands is a common problem with various ssh servers on Android. It looks like its an issue with one or more environment vars not being setup properly which leads to missing lib and a seg-fault. You might want to run a trace on ssh from where you are trying to access the android device. Also the logs of the ssh-server on the Android device ought to be of help...

      Delete
    2. I did some more digging and found out that the version of su that I was using was causing the problem. It is the su that ships with the mk802 (which is what I am using). I downloaded Superuser from the market, and replaced the current su with it. Now it seems to be working, but it is a little slow. You don't happen to know of a way to speed it up do you?

      Delete
    3. Splendid job! :) Among other things, one way to speed-up ssh is switching to RSA keys which are almost 4times faster(for validation) than DSA.

      Delete
    4. Hi erocm123,
      How did you replace "su"?
      I have tried replacing the su file but executing su I do not get the su prompt.
      Can you provide the steps?
      Thanks!!

      Delete
  10. can anybody tell me that if i want to do any action on long click then it is possible using adb shell ? yes then how ? because i had try out to find out but get only by click event . please help me .

    ReplyDelete
  11. Thank you , helped me a lot :)

    ReplyDelete
  12. is there a way to do the "opposite"

    to hook a touch action to a hardware button, for instance

    (I have first person shooters on tables because you cant aim and fire correctly)

    in a game I press the screen to shoot which should be converted to a event, If I can attach that event to a button I'll be able to do the action with the button instead of the screen

    the same way as if I attach a game controller to the tablet.

    is that possible?

    ReplyDelete
  13. This works great! However , how can I use this to simuulate the screenshot capturing ? For capturing screenshot , *simultaneous* keypresses of volume down and power key are needed.

    ReplyDelete
  14. i want to change the device date . changing date by 7 day ahead . i used intent function am start -a android.intent.action.MAIN -n com.android.settings/.DateTimeSettings
    Now i can go ahead by 7 day by input keyevent to change the date .

    ReplyDelete
    Replies
    1. *now i want to go ahead by 7 days by input keyevent to change the date

      Delete
    2. One can use the keyevents 19/20/21/22 (up/down/left/right) and 66(enter) to navigate the UI elements. The following sequence of keyevents does the trick for me on my N1 running CyanogenMod7.2(gingerbread):-

      adb shell

      input keyevent 20
      input keyevent 20
      input keyevent 66
      (down,down,enter to select "set-date" option)
      input keyevent 22
      input keyevent 19
      (move focus to "+" over day)
      input keyevent 66
      input keyevent 19
      input keyevent 66
      input keyevent 19
      input keyevent 66
      input keyevent 19
      input keyevent 66
      input keyevent 19
      input keyevent 66
      input keyevent 19
      input keyevent 66
      input keyevent 19
      input keyevent 66
      (7 times "enter". "Up" to refocus onto "+")
      input keyevent 20
      input keyevent 20
      input keyevent 20
      input keyevent 66
      (move focus "down" to "Set" button and "enter")

      This might have to change depending on your device and any UI modifications based on the ROM you are running. For example if "Set Date" option is further down in the list, then additional "keyevent 20"s will be required to navigate all the way down.

      A simpler method for rooted devices would be to run the following command to set the required time and date.

      date -s yyyyMMdd.hhmmss

      Delete
  15. How do I delete say a list of characters for example.

    The quick brown fox.

    I could from the end of sentence execute the following command 20 times. But that executes rather slowly and it also seems superflous. Is there a execute multiple times command to make it simpler ?

    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67
    input keyevent 67

    ReplyDelete
  16. Use shell scripts! ;-)

    Either enter the entire set of adb commands in a shell-script on the host-PC and run it.

    OR

    Create a shell-script on the Android-device with all the "input keyevent keycode" commands and run this script on the Android-device via "adb shell script-name".

    ReplyDelete
    Replies
    1. Hi. I am creating a navigation bar alternative for Android and using these commands.

      For back key, the command is input keyevent 4

      But after the command is fired on older devices, it takes some time (about a second or so) for the response. That is rather slow.

      Writing a shell script also is not slow as after every command, it pauses for a small amount of time.

      Is there any alternative to speed this up?

      Delete
  17. Thanks mate
    this was useful

    ReplyDelete
  18. Hi ,

    I want to simulate Recent Apps icon on my Android device, can u guys pls let me know how to do it ....

    Thanks in Advance......

    ReplyDelete
  19. I get the following error-
    "Input cannot be resolved to a type"
    Can anybody help??

    ReplyDelete
    Replies
    1. What command did you run and where?...

      Delete
    2. I am a beginner and trying to write an android code to trigger the record button of the camera. I am launching the camera in video mode using intent and added -"Input keyevent 27" in my code to start recording but that produced an error "Input cannot be resolved to a type".

      I then tried this-
      KeyEvent kev = newKeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_CAMERA);
      onKeyDown(KeyEvent.KEYCODE_CAMERA, kev);
      but it didn't trigger the record button.
      Please help. Thanks in advance.

      Delete
    3. Check out the tutorial to launch video recorder activity http://android-er.blogspot.tw/2011/04/start-video-recording-using.html

      Also the following link has examples describing how to capture video in your own activity http://stackoverflow.com/questions/1817742/how-can-i-capture-a-video-recording-on-android

      Delete
    4. Can you please tell how to use "input keyevent" in android code!

      Delete
    5. Sending keyevents in java is accomplished by using dispatchKeyEvent().

      The documentation does go on to say that the keyevent is dispatched from the top of the view tree down to the currently focused view. If this view has focus, it will dispatch to itself. Otherwise it will dispatch the next node down the focus path. This method also fires any key listeners.

      Delete
  20. Great info. I can not get this to work because my ICS tablet does not have the input method on it. I tried pulling it from the emulator, but it seems to have dependencies that I am not getting correct. Have you seen any good info on the correct installation of input and its dependencies?

    ReplyDelete
  21. Any idea how can I read Keyboard Inputs? For example I've pressed S key and I get X,Y coords for tap inputs and pressure in display area of that key... but nothing that could help me identify what key was pressed.

    nevrax-McBkPr:~ nevrax$ adb shell getevent -lt
    add device 1: /dev/input/event1
    name: "lid_input"
    add device 2: /dev/input/event0
    name: "elan-touchscreen"
    add device 3: /dev/input/event2
    name: "gpio-keys"

    [ 161550.717211] /dev/input/event0: EV_ABS ABS_MT_TRACKING_ID 000006ef
    [ 161550.717228] /dev/input/event0: EV_ABS ABS_MT_TOUCH_MAJOR 00000006
    [ 161550.717232] /dev/input/event0: EV_ABS ABS_MT_PRESSURE 0000000d
    [ 161550.717237] /dev/input/event0: EV_ABS ABS_MT_POSITION_X 000000e3
    [ 161550.717241] /dev/input/event0: EV_ABS ABS_MT_POSITION_Y 00000632
    [ 161550.717247] /dev/input/event0: EV_SYN SYN_REPORT 00000000
    [ 161550.862091] /dev/input/event0: EV_ABS ABS_MT_TRACKING_ID ffffffff
    [ 161550.862104] /dev/input/event0: EV_SYN SYN_REPORT 00000000

    Thank you!

    ReplyDelete
    Replies
    1. The touchscreen driver is unaware of what is currently displayed on the screen. It just reports the X,Y co-ordinates.

      If you are trying to setup some sort of automation/monitoring on a particular device that you own, then one possible way to determine the key pressed would be have a look-up table with all the co-ordinate ranges for the on-screen soft-keyboard that you have on your device.

      It will be really challenging to regenerate the look-up table if the orientation of the device changes OR if the on-screen soft-keyboard layout is changed.

      Delete
    2. There are some tools that can record not only tap coords but also key inputs from keyboards and I was wondering how do they do it?

      I'm trying to build an automation tool for repetitive tasks using a simple template system. In order to build those templates first I have to record my actions taps, swipes, key inputs and time between those actions. Otherwise I would have to enable debug mode an manually note each gesture and key input plus the time between actions.

      Delete
    3. Tools to record android keyboard input? Can you share any names/links to what you are referring to?

      Delete
    4. RepetiToch... but I think is having exactly the problem described by you... soft keyboard layout / changing screen orientation.

      Android Bot Maker... seems not to be able to record anything but it can "play" taps and keys based on "input" command.

      Delete
    5. did you guys happen to get this to work?
      I use RepetiToch but that is time based and if I set it up the only way I think it will soon be out of sink with my automagic flow.
      I tried to enable debug mode an manually note each gesture and key input plus the time between actions but it does not seem to do anything I get this in my logs.
      21.02.2014 01:19:58.894 [Flow1] Action 'Execute Root Command: input tap in ' stderr=sh: [1]: syntax error: '<' unexpected filed

      Delete
  22. so how could i type a german umlaut like öäü using "input keyevent"
    using input text ö
    leads to a segmentation fault.

    ReplyDelete
  23. If you cannot use spaces with "text" is because a bug in /system/bin/input.

    In that script you can replace:
    $*
    by
    "$*"

    or run the commands manually

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. "$*" is not working for me. But "$@" is working true.

      Delete
  24. Hello,

    I tried to use the keyevent 26 (KEYCODE_POWER) to shut down the screen by a java application. It's don't seem to work neither for the KEYCODE_HOME but it's work s fine for KEYCODE_BACK... Is theirs some known issues for this problem ? thanks

    ReplyDelete
    Replies
    1. Exactly what commands are you running and how? On a PC connected to your Android device, does the following command from the console/command-line "adb shell input keyevent 26" work for you?...

      Delete
    2. When I use the adb shell input keyevent 26, it's works. But I would like to use it on a java file for the moment I tried :

      Process chmod = Runtime.getRuntime().exec("input keyevent 26"); //it's only works for back pressed

      &

      Instrumentation mInst = new Instrumentation(); mInst.sendKeyDownUpSync( KeyEvent.KEYCODE_POWER ); //it's only works for back pressed

      Delete
    3. The reason for the failure of "input keyevent" command launched using runtime.exec() is not clear to me as well. But i have NOT tried it and cannot vouch that it is supposed to work.

      sendKeyDownUpSync() sends the event to the currently focused "window". Hence only the back button event works as the events generated by the power and home buttons generally are not handled by the foreground activity and sending the activities those events does not produce the desired effect.

      Delete
  25. Any thought on how I use an external heat/motion sensor to trigger the camera on an android device?

    ReplyDelete
  26. Hello,
    Is there a way to simulate a long power button press? I need to turn off the device with a long power button press. I've tried with adb shell input 26 but it seems like a short button press and my phone goes to sleep.

    ReplyDelete
    Replies
    1. The long-button press is not handled in the software stack. That is why it works even when the Android OS is not-responding.

      The power-button long-press event is generally implemented in hardware i.e as an interrupt to the PMIC (power-management chip). Upon receiving the interrupt, the PMIC momentarily cuts-off the power-supply to the main processor, effectively forcing a hard-reboot.

      Use one of the following commands to shutdown/reboot your Android device :
      adb shutdown -k or
      adb reboot or
      adb reboot -p

      Delete
  27. adb shutdown -k seems to be not working. Sadly, I need to do a shutdown instead a reboot. Is there another way to shutdown without using the pwr button?

    ReplyDelete
  28. For your Query :

    Sergiu StratJun 11, 2013, 1:05:00 PM
    Any idea how can I read Keyboard Inputs? For example I've pressed S key and I get X,Y coords for tap inputs and pressure in display area of that key... but nothing that could help me identify what key was pressed.

    nevrax-McBkPr:~ nevrax$ adb shell getevent -lt
    add device 1: /dev/input/event1
    name: "lid_input"
    add device 2: /dev/input/event0
    name: "elan-touchscreen"
    add device 3: /dev/input/event2
    name: "gpio-keys"

    [ 161550.717211] /dev/input/event0: EV_ABS ABS_MT_TRACKING_ID 000006ef
    [ 161550.717228] /dev/input/event0: EV_ABS ABS_MT_TOUCH_MAJOR 00000006
    [ 161550.717232] /dev/input/event0: EV_ABS ABS_MT_PRESSURE 0000000d
    [ 161550.717237] /dev/input/event0: EV_ABS ABS_MT_POSITION_X 000000e3
    [ 161550.717241] /dev/input/event0: EV_ABS ABS_MT_POSITION_Y 00000632
    [ 161550.717247] /dev/input/event0: EV_SYN SYN_REPORT 00000000
    [ 161550.862091] /dev/input/event0: EV_ABS ABS_MT_TRACKING_ID ffffffff
    [ 161550.862104] /dev/input/event0: EV_SYN SYN_REPORT 00000


    Now we can change these hexadecimal code into Binary format , which actually ur system can understand .Below is the code which converts into binary one :

    $LOGFILE = "play.txt";
    $FILE = "Sample.pl";
    open (CHECKBOOK, $LOGFILE);

    while ($record = ) {
    chomp($record);
    if($record eq "sleep"){
    print "sleep 1;";
    sleep 1;
    #continue;
    }
    @values = split(' ', $record);
    $value0 = substr($values[0],0,17);
    $value1 = hex($values[1]);
    $value2 = hex($values[2]);
    $value3 = hex($values[3]);
    #if($value1 eq 0)
    print "adb shell sendevent $value0 $value1 $value2 $value3 \n" ;



    {system( "adb shell sendevent $value0 $value1 $value2 $value3 "); }

    # foreach my $val (@values) {
    # print "$val\n";
    # }

    }

    close(CHECKBOOK);


    Thanks
    Shubham Tomar

    ReplyDelete
  29. nice article, just what I was lookin for.

    ReplyDelete
  30. maybe anyone of You come with such a problem (accept button in camera app):
    http://stackoverflow.com/a/23289891/2570350

    ReplyDelete
  31. m getting error when capturing KeyEvent_0.......KeyEvent_9. in receiver

    ReplyDelete