Please mind that I am completely green in Python and I do not know how callbacks work in this language.
I have been trying for some time to solve my problem, but I cannot figure out what to do.
I have the problem with using callbacks in Python. I use the Python keyboard module to listen to keys pressed on a machine.
When I try to use the keyboard.hook() method, it asks me for a callback. I know how callbacks work, but as long as Python is not my main language I can't really figure out what to do with it.
In JavaScript it's as easy as naming a parameter in a function then printing that parameter. Easy as that.
import keyboard
keyboard.hook()
## How to print keys?
In the official documentation, it is written that the hook() method invokes a callback. How do I access this callback and most importantly print keys which are recorded from it? I just need a simple example then I will be able to remember it forever.
Any help really appreciated.
You can pass a function just like you would a variable—by passing its name to the hook() method.
Then, per the docs on keyboard.hook(), it calls your callback with a keyboard.KeyboardEvent with three fields:
name: an Unicode representation of the character (e.g. "&") or description (e.g. "space"). The name is always lower-case.
scan_code: number representing the physical key, e.g. 55.
time: timestamp of the time the event occurred, with as much precision as given by the OS.
So, putting it together, you can use it like this:
import keyboard
def my_keyboard_hook(keyboard_event):
print("Name:", keyboard_event.name)
print("Scan code:", keyboard_event.scan_code)
print("Time:", keyboard_event.time)
keyboard.hook(my_keyboard_hook)
# Block forever, so that the program won't automatically finish,
# preventing you from typing and seeing the printed output
keyboard.wait()
And each time a key is pressed, you'll print the details of the keyboard event.
Note that the keyboard.wait() call is not necessary if your program would otherwise continue running—I just wanted to make sure that you didn't run the example code, see it terminate immediately, and then think something went wrong.
Something like this appears to be what you want from the documentation.
def keyHook(info):
print(info)
keyboard.hook(keyHook)
Related
So I have 2 files, fish_life_simulator.py and menu.py. fish_life_simulator.py is the main file and executes other files like menu.py depending on what happens. So here is the code and how it should work:
import os
os.chdir(os.path.dirname(__file__))
result = exec(open(r'menu.py', encoding='utf-8').read())
print(result)
So at first when the code arrives to result = exec(open(r'menu.py', encoding='utf-8').read()) it executes menu.py and all is fine, but it could stop for several reasons:
The player exit the game
The player entered settings
The player pressed play
So what I decided to do, is when menu.py will stop running it will return a value, like 1, 2 or 3, so I tried several methods that have been included in here:
Best way to return a value from a python script
like using return or sys.exit("some value here"), but even though I did the part inside of menu.py, neither of them worked, as when I tried return, result from result = exec(open(r'menu.py', encoding='utf-8').read()) always was None for some reason and when I tried sys.exit(1) for example, result didn't get printed at all, so I was just wandering if it was something I was missing inside of fish_life_simulator.py, because the part with sending the value should be fine, but the part of receiving it is problematic.
Just define a function in menu.py:
def do_stuff_in_menu():
...
return result
and in fish_life_simulator.py you just call that function:
import menu
result = menu.do_stuff_in_menu()
print(result)
I agree with everyone who says exec() is not the best way to do this, however, since that's not your question, here's an answer for you.
The exec() function always returns None (see docs). If you need the return code, you could use os.system() or one of the various methods from the subprocess library. Unlike exec(), however, both of these alternatives would create a child process.
That said, I personally would not use any of those methods, but would instead modify menu.py to allow you to import it. It's much more natural and direct.
I am getting a segmentation fault when initializing an array.
I have a callback function from when an RFID tag gets read
IDS = []
def readTag(e):
epc = str(e.epc, 'utf-8')
if not epc in IDS:
now = datetime.datetime.now().strftime('%m/%d/%Y %H:%M:%S')
IDS.append([epc, now, "name.instrument"])
and a main function from which it's called
def main():
for x in vals:
IDS.append([vals[0], vals[1], vals[2]])
for x in IDS:
print(x[0])
r = mercury.Reader("tmr:///dev/ttyUSB0", baudrate=9600)
r.set_region("NA")
r.start_reading(readTag, on_time=1500)
input("press any key to stop reading: ")
r.stop_reading()
The error occurs because of the line IDS.append([epc, now, "name.instrument"]). I know because when I replace it with a print call instead the program will run just fine. I've tried using different types for the array objects (integers), creating an array of the same objects outside of the append function, etc. For some reason just creating an array inside the "readTag" function causes the segmentation fault like row = [1,2,3]
Does anyone know what causes this error and how I can fix it? Also just to be a little more specific, the readTag function will work fine for the first two (only ever two) calls, but then it crashes and the Reader object that has the start_reading() function is from the mercury-api
This looks like a scoping issue to me; the mercury library doesn't have permission to access your list's memory address, so when it invokes your callback function readTag(e) a segfault occurs. I don't think that the behavior that you want is supported by that library
To extend Michael's answer, this appears to be an issue with scoping and the API you're using. In general pure-Python doesn't seg-fault. Or at least, it shouldn't seg-fault unless there's a bug in the interpreter, or some extension that you're using. That's not to say pure-Python won't break, it's just that a genuine seg-fault indicates the problem is probably the result of something messy outside of your code.
I'm assuming you're using this Python API.
In that case, the README.md mentions that the Reader.start_reader() method you're using is "asynchronous". Meaning it invokes a new thread or process and returns immediately and then the background thread continues to call your callback each time something is scanned.
I don't really know enough about the nitty gritty of CPython to say exactly what going on, but you've declared IDS = [] as a global variable and it seems like the background thread is running the callback with a different context to the main program. So when it attempts to access IDS it's reading memory it doesn't own, hence the seg-fault.
Because of how restrictive the callback is and the apparent lack of a buffer, this might be an oversight on the behalf of the developer. If you really need asynchronous reads it's worth sending them an issue report.
Otherwise, considering you're just waiting for input you probably don't need the asynchronous reads, and you could use the synchronous Reader.read() method inside your own busy loop instead with something like:
try:
while True:
readTags(r.read(timeout=10))
except KeyboardInterrupt: ## break loop on SIGINT (Ctrl-C)
pass
Note that r.read() returns a list of tags rather than just one, so you'd need to modify your callback slightly, and if you're writing more than just a quick script you probably want to use threads to interrupt the loop properly as SIGINT is pretty hacky.
Im trying to get wifite (https://github.com/derv82/wifite) working on my 16x2 Adafruit LCD (http://www.adafruit.com/product/1110).
But for some Reason, if I press the specified button nothing happens.
I want to replace all pieces of code that look like this:
try
....
except KeyboardInterrupt:
....
With the code for the LCD Buttons:
try
....
except lcd.buttonPressed(lcd.SELECT):
....
But for some reason nothing happens if I press the button, I don't get a error - And wifite just keeps doing it's thin.
Any Idea why this isn't working how it should ?
Or is there maybe a better way ?
As others have pointed out except KeyboardInterrupt ... is a special construct in Python ... because a [Ctrl]-[C] is handled by your terminal driver and presents an "Interrupt" signal to your program (SIGINT under Unix, Linux and similar operating systems). (There is similar handling under Microsoft operating systems, with different details and slightly different terminology; but the Python code works the same either way.
There are other ways of accessing various other forms of hardware event ... and the Python exception module is not a typical way for those to be implemented.
In the case of the AdaFruit, or other Rasberry Pi devices, you'd use the modules they include with their package. You've already seen it, and presumably done the required import in your code (based on your reference to lcd.buttonPressed()). The problem is that this isn't how you use that function at all.
Read this carefully: https://blog.soton.ac.uk/pi/modules-available/adafruit-rgb-lcd-display/
... it includes example which show how you should be using it. That should be something like:
#!python
# Set up stuff here ...
got_event = False
while not got_event:
if lcd.buttonPressed(lcd.SELECT)
got_event = True
break
# Do other stuff, perhaps
# Or time.sleep(0.1)?
if got_event:
# In case we had other exit conditions from doing other stuff?
subprocess.call(YOUR_OTHER_PROGRAM)
Of course their code is a complete running program. I'm only highlighting a couple of points here. You need to loop around until you get the event your looking for (or loop around forever processing these events for as long as your device is up).
The lcd.buttonPressed() method is checking to see if the button has been pressed since the last time it was cleared; but the method/function doesn't block ... it returns True or False (or possibly None --- that wouldn't affect these code examples --- any "false" value means the button has not been pressed).
You want to sleep for some amount of time between checks. They use a half second delay in their example; I used a tenth of a second. (People will typically perceive a response within a tenth of a second from a computerized device as "instantaneous" while a half second delay will, typically, be slightly annoying). Checking as fast as you can will just needlessly heat up the electronics. Even a 0.01 (one hundredth of a second) sleep is sufficient ... but 0.05-0.1 are probably the best practice for something like this.
If I understand correctly, you want to have one of the buttons on the Adafruit LCD panel interrupt the program at almost any stage. (It would have been great if you'd mentioned this yourself!)
KeyboardInterrupt is a signal sent to a process, usually when a user presses Ctrl + c on a keyboard. To be more precise, a signal is sent by the OS and caught by the Python runtime, which raises a KeyboardInterrupt exception.
However, Ctrl + c is special! In almost any other case, when a user presses a key or a button, this is not translated into a special signal.
I'm not sure how you could get the behavior you want; this may depend quite a bit on the operating system you are using.
What you need is event detection try something like this. You might have to get familiar with Tkinter
from Tkinter import *
root = Tk()
def callback_end(event)
# do whatever ending procedure you want here
quit()
def main()
# do everything in your main code here
if lcd.buttonPressed(lcd.SELECT):
callback_end("<End>")
root.after(Period,main)
root.bind("<End>",callback_end) # if you press the end key it will call the callback_end function
root.after(Period,main) # repeats main every Period in miliseconds
root.mainloop()
I realize that this is not a complete answer but I hope it gets you going in the right direction
I am trying to make a program which has a raw_input in a loop, if anyone presses a key while the long loop is running the next raw_input takes that as input, how do I avoid that?
I don't know what else to add to this simple question. Do let me know if more is required.
EDIT
Some code
for i in range(1000):
var = raw_input("Enter the number")
#.... do some long magic and stuff here which takes afew seconds
print 'Output is'+str(output)
So if someone presses something inside the magic phase, that is take as the input for the next loop. That is where the problem begins. (And yes the loop has to run for 1000 times).
This works for me with Windows 7 64bit, python 2.7.
import msvcrt
def flush_input():
while msvcrt.kbhit():
msvcrt.getch()
I put the OS in the title, window 7 64 bit to be specific. I saw the
answers there. They do apply but by god they are so big. Aren't there
other n00b friendly and safer ways to take inputs?
Let me try to explain why you need to do such an elaborate process. When you press a key it is stored in a section of computer memory called keyboard buffer (not to be confused with stdin buffer). This buffer stores the key's pressed until it is processed by your program. Python doesn't provide any platform independent wrapper to do this task. You have to rely on OS specific system calls to access this buffer, and flush it, read it or query it. msvcrt is a MS VC++ Runtime Library and python msvcrt provides a wrapper over it. Unless you wan't a platform independent solution, it is quite straight forward.
Use msvcrt getch to read a character from console. msvcrt.kbhit() to test if a key press is present in the keyboard buffer and so on. So as MattH has shown, it just a couple of lines code. And if you think you are a noob take this opportunity to learn something new.
Just collect your input outside of the loop (before you enter the loop). Do you really want the user to enter 1000 numbers? well maybe you do. but just include a loop at the top and collect the 1000 numbers at the start, and store them in an array.
then on the bottom half change your loop so it just does all the work. then if someone enters something no the keyboard, it doesn't really matter anymore.
something like this:
def getvars(top=1000):
vars = []
for i in range(0,top):
anum = int(raw_input('%d) Please enter another number: ' % i))
vars.append(anum)
return vars
def doMagic(numbers):
top = len(numbers)
for number in numbers:
# do magic number stuff
print 'this was my raw number %s' % number
if __name__ == "__main__":
numbers = getvars(top=10)
doMagic(numbers)
presented in a different sort of way and less os dependent
There is another way to do it that should work. I don't have a windows box handy to test it out on but its a trick i used to use and its rather undocumented. Perhaps I'm giving away secrets... but its basically like this: trick the os into thinking your app is a screensaver by calling the api that turns on the screensaver function at the start of your magic calculations. at the end of your magic calculations or when you are ready to accept input again, call the api again and turn off the screensaver functionality.
That would work.
There is another way to do it as well. Since you are in windows this will work too. but its a fair amount of work but not really too much. In windows, the window that is foreground (at the top of the Z order) that window gets the 'raw input thread'. The raw input thread receives the mouse and keyboard input. So to capture all input all you need to do is create a function that stands up a transparent or (non transparent) window that sits at the top of the Z order setWindowPos would do the trick , have it cover the entire screen and perhaps display a message such as Even Geduld or Please wait
when you are ready to prompt the user for more input, you use showwindow() to hide the window, show the previous results, get the input and then reshow the window and capture the keys/mouse all over again.
Of course all these solutions tie you to a particular OS unless you implement some sort of try/except handling and/or wrapping of the low level windows SDK calls.
I defined an handler for EVT_IDLE that does a certain background task for me. (That task is to take completed work from a few processes and integrate it into some object, making a visible change in the GUI.)
The problem is that when the user is not moving the mouse or doing anything, EVT_IDLE doesn't get called more than once. I would like this handler to be working all the time. So I tried calling event.RequestMore() at the end of the handler. Works, but now it takes a whole lot of CPU. (I'm guessing it's just looping excessively on that task.)
I'm willing to limit the number of times the task will be carried out per second; How do I do that?
Or do you have another solution in mind?
Something like this (executes at most every second):
...
def On_Idle(self, event):
if not self.queued_batch:
wx.CallLater(1000, self.Do_Batch)
self.queued_batch = True
def Do_Batch(self):
# <- insert your stuff here
self.queued_batch = False
...
Oh, and don't forget to set self.queued_batch to False in the constructor and maybe call event.RequestMore() in some way in On_Idle.
This sounds like a use case for wxTimerEvent instead of wxIdleEvent. When there is processing to do call wxTimerEvent.Start(). When there isn't any to do, call wxTimerEvent.Stop() and call your methods to do processing from EVT_TIMER.
(note: i use from wxWidghets for C++ and am not familiar with wxPython but I assume they have a similar API)