私は最小限の作業例を投稿しようとしますが、残念ながらこの問題は多くの断片を必要とします。別のスレッドでPythonのキーエコーが最初のキーストロークを表示しない
まず、関数呼び出しでキーを押すことをシミュレートする簡単なスクリプトを使用しています。これはhereから調整されています。
import ctypes
SendInput = ctypes.windll.user32.SendInput
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):
_fields_ = [("wVk", ctypes.c_ushort),
("wScan", ctypes.c_ushort),
("dwFlags", ctypes.c_ulong),
("time", ctypes.c_ulong),
("dwExtraInfo", PUL)]
class HardwareInput(ctypes.Structure):
_fields_ = [("uMsg", ctypes.c_ulong),
("wParamL", ctypes.c_short),
("wParamH", ctypes.c_ushort)]
class MouseInput(ctypes.Structure):
_fields_ = [("dx", ctypes.c_long),
("dy", ctypes.c_long),
("mouseData", ctypes.c_ulong),
("dwFlags", ctypes.c_ulong),
("time",ctypes.c_ulong),
("dwExtraInfo", PUL)]
class Input_I(ctypes.Union):
_fields_ = [("ki", KeyBdInput),
("mi", MouseInput),
("hi", HardwareInput)]
class Input(ctypes.Structure):
_fields_ = [("type", ctypes.c_ulong),
("ii", Input_I)]
def getKeyCode(unicodeKey):
k = unicodeKey
curKeyCode = 0
if k == "up": curKeyCode = 0x26
elif k == "down": curKeyCode = 0x28
elif k == "left": curKeyCode = 0x25
elif k == "right": curKeyCode = 0x27
elif k == "home": curKeyCode = 0x24
elif k == "end": curKeyCode = 0x23
elif k == "insert": curKeyCode = 0x2D
elif k == "pgup": curKeyCode = 0x21
elif k == "pgdn": curKeyCode = 0x22
elif k == "delete": curKeyCode = 0x2E
elif k == "\n": curKeyCode = 0x0D
if curKeyCode == 0:
return 0, int(unicodeKey.encode("hex"), 16), 0x0004
else:
return curKeyCode, 0, 0
def PressKey(unicodeKey):
key, unikey, uniflag = getKeyCode(unicodeKey)
extra = ctypes.c_ulong(0)
ii_ = Input_I()
ii_.ki = KeyBdInput(key, unikey, uniflag, 0, ctypes.pointer(extra))
x = Input(ctypes.c_ulong(1), ii_)
ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
def ReleaseKey(unicodeKey):
key, unikey, uniflag = getKeyCode(unicodeKey)
extra = ctypes.c_ulong(0)
ii_ = Input_I()
ii_.ki = KeyBdInput(key, unikey, uniflag + 0x0002, 0, ctypes.pointer(extra))
x = Input(ctypes.c_ulong(1), ii_)
ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
これをkeyPress.pyという名前のファイルに保存しました。
これを使用して、私はPythonシェルで入力中にユーザーが入力したものを検出できる簡単なプログラムを作りたかったのです。私がmsvcrt.getch()を使用してキーを押した後、それがまだ押されているように見えるようにするには、上記のスクリプトを使用します(そして、意味においてキープレスをエコーします)。
ここにありますコード:
import keyPress
import msvcrt
import threading
def getKey():
k = msvcrt.getch()
# Escaped Key: 224 is on the keyboard, 0 is on the numpad
if int(k.encode("hex"), 16) == 224 or int(k.encode("hex"), 16) == 0:
k = msvcrt.getch()
if k == "H": k = "up"
elif k == "P": k = "down"
elif k == "K": k = "left"
elif k == "M": k = "right"
elif k == "G": k = "home"
elif k == "O": k = "end"
elif k == "R": k = "insert"
elif k == "I": k = "pgup"
elif k == "Q": k = "pgdn"
elif k == "S": k = "delete"
# Fix weird linebreak
if k == "\r":
k = "\n"
return k
def actualGetKeys():
while True:
k = getKey()
keyPress.PressKey(k)
keyPress.ReleaseKey(k)
def getKeys():
p = threading.Thread(target=actualGetKeys)
p.daemon = True
p.start()
私はkeyGet.pyという名前のファイルにこれを保存
をこれは、すべてのユーザーがEnterキーを押すたびことを除いて、最初のキーが画面に表示されていない、非常にうまく機能しています。コンソールはあなたが入力したことをまだ知っていて、そこには表示されません:
何が起こっているか私は多くのことを試しましたが、私はこの振る舞いを変えるように見えません。
スクリプトが実行されている間にキー入力を非同期的に取得し、コマンドプロンプトに入力した各コマンドのテキストを使用して実行できるようになりました(つまり、storeこれらは配列になります)。私がある場合、私はちょうど思ったんだけど、これは基本的に、彼らはそれを入力した後、ロボットが自分の入力を再入力持つようになるために起因している知っている
:私はに実行しています唯一の問題は、このようなものですこれを行う方法は、ロボットが入力するときに入力が実際に表示されるのを防ぐので、ユーザーが期待するように機能します。
ですfgetsなどの関数。したがって、 'getch'がコンソールをrawモードに設定すると、Pythonの' fgets'読み込みを妨げます。 – eryksun
ロックを使って互いに干渉しないようにしても、 'getch'はその行の最初の文字に対してのみ呼び出されます。コマンドライン編集、F7履歴メニューなどで 'fgets'で読み取った読み込みは、残りの行を消費します。私は 'PyOS_InputHook'(ワンタイム設定)と' PyOS_ReadlineFunctionPointer'のフックを組み合わせて、ctypesを使ってロックテストを行いました。あなたが望むなら私はそれを投稿することができますが、最終結果は何にも役立ちません。コンソールから読み込むこれらの2つの方法は、うまく一緒に再生されません。 – eryksun
Hmm。実際にこれを修正する方法はありませんか? – Phylliida