Reputation: 7513
I am trying to use wx.TextCtrl to catch the typed key events, and directly forward the typed key to the stdin of a subprocess. Please note, for my special purpose, I will
completely disable the text editing feature of the TextCtrl. i.e., when I type a letter,
the letter will not be appearing on the TextCtrl, it will be directly forwarded.
Here is some code to illustrate what I want.
# inside the main frame
self.text = wx.TextCtrl(self.panel, wx.ID_ANY, style=wx.TE_MULTILINE)
self.text.Bind(wx.EVT_KEY_DOWN, self.OnKey)
self.text.Bind(wx.EVT_CHAR, self.OnChar)
# ...
def OnKey(self, evt):
keycode = evt.GetKeyCode()
# ENTER
if keycode == 13:
self.subprocess.stdin.read("\n")
if keycode == 9:
self.subprocess.stdin.read("\t")
if keycode == 8:
self.subprocess.stdin.read("\b")
if keycode == 316:
pass # maybe some key will be ignored
else:
evt.skip()
def OnChar(self, evt):
key=chr(keycode)
self.subprocess.stdin.read(key)
I want to forward "ENTER", "TAB", "BACKSPACE", characters, numbers, etc., all the key input events to stdin, without letting TextCtrl to interfere. Is there a good way to do it? Or I have to explicitely match each key one by one?
Thanks for any suggestions!
Upvotes: 0
Views: 2256
Reputation: 1090
here you can find some of the modifiers and key states on the "key" python module:
https://pythonhosted.org/pyglet/programming_guide/keyboard_events.html
You can only use 1 binder, like @KEY_DOWN and not both @KEY_DOWN and EVT_CHAR
To manipulate chars you need to check the range of values but using the infos on the website above you can, for example do:
key.A
TO identify "a".
Otherwise you can identify "a" by the keycode associated (unicode or ASCII).
You need to get from the "evt" KeyEvent the:
evt.GetRawKeyCode()
To identify modifiers like SHIFT and CTRL SX ecc pressed with the key:
evt.GetModifiers()
Here, as an example of the usage of the "key" module, a listener I made that makes a TextCtrl accept only numerical values iput. You can modify it if you want. For letters you need to check for numerical values from: 65 (A) to 90 (Z) and from 97 (a) to 122 (z). And u can use:
evt.GetUnicodeKey()
But also
evt.GetRawKeyCode()
Works. So you will have:
rawKey = evt.GetRawKeyCode()
if rawKey >= 65 and rawKey <= 90 and rawKey >= 97 and rawKey <= 122:
# Inserted a letter from the alphabet.
###########
from pyglet.window import key
from Utils.NumberUtils import NumberUtils
ENTRY_ID = "id"
ENTRY_KEY_EVENT = "keyEvent"
ENTRY_SELECTION_EVENT = "selectionEvent"
MASK_STARTED_RIGHT_SELECTION = 1
MASK_STARTED_LEFT_SELECTION = -1
class KeyboardEventUtils(object):
__mLastEvt = {}
def on_change_text_check_is_float_value(self, evt):
txt = evt.GetEventObject()
strng = txt.GetValue()
rawKey = evt.GetRawKeyCode()
modifiers = evt.GetModifiers()
if KeyboardEventUtils.__mLastEvt != None and len(KeyboardEventUtils.__mLastEvt) > 0 and KeyboardEventUtils.__mLastEvt[ENTRY_ID] != txt.GetId():
self._mLastEvt = {}
if chr(rawKey).isnumeric() or (rawKey == key.PERIOD and not chr(rawKey) in strng and len(strng) > 0) or (rawKey == key.MINUS and not chr(rawKey) in strng and (len(strng) == 0 or txt.GetInsertionPoint() == 0)):
pos = txt.GetInsertionPoint()
txt.SetValue(str(float(txt.GetValue()[:pos] + chr(rawKey) + txt.GetValue()[pos:])))
txt.SetInsertionPoint(pos + 1)
elif (modifiers == 4 or modifiers == key.MOD_SHIFT) and rawKey == key.LEFT: # 4 (?) key.MOD_SHIFT (?)
pos = txt.GetInsertionPoint()
rng = list(txt.GetSelection())
if rng[0] == rng[1] and ENTRY_SELECTION_EVENT in KeyboardEventUtils.__mLastEvt:
del KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT]
if ENTRY_SELECTION_EVENT in KeyboardEventUtils.__mLastEvt and KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT] == MASK_STARTED_RIGHT_SELECTION:
rng[1] = rng[1] - 1
else:
KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT] = MASK_STARTED_LEFT_SELECTION
rng[0] = rng[0] - 1
txt.SetSelection(rng[0], rng[1])
elif (modifiers == 4 or modifiers == key.MOD_SHIFT): # 4 (?) key.MOD_SHIFT (?)
pos = txt.GetInsertionPoint()
rng = list(txt.GetSelection())
if rng[0] == rng[1] and ENTRY_SELECTION_EVENT in KeyboardEventUtils.__mLastEvt:
del KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT]
if ENTRY_SELECTION_EVENT in KeyboardEventUtils.__mLastEvt and KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT] == MASK_STARTED_LEFT_SELECTION:
rng[0] = rng[0] + 1
else:
KeyboardEventUtils.__mLastEvt[ENTRY_SELECTION_EVENT] = MASK_STARTED_RIGHT_SELECTION
rng[1] = rng[1] + 1
txt.SetSelection(rng[0], rng[1])
elif rawKey == key.LEFT:
rng = list(txt.GetSelection())
if rng[0] != rng[1]:
txt.SetInsertionPoint(rng[0])
else:
txt.SetInsertionPoint(txt.GetInsertionPoint() - 1)
elif rawKey == key.RIGHT:
rng = list(txt.GetSelection())
if rng[0] != rng[1]:
txt.SetInsertionPoint(rng[1])
else:
txt.SetInsertionPoint(txt.GetInsertionPoint() + 1)
elif rawKey == key.UP or rawKey == key.DOWN:
pass
elif rawKey == key.BACKSPACE:
pos = txt.GetInsertionPoint()
if txt.GetStringSelection() == "":
txt.SetValue(txt.GetValue()[:pos-1] + txt.GetValue()[pos:])
txt.SetInsertionPoint(pos - 0x1)
else:
r = txt.GetSelection()
txt.SetValue(txt.GetValue()[:r[0]] + txt.GetValue()[r[1]:])
txt.SetInsertionPoint(pos)
elif rawKey == key.DELETE:
pos = txt.GetInsertionPoint()
if txt.GetStringSelection() == "":
txt.SetValue(txt.GetValue()[:pos] + txt.GetValue()[pos+1:])
else:
r = txt.GetSelection()
txt.SetValue(txt.GetValue()[:r[0]] + txt.GetValue()[r[1]:])
txt.SetInsertionPoint(pos)
elif modifiers == key.MOD_CTRL and rawKey == key.A:
txt.SelectAll()
else:
KeyboardEventUtils.__mLastEvt[ENTRY_ID] = txt.GetId()
KeyboardEventUtils.__mLastEvt[ENTRY_KEY_EVENT] = evt
return False
KeyboardEventUtils.__mLastEvt[ENTRY_ID] = txt.GetId()
KeyboardEventUtils.__mLastEvt[ENTRY_KEY_EVENT] = evt
return True
Upvotes: 0
Reputation: 2655
You can do this to convert the key code to a character:
chr(keycode)
That won't get everything though, like enters and tabs. You'd have to handle that on a case by case basis (like you do in your example). Otherwise you'll need to create a dictionary of key code to character mappings:
codemap = {97:'a', 98:'b', 8:'\b'} # Fill this out
self.subprocess.stdin.read(codemap[keycode])
You also might want to play with wx.TE_PROCESS_ENTER and wx.TE_PROCESS_TAB. They enable/disable capturing the enter and tab keys as text.
Upvotes: 0