KEY_DOWN not working in CURSES - curses

I'm building a curses module and using KEY_DOWN to check if a arrow down key is pressed.
But, I get a Name error saying KEY_DOWN is not defined.
if value == KEY_DOWN:
NameError: global name 'KEY_DOWN' is not defined

Good day!
You have to do:
if value == curses.KEY_DOWN:
for it to work.
Hope this works!!!
But if this doesn't work show us your code (so we can analyze it)

To follow up to mvndaai's answer, if you want to detect arrow keys in Python, you have to AND together the three different ASCII values. For example:
key = getch()
if key == (27 and 91 and 65): #27 is ESC, 91 is [, and 65 is A
print("Up key pressed!")
if key == (27 and 91 and 66):
print("Down key pressed!")
if key == (27 and 91 and 67):
print("Right key pressed!")
if key == (27 and 91 and 68):
print("Left key pressed!")

I am not sure why the yave a gloabl named KEY_DOWN, but if you want a key down, you need to do 3 getchs. Warning, the first getch is the same as an ESC. That means you either make sure it doesn't close on ESC or do a work around like I did below. I also included a chart of what you will get as a getch for each key.
KeyESCUPDOWNRIGHTLEFT
getch2727272727
getch [[[[
getch ABCD
Which means that when you hit any Arrow key and you are triggering a ESC.
In ruby I tried a work around of checking for 27, then doing a quick timeout on another getch. If that gets a [ it is an arrow or something else, otherwise it is the escape key. Here is my ruby code:
def read_key
ch = getch
return check_escape_chars if ch == 27
ch
end
def check_escape_chars
require 'timeout'
begin
Timeout.timeout(0.0001) {getch}
case getch
when "A"; return "UP"
when "B"; return "DOWN"
when "C"; return "RIGHT"
when "D"; return "LEFT"
end
rescue Timeout::Error
return "ESC"
end
end

Related

Logitech Script, 1st and 2nd click events with time reset

What I want to do is if I press the button on my mouse it uses a key like "E" and if I press the button again it uses the key "W" and after 2 seconds it resets, I mean if I don’t press the same button after 2 seconds it uses letter "e " again. Is that possible?
I've tried some codes but no results yet:
function OnEvent(event, arg, family)
if event == "MOUSE_BUTTON_PRESSED" and arg == 5 then
toggle = not toggle
if toggle then
PressKey("e")
ReleaseKey("e")
else
PressKey("w")
ReleaseKey("w")
end
end
end
local prev_tm_btn5 = -math.huge
function OnEvent(event, arg, family)
if event == "MOUSE_BUTTON_PRESSED" and arg == 5 then
local tm = GetRunningTime()
local key = tm - prev_tm_btn5 > 2000 and "e" or "w"
prev_tm_btn5 = tm
PressKey(key)
Sleep(15)
ReleaseKey(key)
end
end

How can I read the arrow keys in a Ruby curses application?

I have a Ruby curses application in which I'd like to trap for the arrow keys and function keys. The problem is that some keystrokes generate multiple values when using STDIN.getch. When I type a 'regular' key like a-z I get a single value back. When I type a [F]key or arrow key I get three values back.
Is there a gem designed for handling keyboard input or a better way to accomplish reading keystrokes?
#!/usr/bin/ruby
require 'curses'
require 'io/console'
Curses.noecho
Curses.init_screen
main_window = Curses::Window.new(24, 40, 1, 0)
num_keys = 0
loop do
ch = STDIN.getch
num_keys = num_keys + 1
main_window.addstr(' key:' + ch.inspect + ' count:' + num_keys.to_s)
main_window.refresh
break if ch == 'q'
end
Curses.close_screen
Trying enabling the keypad on the window right after you instantiate it.
main_window = Curses::Window.new(24, 40, 1, 0)
main_window.keypad = true
and then instead of using STDIN.getch there's a getch method on the window as well you can use, so try changing
ch = STDIN.getch
to
ch = main_window.getch
now when I run your program, I get
key: 259 count: 1
when I hit the up arrow instead of
key:"\e" count 1 key:"[" count:2 key:"A" count:3

Better way to write this code

I am designing a user interface for a menu project. I tried using a for-loop such as:
for i in 0..8
i=i
end
for k in 0..7
k=k
end
if #selection==i && #unlock==k && $switches[(what do I do here?)]==?????
do thing
Whenever the user presses the Y key, it will turn off a function; if #selection==1 is highlighted and the user presses the "Y" key, the corresponding switch at that specific location should be turned off. #unlock is just used as a way of saying that, unless this global boolean is set to true, the user can press "Y" and turn this switch on or off.
First thing, you could change each if else to something like this:
BITMAP_PATH = "Graphics/Pictures/Input Map/switch"
if #selection==1 && #unlock1
pbSEPlay("BW2MenuChoose",65)
bitmap_switch = $switches[310] ? 'off' : 'on' # sets path to off/on
#graphics["switch"].setBitmap(BITMAP_PATH + bitmap_switch)
!$switches[310] # it changes value of boolean to opposite value
end
And the selections that only have one condition could be written like this:
if #selection==0 && #unlock0
pbSEPlay("buzzer",65)
end
You could also try writing a case expression for #selection. Probably you could dry it even more, but I do not really understand what each #unlock is used for.
Edit:
BITMAP_PATH = "Graphics/Pictures/Input/switch"
SELECTION_SWITCHES = [nil, 310, 300, 339, 338, 330, 318]
def pbChangeSwitch
case
when 0
case #selection
when 0,7
pbSEPlay("buzzer",65) if instance_variable_get("#unlock#{#selection}")
when 1..6
if instance_variable_get("#unlock#{#selection}")
pbSEPlay("BW2MenuChoose",65)
bitmap_switch = $switches[SELECTION_SWITCHES[#selection]] ? 'off' : 'on'
#sprites["switch"].setBitmap(BITMAP_PATH + bitmap_switch)
index = SELECTION_SWITCHES[#selection]
$switches[index] = !$switches[index]
end
end
Graphics.update
Please add $ to the last line. bitmap_switch can not be true or false, because you add it to BITMAP_PATH, so it has to be 'off' or 'on'.

what do the parameter values in AppleSymbolicHotKeys plist dict represent?

tl;dr
what does the first parameters value in com.apple.symbolichotkeys:AppleSymbolicHotKeys represent?
details...
the AppleSymbolicHotKeys structure
the OS X symbolic hotkeys plist file at
~/Library/Preferences/com.apple.symbolichotkeys.plist
stores hotkeys in a dict called as 'AppleSymbolicHotKeys' with entries that look like
<action:int> = Dict {
enabled = <enabled:bool>
value = Dict {
type = <type:string>
parameters = Array {
<param_1:int>
<param_2:int>
<param_3:int>
}
}
}
example:
10 = Dict {
enabled = true
value = Dict {
type = standard
parameters = Array {
56
28
1572864
}
}
}
pro tip: you can take a look with
/usr/libexec/PlistBuddy -c "Print :AppleSymbolicHotKeys" ~/Library/Preferences/com.apple.symbolichotkeys.plist
the values
action:int
this is the id of the action the hotkey will take. there are reasonably complete lists around the net, do some googling 'cause i don't have enough points to post links or whatever.
enabled:bool
whether the hotkey is enabled.
type:string
always seems to be 'standard'.
param_1:int
this is the one i can't get. it doesn't seem necessarily connected to params 2 and 3, though it often changes when the other params are changed. for instance...
i can click Restore Defaults in the System Preferences -> Keyboard -> Shortcuts -> Mission Control view, and it will set "Switch to Desktop 1" to "ctrl + 1". reading the value for that action (number 118), i see that param_1 is set to 65535. if i manually set the key combo to "ctrl + 1" in the UI, i get param_1 set to 49. the values of param_2 and param_3 stay the same throughout.
param_2:int
this seems to be key codes from
/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h
for the non-modifier key to be pressed, except for the value 65535, which is very common in param_1, and shows up in param_2 on my local machine for actions 160, 163 and 175.
param_3:int
seems to indicate the modifier key to be depressed, as according to
MODS = {
0=>"No modifier",
131072=>"Shift",
262144=>"Control",
524288=>"Option",
1048576=>"Command",
393216=>"Shift + Control",
655360=>"Shift + Option",
1179648=>"Shift + Command",
786432=>"Control + Option",
1310720=>"Control + Command",
1572864=>"Option + Command",
917504=>"Shift + Control + Option",
1441792=>"Shift + Control + Command",
1703936=>"Shift + Option + Command",
1835008=>"Control + Option + Command",
1966080=>"Shift + Control + Option + Command",
}
where you will notice the numbers representing multiple modifiers are the sum of the modifiers they represent, e.g.
"Shift + Control" = 393216 = 131072 + 262144 = "Shift" + "Control"
so...
any insight would be greatly appreciated, and hope this can serve as a reference for the info i dug up to anyone else approaching the subject.
It is the ascii code of the letter on the key, or -1 (65535) if there is no ascii code. Note that letters are lowercase, so D is 100 (lowercase d).
Sometimes a key that would normally have an ascii code uses 65535 instead. This appears to happen when the control key modifier is used, for example with hot keys for specific spaces.
There is a nice list of keys and values from 2011 here, along with some other good details:
http://hintsforums.macworld.com/showthread.php?t=114785
The numerical values in nrser's answer make more sense when viewed in hexadecimal form:
0x000000 => "No modifier",
0x020000 => "Shift",
0x040000 => "Control",
0x080000 => "Option",
0x100000 => "Command",
The others are simply bit-wise-ORs of the above values, for example:
0x060000 => "Shift + Control",
0x180000 => "Command + Option",
In addition to what's already been said, I've compiled a JSON manifest of all 256 possible modifier bitwise-operated results — including the function keys:
https://gist.github.com/stephancasas/74c4621e2492fb875f0f42778d432973

Multiple Key Event Bindings in Tkinter - "Control + E" "Command (apple) + E" etc

Mac OS X 10.6.6 - Tkinter
I want to bind multiple-key events, and while I have found an effbot article and the Tk man pages, I've been unable to make this work correctly. I'm new here.
I've had mixed success. I've been able to get Shift + letter key, but not Control or Command (Apple key). What I really want to do is Command + letter and Control + letter key so it would theoretically work in Windows and OS X.
I want it to work at window-level, so I'm using root. Perhaps there is a better way. Below is what I've tried:
root.bind('<Shift-E>', self.pressedCmdE) # Works
root.bind('e', self.pressedCmdE) # Works
root.bind('<Command-E>', self.pressedCmdE) # Does Not Work
#root.bind('<Mod1-E>', self.pressedCmdE) # # Do Mod1, M1, and
#root.bind('<M1-E>', self.pressedCmdE) # # Command mean the same thing?
Strangely, when I press alt/option + (E, N, or others) it creates an error. Is it interacting with PythonLauncher?
2011-06-16 16:19:22.618 Python[1546:d07] An uncaught exception was raised
2011-06-16 16:19:22.621 Python[1546:d07] *** -[NSCFString characterAtIndex:]: Range or index out of bounds
2011-06-16 16:19:22.622 Python[1546:d07] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFString characterAtIndex:]: Range or index out of bounds'
*** Call stack at first throw:
(
0 CoreFoundation 0x00007fff85b397b4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00007fff848b90f3 objc_exception_throw + 45
2 CoreFoundation 0x00007fff85b395d7 +[NSException raise:format:arguments:] + 103
3 CoreFoundation 0x00007fff85b39564 +[NSException raise:format:] + 148
4 Foundation 0x00007fff866eb5e1 -[NSCFString characterAtIndex:] + 97
5 Tk 0x0000000100759bcf Tk_SetCaretPos + 663
6 Tk 0x000000010075fd94 Tk_MacOSXSetupTkNotifier + 699
7 Tcl 0x000000010061d2ae Tcl_DoOneEvent + 297
8 _tkinter.so 0x00000001001d9be9 init_tkinter + 1132
9 Python 0x0000000100089187 PyEval_EvalFrameEx + 15317
10 Python 0x000000010008acce PyEval_EvalCodeEx + 1803
11 Python 0x000000010008935e PyEval_EvalFrameEx + 15788
12 Python 0x000000010008acce PyEval_EvalCodeEx + 1803
13 Python 0x000000010008ad61 PyEval_EvalCode + 54
14 Python 0x00000001000a265a Py_CompileString + 78
15 Python 0x00000001000a2723 PyRun_FileExFlags + 150
16 Python 0x00000001000a423d PyRun_SimpleFileExFlags + 704
17 Python 0x00000001000b0286 Py_Main + 2718
18 Python 0x0000000100000e6c start + 52
)
terminate called after throwing an instance of 'NSException'
Abort trap
With Tkinter, "Control-R" means Ctrl-Shift-R whereas "Control-r" means Ctrl-R. So make sure you're not mixing up uppercase and lowercase.
This appears to be a bug in Tk. I get the same error with tcl/tk on the mac as well as with python/tkinter. You can bind <Command-e> to a widget (I tried with a text widget) but binding it to the root window or to "all" seems to cause the error you get.
Enhanced to cover the Alt and Meta keys, aka Option and Command on macOS.
# Original <https://StackOverflow.com/questions/6378556/
# multiple-key-event-bindings-in-tkinter-control-e-command-apple-e-etc>
# Status of alt (ak option), control, meta (aka command)
# and shift keys in Python tkinter
# Note, tested only on macOS 10.13.6 with Python 3.7.4 and Tk 8.6.9
import tkinter as tk
import sys
_macOS = sys.platform == 'darwin'
_Alt = 'Option' if _macOS else 'Alt'
_Ctrl = 'Control'
_Meta = 'Command' if _macOS else 'Meta'
_Shift = 'Shift'
alt = ctrl = meta = shift = ''
def up_down(mod, down):
print('<%s> %s' % (mod, 'down' if down else 'up'))
return down
def key(event):
'''Other key pressed or released'''
# print(event.keycode, event.keysym, event.down)
global alt, ctrl, meta, shift
t = [m for m in (alt, ctrl, shift, meta, str(event.keysym)) if m]
print('+'.join(t))
def alt_key(down, *unused):
'''Alt (aka Option on macOS) key is pressed or released'''
global alt
alt = up_down(_Alt, down)
def control_key(down, *unused):
'''Control key is pressed or released'''
global ctrl
ctrl = up_down(_Ctrl, down)
def meta_key(down, *unused):
'''Meta (aka Command on macOS) key is pressed or released'''
global meta
meta = up_down(_Meta, down)
def shift_key(down, *unused):
'''Shift button is pressed or released'''
global shift
shift = up_down(_Shift, down)
def modifier(root, mod, handler, down):
'''Add events and handlers for key press and release'''
root.event_add('<<%sOn>>' % (mod,), ' <KeyPress-%s_L>' % (mod,), '<KeyPress-%s_R>' % (mod,))
root.bind( '<<%sOn>>' % (mod,), lambda _: handler('<%s>' % (down,)))
root.event_add('<<%sOff>>' % (mod,), '<KeyRelease-%s_L>' % (mod,), '<KeyRelease-%s_R>' % (mod,))
root.bind( '<<%sOff>>' % (mod,), lambda _: handler(''))
root = tk.Tk()
root.geometry('256x64+0+0')
modifier(root, 'Alt', alt_key, _Alt)
modifier(root, 'Control', control_key, _Ctrl)
modifier(root, 'Meta', meta_key, _Meta)
modifier(root, 'Shift', shift_key, _Shift)
root.bind('<Key>', key)
root.mainloop()
Option 1
Something like this:
# Status of control, shift and control+shift keys in Python
import tkinter as tk
ctrl = False
shift = False
ctrl_shift = False
def key(event):
global ctrl, shift, ctrl_shift
#print(event.keycode, event.keysym, event.state)
if ctrl_shift:
print('<Ctrl>+<Shift>+{}'.format(event.keysym))
elif ctrl:
print('<Ctrl>+{}'.format(event.keysym))
elif shift:
print('<Shift>+{}'.format(event.keysym))
ctrl = False
shift = False
ctrl_shift = False
def control_key(state, event=None):
''' Controll button is pressed or released '''
global ctrl
ctrl = state
def shift_key(state, event=None):
''' Controll button is pressed or released '''
global shift
shift = state
control_shift(state)
def control_shift(state):
''' <Ctrl>+<Shift> buttons are pressed or released '''
global ctrl, ctrl_shift
if ctrl == True and state == True:
ctrl_shift = True
else:
ctrl_shift = False
root = tk.Tk()
root.geometry('256x256+0+0')
root.event_add('<<ControlOn>>', '<KeyPress-Control_L>', '<KeyPress-Control_R>')
root.event_add('<<ControlOff>>', '<KeyRelease-Control_L>', '<KeyRelease-Control_R>')
root.event_add('<<ShiftOn>>', '<KeyPress-Shift_L>', '<KeyPress-Shift_R>')
root.event_add('<<ShiftOff>>', '<KeyRelease-Shift_L>', '<KeyRelease-Shift_R>')
root.bind('<<ControlOn>>', lambda e: control_key(True))
root.bind('<<ControlOff>>', lambda e: control_key(False))
root.bind('<<ShiftOn>>', lambda e: shift_key(True))
root.bind('<<ShiftOff>>', lambda e: shift_key(False))
root.bind('<Key>', key)
root.mainloop()
Option 2
However, in the end, I decided to process keystrokes manually. You can se the example in this file. First, I set keycodes and shortcuts in two dictionaries self.keycode and self.__shortcuts:
# List of shortcuts in the following format: [name, keycode, function]
self.keycode = {} # init key codes
if os.name == 'nt': # Windows OS
self.keycode = {
'o': 79,
'w': 87,
'r': 82,
'q': 81,
'h': 72,
's': 83,
'a': 65,
}
else: # Linux OS
self.keycode = {
'o': 32,
'w': 25,
'r': 27,
'q': 24,
'h': 43,
's': 39,
'a': 38,
}
self.__shortcuts = [['Ctrl+O', self.keycode['o'], self.__open_image], # 0 open image
['Ctrl+W', self.keycode['w'], self.__close_image], # 1 close image
['Ctrl+R', self.keycode['r'], self.__roll], # 2 rolling window
['Ctrl+Q', self.keycode['q'], self.__toggle_poly], # 3 toggle between roi/hole drawing
['Ctrl+H', self.keycode['h'], self.__open_poly], # 4 open polygons for the image
['Ctrl+S', self.keycode['s'], self.__save_poly], # 5 save polygons of the image
['Ctrl+A', self.keycode['a'], self.__show_rect]] # 6 show rolling window rectangle
Then added self.__keystroke function to monitor <Ctrl> keystroke events. This function checks if <Ctrl> key is pressed or not:
def __keystroke(self, event):
""" Language independent handle events from the keyboard """
#print(event.keycode, event.keysym, event.state) # uncomment it for debug purposes
if event.state - self.__previous_state == 4: # check if <Control> key is pressed
for shortcut in self.__shortcuts:
if event.keycode == shortcut[1]:
shortcut[2]()
else: # remember previous state of the event
self.__previous_state = event.state
Finally, bind the self.__keystroke function to the master GUI window. Note that this function is bonded in the idle mode, because multiple keystrokes slow down the program on weak computers:
# Handle keystrokes in the idle mode, because program slows down on a weak computers,
# when too many key stroke events in the same time.
self.master.bind('<Key>', lambda event: self.master.after_idle(self.__keystroke, event))

Resources