How do I sense what key is pressed?

815 views
Skip to first unread message

kiikr...@gmail.com

unread,
Sep 25, 2016, 9:54:03 AM9/25/16
to autokey-users
I wish to have AutoKey take various actions depending on what sequence of keys I press, even when I am not inputting text or phrases.  For my particular situation, I'd like AutoKey to switch to my browser when I press <Super>+W and then B; but if I press <Super>+W and then E, I'd like it to switch to my editor.

So, when I type <Super>+W, I'd like it to run an AutoKey script.  Within that AutoKey script, how do I read what the next keystroke is, so that it knows which window to switch to?

Later on, I'd like <Super>+R to launch various programs depending on what the next keystroke is, or <Super>+D to insert the date/time stamp in various formats depending on what the next keystroke is.

I tried: system.exec_command("bash -c 'read -n1 MyVar; DoSomethingWith $MyVar'") and various incarnations of using bash, but it didn't work.  (I probably need to run it within a window, like  konsole -e "bash -c 'read bla bla bla' " but I'm not sure this would even be feasible.)

I've looked through the documentation and see where AutoKey can work with the mouse, and can insert keystrokes as if coming from the keyboard, but nothing to see what the user has actually pressed on the keyboard.

Any help would be appreciated.

Steve Fisher

unread,
Sep 25, 2016, 10:01:56 AM9/25/16
to autoke...@googlegroups.com
This is easier in a script:
#!/bin/bash
######################################################################################################
# This script will toggle minimize/activate first window with specified class
# If window not found program will be launched
#
# window class can be found with next programs:
#   wmctrl -x -l
#   xprop
# No credit taken.......... Cannot read the original.....
# Found on http://blog.sokolov.me/2014/06/20/linuxx11-toggle-window-minimizemaximize/
# in Russian :) but works when adjusting the wrapping.
# Assigned to meta-f in KDE plasma 5
######################################################################################################
NEEDED_WINDOW_CLASS="Navigator.Light"
LAUNCH_PROGRAM="/usr/bin/light"
######################################################################################################
NEEDED_WINDOW_WINDOW_ID_HEX=`wmctrl -x -l | grep ${NEEDED_WINDOW_CLASS} | awk '{print $1}' | head -n 1`
NEEDED_WINDOW_WINDOW_ID_DEC=$((${NEEDED_WINDOW_WINDOW_ID_HEX}))
if [ -z "${NEEDED_WINDOW_WINDOW_ID_HEX}" ]; then
    ${LAUNCH_PROGRAM}
else
    echo "Found window ID:${NEEDED_WINDOW_WINDOW_ID_DEC}(0x${NEEDED_WINDOW_WINDOW_ID_HEX})"
    ACIVE_WINDOW_DEC=`xdotool getactivewindow`
    if [ "${ACIVE_WINDOW_DEC}" == "${NEEDED_WINDOW_WINDOW_ID_DEC}" ]; then
        xdotool windowminimize ${NEEDED_WINDOW_WINDOW_ID_DEC}
    else
        xdotool windowactivate ${NEEDED_WINDOW_WINDOW_ID_DEC}
    fi
fi


The two lines you need to change are:
NEEDED_WINDOW_CLASS="Navigator.Light"
LAUNCH_PROGRAM="/usr/bin/light"

I have them set to firefox light.  window class can be found with autokey.
 

Then assign the hotkey in your desktop environment.

--
You received this message because you are subscribed to the Google Groups "autokey-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to autokey-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Joe

unread,
Sep 25, 2016, 2:41:47 PM9/25/16
to autoke...@googlegroups.com
Nice script. Thanks for posting it.

It's important to remember that, especially with Linux, there are often
many ways to solve problems.

To address the OP's question, a script like this would be a good
starting point. It would have to be rewritten it to read the next
keypress (with read) and then use wmctrl invocations (probably in a case
statement) to perform the desired actions.

Joe
> send an email to autokey-user...@googlegroups.com
> <mailto:autokey-user...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "autokey-users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to autokey-user...@googlegroups.com
> <mailto:autokey-user...@googlegroups.com>.

Joe

unread,
Sep 25, 2016, 3:28:05 PM9/25/16
to autoke...@googlegroups.com
I'm not sure how to do this nicely from within AutoKey.

It's probably not too difficult to write Python code inside your macro
to read the next keypress from the keyboard, but I've never done it.

What you can do, without that sort of coding, is to open an input dialog
using the AutoKey API (using input_dialog() or list_menu() ).

See: http://autokey.sourceforge.net/apidoc/frames.html

I had a simple example of this, but can't find it now.

You probably can't use straight bash as you attempted because stdin and
stdout don't go where you think they do when you're using a gui.

What you may be able to do instead (untested), is to run a gui
interaction program like kdialog, zenity, or yad to get your input from
the the gui and return the input to your script.

Let us know how you are progressing. We'll try to help if you get stuck.

Joe

Steve Fisher

unread,
Sep 25, 2016, 3:36:09 PM9/25/16
to autoke...@googlegroups.com
I wonder which desktop environment the OP uses...

A lot of what he wants can be easily done from the keyboard settings.  Like you I am not a python programmer.


To unsubscribe from this group and stop receiving emails from it, send an email to autokey-users+unsubscribe@googlegroups.com <mailto:autokey-users+unsubscri...@googlegroups.com>.

For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "autokey-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to autokey-users+unsubscribe@googlegroups.com.

Joe

unread,
Sep 25, 2016, 3:50:58 PM9/25/16
to autoke...@googlegroups.com
On 09/25/2016 03:36 PM, Steve Fisher wrote:
> I wonder which desktop environment the OP uses...
>
> A lot of what he wants can be easily done from the keyboard settings.
> Like you I am not a python programmer.
<soapbox>
That's why I wrote the problem reporting guide
https://github.com/autokey/autokey/wiki/Problem-Reporting-Guide
and often refer people to
http://catb.org/~esr/faqs/smart-questions.html

Almost everyone unconsciously assumes we're looking over their shoulder
and know exactly what their setup is and what they did.

When they give us that information to start with, we can be more sure
we're answering the real question and get to a solution much more quickly.
</soapbox>

Joe
>
>
> On 25 September 2016 at 20:28, Joe <jos...@main.nc.us
> <mailto:jos...@main.nc.us>> wrote:
>
> I'm not sure how to do this nicely from within AutoKey.
>
> It's probably not too difficult to write Python code inside your
> macro to read the next keypress from the keyboard, but I've never
> done it.
>
> What you can do, without that sort of coding, is to open an input
> dialog using the AutoKey API (using input_dialog() or list_menu() ).
>
> See: http://autokey.sourceforge.net/apidoc/frames.html
> <http://autokey.sourceforge.net/apidoc/frames.html>
>
> I had a simple example of this, but can't find it now.
>
> You probably can't use straight bash as you attempted because
> stdin and stdout don't go where you think they do when you're
> using a gui.
>
> What you may be able to do instead (untested), is to run a gui
> interaction program like kdialog, zenity, or yad to get your input
> from the the gui and return the input to your script.
>
> Let us know how you are progressing. We'll try to help if you get
> stuck.
>
> Joe
>
>
> On 09/25/2016 09:54 AM, kiikr...@gmail.com
> autokey-user...@googlegroups.com
> <mailto:autokey-users%2Bunsu...@googlegroups.com>
> <mailto:autokey-user...@googlegroups.com
> <mailto:autokey-users%2Bunsu...@googlegroups.com>>.
> For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "autokey-users" group.
> To unsubscribe from this group and stop receiving emails from it,
> send an email to autokey-user...@googlegroups.com
> <mailto:autokey-users%2Bunsu...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "autokey-users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to autokey-user...@googlegroups.com
> <mailto:autokey-user...@googlegroups.com>.

kiikr...@gmail.com

unread,
Sep 30, 2016, 5:55:51 AM9/30/16
to autokey-users
Thank you for your advice and information.  You have answered my main question.  If I understand correctly, then, although Autokey can read mouse clicks and insert keystrokes, it cannot read keystrokes.

This was not clear from the documentation, which of course only shows what Autokey *can* do and not necessarily what it *cannot* do, so I combed through the entire documentation to see.  There was nothing about reading keystrokes, but I wanted to be sure.

Thanks for the script using wmctrl and xdotool.  I found other similar scripts, but hadn't actually assembled one of my own yet.  Previously under KDE3, one could assign multiple keystroke sequences (e.g. Super-W,E for launching editor) but lost this capability when I migrated to KDE4.  (Yes, under certain limited circumstances, KDE4 can do multi-key sequences, but not a global shortcut to launch a program.)  As you allude to, the altered behaviour of stin that prevents bash from functioning as it would in a terminal environment also seems to affect the use of Python's input() and raw_input() functions to sense the keystrokes, which was the first thing I attempted in trying to solve this problem.

Having utmost respect for Mr. E.S.Raymond, I have read http://catb.org/~esr/faqs/smart-questions.html several times (part of what drew me toward the FLOSS movement), but while I would agree that "Almost everyone unconsciously assumes we're looking over their shoulder and know exactly what their setup is and what they did," I didn't give details because I was more asking about the capabilities of AutoKey and didn't think that would be affected by the details of my OS environment.  Also, specifying a more generalized question about draw more of a response from those who might not be (and might not need to be) familiar with my specific situation.   In fact, this question is part of my exploration into which GUI automation system I might want to invest my time in.  I'm happy to elaborate on the context of my question.

For a long time, my work environment has used a Windows-only program, forcing me into a Windows environment under which, thankfully, I discovered AutoHotkey, the open source GUI automatino system which makes Windows bearable.  It has developed quite an ecosystem of scripts, and with it I finally feel that I have control over my own computer and am no longer at the whim of programs that steal the focus, pop-up warning windows, and make me use the mouse when it would be so much more efficient to touch-type on the keyboard.

More recently, the work environment has changed so that we are using web-only systems, and now here is my chance to use the same Linux environment at work that I use at home.  The only problem is that I now rely on the AutoHotkey scripts that I've slowly developed over the years (60,000 lines of code so far).  Having explored xdotool when it first came out, and having checked periodically the progress of IronAHK ("AutoHotkey for Linux"), I've returned after some absence to see the gratifying presence of AutoKey.  It looks promising, and while I recognize that it might not have yet developed the same level of sophistication as the long-running AutoHotkey project, its basis in Python and its compatibility with Linux (well, the X windowing environment, more accurately) make it very attractive.  I took to attempting to reproduce some of the more basic functions of my AutoHotkey scripts to check it out.  Sensing a key is one of my basic needs simply because there are so many different functions that I want to trigger that I'm going to run out of hotkey triggers unless I use key sequences.  Besides, I don't want to conflict with some of the other already-assigned keys -- e.g. Alt-F4 will be forever to me the key to close windows, and is not available to run my scripts (of which I've about 60-70 under AutoHotkey.

I did look into using input_dialog() etc. as Joe suggests, but as far as I can tell, these will require more than one keypress to select (i.e. choose and then press Enter).  I might be wrong; I'll revisit it.  But I want a simple key sequence to switch that will not interrupt my train of thought; e.g. say I'm in Firefox, and then I press Super-W E to switch to the editor, and then after a few keystrokes I press Super-W B to switch to the bash console.  I want it to be as intuitive as Alt-Tab to swap between windows, and not necessarily have a window pop up: "What do you want to do now?" and then have me have to read which choice I want, and then type [Down][Down][Down][Enter].

I did read "https://github.com/autokey/autokey/wiki/Problem-Reporting-Guide".  When I better understand the capabilities of AutoKey and know what I should or should not expect it to do, I'll make sure I use this format to ask for help with programming bugs.

I also plan to take a look at AutoPy, one of the advantages of which is that it will work for Windows as well as Linux, so I might be able to use it on multiple platforms and save me some time.  Not sure it will do what I need, but sometime later I'll get around to looking at it.  At the current time, because of my busy schedule, I can only afford a small amount of time every once in a long while to devote to looking for long-term solutions to my GUI needs, so I'm grateful that you folks are willing to respond to my queries when I am not able to glean the information from the documentation.

I trust that I've answered Mr. Fisher's question about what OS / Desktop environment I use.
>         <mailto:autokey-users%2Bunsu...@googlegroups.com>>.
>         For more options, visit https://groups.google.com/d/optout
>         <https://groups.google.com/d/optout>.
>
>
>     --
>     You received this message because you are subscribed to the Google
>     Groups "autokey-users" group.
>     To unsubscribe from this group and stop receiving emails from it,
>     send an email to autokey-user...@googlegroups.com
>     <mailto:autokey-users%2Bunsu...@googlegroups.com>.
>     For more options, visit https://groups.google.com/d/optout
>     <https://groups.google.com/d/optout>.
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "autokey-users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to autokey-user...@googlegroups.com

Joe

unread,
Sep 30, 2016, 11:38:44 PM9/30/16
to autoke...@googlegroups.com
Thanks for the very detailed reply.

Here are a bunch of separate issues that I didn't feel like putting inline.

Documentation: Well, we do have some ... <G> We could use a lot more.

While AutoKey is supposed to do mouse stuff (and did at one time), this
functionality is currently broken in this branch. We had a developer fix
most of it, but he didn't finish the work before he had to leave the
project. I am told that this does work in the autokey.py3 branch, but I
haven't tried it yet. I even found some reference to the xautomation
project over there, so he may even have integrated some graphic
recognition stuff for use in positioning the cursor.

As far as asking for too much information from you, it's pretty much
Damned if you do, damned if you don't. Sometimes it's critical to know
and sometimes it's none of your business (and I've been told that before
on stackexchange. -> It's not an XY problem, I know what I'm doing and I
asked exactly what I needed to know!)

My suggestion for using input_dialog() was as "better than nothing". I
knew it wouldn't be nice.

When working with AutoKey macros, I often use the trace for myself so I
can see things from AutoKey's perspective. It's not just for problem
reporting.

60.000 lines of macros is frankly intimidating! Sounds more like you
wrote your own IDE. Wow. Please share some of it with us once you get it
working in AutoKey.

Since it sounds like you may know Python, I looked into this further,
but I'm out of my depth with the answers I found.

This is an interesting problem which seems to have been solved, but,
apparently, it's not simple.

I did a duckduckgo search for

python linux detect gui keypress

and came up with a lot - including the following. The last one looks
most promising. In it, you need to search down to the answer by Ankit
Daftery for a solution that doesn't hang (block) waiting for a keypress.

Of course, you have to handle the case where the input doesn't match one
of your triggers. You probably don't want those keypresses to be
swallowed by your code.

http://stackoverflow.com/questions/13713347/detect-specific-keypresses-in-gui

http://stackoverflow.com/questions/24072790/detect-key-press-in-python

https://www.reddit.com/r/Python/comments/3j4vtd/way_to_detect_keypress_in_python_without/

https://docs.python.org/2.7/library/tkinter.html

http://code.activestate.com/recipes/134892-getch-like-unbuffered-character-reading-from-stdin/
Search for Ankit Daftery for an unblocking method.

If you do get this to work, please tell us. I think a lot of people
could use it.

Joe
> <http://catb.org/%7Eesr/faqs/smart-questions.html>
>
> Almost everyone unconsciously assumes we're looking over their
> shoulder
> and know exactly what their setup is and what they did.
>
> When they give us that information to start with, we can be more sure
> we're answering the real question and get to a solution much more
> quickly.
> </soapbox>
>
> Joe
> >
> >
> > On 25 September 2016 at 20:28, Joe <jos...@main.nc.us <javascript:>
> > On 09/25/2016 09:54 AM, kiikr...@gmail.com <javascript:>
> > autokey-user...@googlegroups.com <javascript:>
> > <mailto:autokey-users%2Bunsu...@googlegroups.com
> <javascript:>>
> > <mailto:autokey-user...@googlegroups.com
> <javascript:>
> > <mailto:autokey-users%2Bunsu...@googlegroups.com
> <javascript:>>>.
> > For more options, visit
> https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>
> > <https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>>.
> >
> >
> > --
> > You received this message because you are subscribed to the
> Google
> > Groups "autokey-users" group.
> > To unsubscribe from this group and stop receiving emails
> from it,
> > send an email to autokey-user...@googlegroups.com <javascript:>
> > <mailto:autokey-users%2Bunsu...@googlegroups.com
> <javascript:>>.
> > For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>
> > <https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>>.
> >
> >
> > --
> > You received this message because you are subscribed to the Google
> > Groups "autokey-users" group.
> > To unsubscribe from this group and stop receiving emails from
> it, send
> > an email to autokey-user...@googlegroups.com <javascript:>
> > <mailto:autokey-user...@googlegroups.com <javascript:>>.
> > For more options, visit https://groups.google.com/d/optout
> <https://groups.google.com/d/optout>.
>
> --
> You received this message because you are subscribed to the Google
> Groups "autokey-users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to autokey-user...@googlegroups.com
> <mailto:autokey-user...@googlegroups.com>.

Theo Ret

unread,
Dec 29, 2016, 4:01:47 PM12/29/16
to autokey-users
Hello,

I have also been using Autohotkey a lot and now I am looking for an alternative of Autohotkeys "input" function with Autokey.

After some research I found the useful python module "pyxhook":
https://github.com/JeffHoogland/pyxhook

This works fine for me. If you follow the guthub link you can find an easy introductory example of how to use pyxhook.

I have now defined my own class (still in progress):

import pyxhook, time

class keyhook:
    """ Listens until number of keys is maxkeys
    or until one of the endkeys is pressed
    or until maxtime is reached
    or until the self-defined function condfunc returns any value, which is taken to be the exitcode. Condfunc can optionally have 1 argument which will be replaced by self. This way condfunc can depend on the already pressed keys.
    The pressed keys are stored in the list 'self.keys'.
    """

    def __init__(self, maxkeys=1, endkeys=[],condfunc=lambda:None, maxtime=10, timestep=0.1,):
        self.maxkeys=maxkeys
        if (type(endkeys) is not list):
            endkeys=[endkeys]
        self.endkeys=endkeys
        self.maxtime=maxtime
        self.timestep=timestep
        #support for 0 and 1 arguments in condfunc:
        if condfunc.__code__.co_argcount == 0:
            condfunc2=lambda self:condfunc()
            #condfunc2(self) will ignore the self argument in this case.
        else:
            condfunc2=condfunc
       
        self.time=0
        self.keynumber=0
        self.keys=[]
       
        self.hm = pyxhook.HookManager()
        self.hm.KeyDown = self.kevent
        self.hm.HookKeyboard()       
       
        self.exitcode="active"
        self.hm.start()       
        while self.exitcode == "active":
                time.sleep(self.timestep)
                self.time += self.timestep
                if self.time >= self.maxtime:
                    self.exitcode="timeout"
                   
                c = condfunc2(self)
                if c != None:
                    self.exitcode=c
        self.hm.cancel()

    def kevent(self, event):
        k = event.Key
        self.keys.append(k)
        self.keynumber += 1
        if self.keynumber == self.maxkeys:
            self.exitcode="maxkeys"
        if k in self.endkeys:
            self.exitcode="endkey"
           
           
           
# Testing:          
def f(self):
    if (len(self.keys)>1) and (self.keys[:2]==["a","a"]):
        return("two times a pressed")
test=keyhook(5,["Return","F2","space"],f)
print(test.keys)
print(test.exitcode)




The only problem left: I want to stop the input from being sent to the current window while the keyhook is active.
Do you have an idea how to do this?
My ideas:
- open an invisible window to catch the input and keep it focused
- do something with the python xlib module
- maybe use some built-in autokey function
But I have no idea how to do these things elegantly.

Joe

unread,
Dec 29, 2016, 4:57:53 PM12/29/16
to autoke...@googlegroups.com
Welcome to the list, Theo.

While this looks intriguing (and very useful), it's way beyond my quite
minimal understanding of Python.

You may be able to find some help here:

https://stackoverflow.com/questions/tagged/autokey ...

Please do post back here with any progress you make.

And, if you can, please stick around this list. We really need someone
who actually knows some Python! I answer the really simple Python
questions - looking things up as I go.

Joe
Message has been deleted
Message has been deleted

Theo Ret

unread,
Jan 3, 2017, 6:50:16 PM1/3/17
to autokey-users
Thanks for the welcome!

I have just started to learn python three months ago and I use autokey as a very useful  training opportunity.

If you want to understand my code, take a look at this example about pyxhook from the github page:

"""
A simple example of hooking the keyboard on Linux using pyxhook

Any key pressed prints out the keys values, program terminates when spacebar
is pressed.
"""
from __future__ import print_function

# Libraries we need
import pyxhook
import time


# This function is called every time a key is presssed
def kbevent(event):
   global running
   # print key info
   print(event)

# If the ascii value matches spacebar, terminate the while loop
if event.Ascii == 32:
   running = False


# Create hookmanager
hookman = pyxhook.HookManager()
# Define our callback to fire when a key is pressed down
hookman.KeyDown = kbevent
# Hook the keyboard
hookman.HookKeyboard()
# Start our listener
hookman.start()

# Create a loop to keep the application running
running = True
while running:
   time.sleep(0.1)

# Close the listener when we are done
hookman.cancel()




This is all you need to understand for using pyxhook. My class is then just adding a lot of conditions for when to end the keyhook and where to save the pressed keystrokes, as well as making it possible to call the keyhook with a single command. I recommend learning how class definitions, instance objects and namespaces work in Python, if you find the time and if you haven't done that yet. These structures are used in almost all modules I know and can make your life much easier in cases like this.

Theo Ret

unread,
Jan 3, 2017, 6:52:12 PM1/3/17
to autokey-users
And yes, I will post back here, when I have come up with a final version of my keyhook class. I have already implemented more features.
Reply all
Reply to author
Forward
0 new messages