Capturing key events in the linux console - linux

I have a problem, that is similar to a lot of other's before me, but different in a way that makes it much more difficult. :)
I'm writing a text editor for the Linux console. There is no X11 running, so forget about any toolkit for that. I want to capture key down and key-up events as I want to be able to mark sections of text by holding down shift and using the arrow keys (much like you would in an X-based or Windows-based editor).
I've previously managed to write an application that uses raw mode to access key scancodes, but it is unable to handle detecting shift key and arrow keys at the same time.
Does anyone have an example code that is able to detect any key combinations (or at least all combinations with shift, ctrl and alt).

How about using ncurses, which does all that for you? It also helps you with figuring out how to format text for the particular terminal type you're connected with and so on.
Using the getkey() function the python binding provide, I am able to find out modifiers for different keys. I also found out that for Shift+Arrow keys, there is a separate key code, abbreviated with KEY_SR, KEY_SF for up and down and KEY_SLEFT and KEY_SRIGHT.
import curses
import curses.textpad
import curses.ascii
def decodeSuffix(i):
return {
0b110: ( True, True, False),
0b100: ( True, False, True),
0b111: (False, True, True),
0b101: (False, True, False),
0b011: (False, False, True),
}[i]
def test(stdscr):
while True:
k = stdscr.getkey()
if k == "\n":
return
elif k[0] == "k" and len(k) > 1:
i = int(k[-1])
shift, ctrl, alt = decodeSuffix(i)
s = ""
if shift:
s += "shift "
if ctrl:
s += "ctrl "
if alt:
s += "alt "
s += k[1:-1]
stdscr.addstr("{0:40s} {1:08b}\n".format(s, i))
else:
stdscr.addstr("{0}\n".format(k))
pass
curses.wrapper(test)
You may play around with that. Looking at the source of getkey(), we find that it's basically a combination of getch and keyname curses functions.

I have sort of managed to do what I set out to do. The only problem is it requires that I connect directly to the keyboard driver. Right now I do not know how to do that without root privileges, so my editor requires root. This could be awkward.
In short, I open the /dev/input/event? stream, where ? is the number of the keyboard driver (most often 0) and capture the key-presses from there. This is really only useful for checking the state of a key (by building a key-state from the down and up-press events) since the events are delivered from all applications (this is after all the keyboard driver).
It is better to get all other key-presses from a more conventional source and just use the keyboard driver for CTRL, SHIFT and so on.
I'll post code later if I get it to work together. :)

Related

How do I programmatically change the note type of a note?

I'm currently trying to develop an Anki addon that changes the note type of a card when in the card browser.
To accomplish this, I'm initially hooking into the editor shortcuts via aqt.gui_hooks.editor_did_init_shortcuts.append(), then adding a shortcut that sends a callback to another function, passing in aqt.editor.Editor into a function
the problem is I'm now having a hard time changing the note type of the card.
I've tried editor.note.note_type = mw.col.models.by_name(note_type), but it doesn't seem to change anything.
I've looked at other anki extensions, but it seems they change the note_type by modifying the notetype_chooser.selected_note_type_id field of aqt.addcards, which is not found in aqt.editor.Editor
here's the code I have so far:
def editor_switch_note_card_type(editor: aqt.editor.Editor, note_type: str):
# doesn't do anything
editor.note.note_type = mw.col.models.by_name(note_type)
# does something
editor.note['Front'] += 'hello world'
# not sure if this does anything
mw.col.update_note(editor.note)
# editor_init_shortcuts binds editor_switch_note_card_type to a shortcut key when editor is focused
aqt.gui_hooks.editor_did_init_shortcuts.append(editor_init_shortcuts)

How to personalize PF key assignments in Control-M?

Control-M's ISPF client in zOS (mainframe) comes with a set of predefined values assigned to PF keys (function keys), such as:
PF2 = SPLIT
PF9 = SWAP
However, similar to other ISPF applications, I'd like to change the values of those PF keys (and a few others, such as PF2 = RETURN) like so:
PF2 = SPLIT NEW
PF9 = SWAP NEXT
And trying to use standard ISPF's primary command "PFKEYS" "KEYS" (typo, pointed out in first answer), via which you can adapt the values of your PF keys, doesn't seem to work for Control-M either (you only get error message "UNRECOGNIZED COMMAND", no matter on which screen you try this command).
Any suggestions about how to change those values for PF2 and PF9 anyhow?
PFKEYS is not a valid ISPF command. The proper commands to access the ISPF PF Key Definitions and Labels dialog are KEYS for context sensitive key assignments or ZKEYS for global key assignments.
Navigate into Control-M, then use the KEYS command to launch the dialog and assign the desired function key commands. You may need to explicitly enter the SAVE command to commit your key assignment changes to your profile (although PF3 should invoke an END, which includes a SAVE).
Subsequently, PFSHOW (or the short version, FKA) will add an "infobar" of sorts to your panel that shows the PF keys, and either the defined label or the first 8 chars of the command that is currently assigned to each function key. Enter PFSHOW OFF (or FKA OFF) to remove this display.
The KEYLIST ON/OFF command can be used to switch between default and custom key assignments for some product panels. Enter the KEYLIST command with no arguments to see if options are available. FWIW... I don't have access to Control-M, but our installation of other BMC products does not include custom keylists.
Some PFkey errors can be attributed to installation procedures that do not include the appropriate members in logon procs. For Control-M, these members appear to be CMTCMDS and/or CMTUCMDS. The sysadmins responsible for installing the product would likely need to address this type of issue. However, the issue described here provides no indication of an installation problem.

I cannot send keystrokes to a selected input box

from pywinauto.application import Application
app = Application().Start(cmd_line=u'"path to program" ')
afx = app[u'Afx:01360000:0']
afx.Wait('ready')
afxtoolbar = afx[u'1']
toolbar_button = afxtoolbar.Button(3)
toolbar_button.Click()
window = app.Dialog
window.Wait('ready')
edit = window.Edit4
edit.Click()
app.typekeys ("Success")
So at this point, I've gotten the application to open, the correct window to pop up and also a mouse click on the box that I want to populate with a short string. I cannot for the life of me, figure out how to pass keyboard input to this field. I have read all the docs for PyWinAuto, and nothing is helping...
Basically all I need to do is figure out how to send a string, and then how to send the TAB key six times. I can then finish my program to automate this application.
I am also using Swapy64bit to help. The program uses a win32 backend. I'm using Python 3.6.
Am I not prefixing typekeys correctly? The PyWinAuto documentation leaves much to be desired.
First the correct name of the method is type_keys, but assume you use it correctly.
The reason might be losing focus at the edit control because type_keys tries to set focus automatically. The solution is:
app.type_keys("Success{TAB 6}", set_foreground=True)

Semantic guess the number game errors - Python3.x

I am 11 years old and am keen programmer learning Python.
1) I am programming a guess the number game and when I ask the user if they want to play again, I get a semantic error (I think this is the correct way to describe it) where if I input "no", "n", "NO" or "N", the if statement is still executed, causing the loop() function to run again, after calculating scores. Take a look at the following image (sorry about the cluttered windows).
Play again error: https://i.stack.imgur.com/TsEyw.png
Here is a link to the rest of the program:
https://gist.github.com/anonymous/f9be138e07c569b8721b990293d92314 (I only have 8 reputation points) , but I am looking at just this snippet:
def play_again():
again = input("\nWould you like to play again? y/n " + prompt)
if again.upper() == "Y" or "YES":
global gu_num
percent = gu_num * 10
score = 100 - percent
highscores = [{round: (score)}]
current_score = {round: (score)}
highscores.append(current_score)
print("Lets see if you can beat your score of " + str(current_score[round]) + ".\nHere we go!")
gu_num = 0
loop()
elif again.upper() == "N" or "NO":
print("Ok then.\nThank you for playing Guess The Number and I hope to see you again soon!\nThis game was created and devoloped by Kiran Patel (me), age 12. If you liked this game or want to talk to me about -->anything<--, please do email me at kiran#inteleyes.com. It'll make me happy! Thank you for playing Guess the number with me.\n\n program was developed by Kiran Patel in 2017 ad.")
input("\n\nPress the enter key to exit")
quit()
else:
print("Sorry, I don't understand. Please try again:")
play_again()
2) I'm having a similar problem with the part of my code which starts to handle files. When I input a 'no' (same if expression) the program will execute the part of that if statement which creates the file (take a look at this image: file saving result and this image: file operations code). Note that the 'file operations code' image prints out the file-save error message because I hadn't given perms to write in prog'/files folder. I know it has tried to save the file because of the error message that was printed out (I intended the error message to be printed out).
3) Also, does anyone know what #!/usr/bin/python means? I know its hashtagged out, but I have seen it before like this and I was wondering what it means.
As always, ANY help will
be appreaciated, so please don't hesitate on adding something that is not directly relevant to the question, because I may well have missed it (unless it is completely irrelevant).
Once again, thanks in advance for your help.
From Kiran
The problem is here (and on every line that looks like it):
if again.upper() == "Y" or "YES":
Here's what you (reasonably) assume it's doing (This is how you would fix it, btw):
if (again.upper() == "Y") or (again.upper() == "YES"):
Here's what it's actually doing:
if (again.upper() == "Y") or "YES":
So let's say that you typed Q at the prompt. As Python reads along the line, it sees the first comparison operator, ==, and compares just the two things on either side of it: "Q" and "Y". "Those are not equal", thinks Python, and moves on to the next part: comparing False - the answer to the first part - with "YES".
In Python, if something exists and isn't False or 0 or something similar, it gets treated as True. "False is False, but "YES" is a perfectly valid string", thinks Python. "and the or operator means that if either of these two things is True, the whole thing is True, so this must all be true and I should run this block of code now." And so it does, every time, no matter what you type.
As a general rule, when you're doing these kinds of tests, it's only safe to do one comparison at a time. Any more than that and it's time to bring in the parentheses.
Also, regarding #!/usr/bin/python: the #! is called a Shebang, and it's not part of Python at all - it's part of your operating system (assuming your operating system isn't Windows). It says to your OS: "This may look like an ordinary text file, but it's actually a script, which you should run using the program located at /usr/bin/python".

How to send "Ctrl + c" in Sikuli?

This feels like it should be pretty easy but I can't find documentation on how to do this:
I just want Sikuli to type Ctrl+C to copy text to the clipboard.
type(KEY_CTRL+'c') doesn't work and neither does type(KEY_CTRL,'c').
Any suggestions?
Try using type("c",KEY_CTRL) instead.
I wrote a simple script which types a line in notepad, double clicks it to mark it and then ctrl+x ctrl+v it into the document again. Works great.
openApp("notepad.exe")
find("textfield.png" )
type("Some text")
doubleClick("theText.png")
type("x", KEY_CTRL)
click("theTextField.png" )
type("v",KEY_CTRL)
The following works in 0.9 and newer versions of sikuli
type('x', KeyModifier.CTRL)
Key objects are defined for pretty much all the modifier keys and num pad keys. Anyways, it should look something like this
keyDown(Key.CTRL)
type('c')
keyUp(Key.CTRL)
The usage of type() and the possible key names are documented here:
http://doc.sikuli.org/region.html#Region.type
http://doc.sikuli.org/keys.html#key-constants
As others have mentioned, use the following:
type('c', Key.CTRL) # Copy command
One point worth mentioning - do not use upper-case characters, i.e.:
type('C', Key.CTRL) # Does not copy, avoid this
I haven't looked into the Sikuli source code, but my best guess is that it implicitly sends this as Shift+C, which results in a different command entirely.
type('x', Key.CTRL) also works.
Also, make sure that NUM_LOCK is off. If NUM_LOCK is on, it can make anything with KeyModifier.CTRL or KeyModifier.SHIFT misbehave.
You can try next code:
keyDown(Key.CTRL)
type("c")
keyUp(Key.CTRL)
I had a requirement to automate a flash content. The following code worked for me.
These were the following steps I ahd to perform as a part of the automation:
Enter Username and Password
Click on Login Button
Click on the button which will navigate to the application
The challenge I faced was to focus on the Username and password which had no placeholders . Hence the focusing was difficult. So I used the CTRL keys to do this .
Pattern appLogo = new Pattern("C:\\images\\appLogo.png");
StringSelection userNameText = new StringSelection("username");
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(userNameText, null);//Copy the text into the memory
Screen s = new Screen();
s.find(appLogo);
s.click(appLogo);
s.type(Key.TAB);//I had to enter tab twice to focus on user name textbox
s.type(Key.TAB);
s.type("V",KeyModifier.CTRL);
StringSelection password = new StringSelection("password");
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(password, null);
s.type(Key.TAB);//I had to enter tab twice to focus on user name textbox
s.type("V",KeyModifier.CTRL);
Pattern loginButton = new Pattern("C:\\images\\Login.png");
s.find(loginButton);
s.doubleClick(loginButton);
The scenario is like i need to press say key E in my keyboard after finishing the test how to add this in the script in Sikuli IDE.

Resources