python:how to copy/replace text on internet textbox using hotkey - python

This has been bugging me for the last few days.
What I'm trying to achieve is:
1. Select(by dragging, shift, etc) text from an internet text editor.
2. press a hotkey (Alt-` in the code below)
3. Retrieve/copy that text to python program
4. Replace the selected text with a different block of text.
So if I select the word "stack" in a text editor and press Alt+`, then the selection should change into "stack overflow".
With the press of that hotkey only.
It seems pretty easy, but I found out that it really isn't.
This is as far as I've gotten:
import pyHook
import win32clipboard
import win32api, win32con
def sm():
handle = win32api.GetCurrentProcess()
win32api.SendMessage(handle ,win32con.WM_COPY, 0,0)
def OnKeyboardEvent(event):
if event.Alt != 0:
if event.KeyID != 192:
sm()
try:
win32clipboard.OpenClipboard()
a = win32clipboard.GetClipboardData(13)
finally:
try:
win32clipboard.CloseClipboard()
finally:
print "error"
return True
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
if __name__ == '__main__':
import pythoncom
pythoncom.PumpMessages()
This is just one of the many codes I've tried.
I'm not even sure if WM_COPY is the right message to use. In fact, I don't really get what messages are supposed to do and how they work.
Retrieving the text is just the first part of the whole program and I'm stuck.
I don't care if I use the clipboard to make this happen.
Any ideas? I really want to make this work, because I do this tedious replacement every day.

Related

How to open a program using keyboard input?

My project is to make a program that you can run while you are playing games or other programs in the background.
When you press a certain key, your notepad should open and also close after you press the same key again.
I have managed to open notepad with subprocess and that works fine but I have no idea to make it open only when a certain key is pressed.
Thanks for any help!
EDIT:
What I tried already:
import subprocess
import keyboard
if keyboard.is_pressed('k'):
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
input()
here it just doesn't detect any keyboard input, the input() at the end makes the program not close instantly
import subprocess
import keyboard
keyboard.add_hotkey('ctrl+k', print,args=("hello", "test"))
input()
Here if I press "ctrl+k it" will print hello test that means the hotkey works fine. When I switch this part "print,args=("hello", "test")" to "subprocess.Popen('C:\Windows\System32\notepad.exe')"(it should open the program instead of printing hello test) the notepad opens instantly after I run the program and when I press "ctrl+k" I get a big error.
A more complex, but still working example could be the following. With this code your program will be always listening the keyboard, not only when you are focused on the input, so may be mre practical in your case
from pynput import keyboard
import subprocess
import threading
class MyException(Exception): pass
class Listening:
"""Is allways waiting for the keyboard input"""
def __init__(self):
self.notepad_open = False # to know the state
with keyboard.Listener(
on_press=self.on_press) as listener:
try:
listener.join()
except:
pass
def on_press(self, key):
try:
if key.char == "k":
if not self.notepad_open:
self.subprocess = \
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
self.notepad_open = True # update state
else:
self.subprocess.kill()
self.notepad_open = False # update state
except: # special key was pressed
pass
thread = threading.Thread(target=lambda: Listening())
thread.start()
The problem is that you check for the key 'k' only once at the beginning. If you want the program to correctly work then you should try this:
import time
import subprocess
import keyboard
while True:
if keyboard.is_pressed('k'):
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
time.sleep(5)
-I used the time so that you can only open the program once 5 seconds(If you're curious, see what happens without it)-

Pywinauto unable to find/close pop-up window

Source code
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
app = Application(backend='uia').start("C:\\Program Files (x86)\\Advantech\\AdamApax.NET Utility\\Program\\AdamNET.exe")
win = app['Advantech Adam/Apax .NET Utility (Win32) Version 2.05.11 (B19)']
win.wait('ready')
win.menu_select("Setup->Refresh Serial and Ethernet")
win.top_window().print_control_identifiers(filename="file.txt")
# win.top_window().OKButton.click_input() ---------This is what I hope to do
else
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
Problem Statement
I had to run this application with elevation rights. The above is my code. The problem is I can't identify the window (view in output image) that pops up after selection from menu. I need to close the window. Please excuse the line
win.top_window().print_control_identifiers(filename="file.txt")
It was meant write the identifiers into a text file because the structure of this code does not display the outputs for me to view. However, since nothing is appended, I guess pywinauto couldn't identify the dialog.
For a clearer understanding, please view the image (input) of when it selects the menu.
Input
Now, it pops up with this dialog (output)
Output
I've also used spy to identify the caption and it gives:
(Handle: 004E07D4,
Caption: Information,
Class: #32770(Dialog),
Style: 94C801C5)
Other things I've tried:
Besides using win.topwindow() to identify the dialog, I've used
win[Information].OKButton.click_input()
win[Information].OK.click_input()
win[Information].OK.close()
win[Information].OK.kill(soft=false)
win.Information.OKButton.click_input()
win.Information.OK.click_input()
win.Information.OK.close()
win.Information.OK.kill(soft=false)
app[Information] ...... curious if I could discover the new window from original application
I've also send keys like enter, space, esc & alt-f4 to close the dialog with libraries like keyboard, pynput & ctypes. It still doesn't work.
Link to download the same application: http://downloadt.advantech.com/download/downloadsr.aspx?File_Id=1-1NHAMZX
Any help would be greatly appreciated !
I finally found a thread that demonstrated the way multi thread works to solve this issue. I tried it myself and it works. It's a little different as a few parts of the code have depreciated. Here is the link to the solution:
How to stop a warning dialog from halting execution of a Python program that's controlling it?
Here are the edits I made to solve the problem:
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
def __init__(self, window_name, quit_event):
threading.Thread.__init__(self)
self.quit_event = quit_event
self.window_name = window_name
def run(self):
while True:
try:
handles = windows.find_windows(title=self.window_name)
except windows.WindowNotFoundError:
pass
else:
for hwnd in handles:
app = Application()
app.connect(handle=hwnd)
popup = app[self.window_name]
popup.close()
if self.quit_event.is_set():
break
time.sleep(1)
quit_event = threading.Event()
mythread = ClearPopupThread('Information', quit_event)
mythread.start()
application = Application(backend="uia").start("C:\\Program Files (x86)\\Advantech\\AdamApax.NET Utility\\Program\\AdamNET.exe")
time.sleep(2)
win = application['Advantech Adam/Apax .NET Utility (Win32) Version 2.05.11 (B19)']
win.menu_select("Setup->Refresh Serial and Ethernet")
quit_event.set()
else:
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
The best thing is this solution works for every other dialog that halts the main script from working & I could use them to do different actions like clicking buttons, inserting values, by adding more multi threads.

Multimedia Keys in Python (Linux)

I want to detect when the XF86Launch1 key is pressed on my keyboard, using Python.
I have a headless server with a Bluetooth connected keyboard. I'd like to launch a command-line program whenever a specific multimedia key is pressed.
At the moment, I'm using:
import sys
import tty, termios
def getch():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
print getch()
But it won't detect multimedia keys. Nothing prints out when I press them.
Is there a way to detect these keys on a headless Ubuntu box - or a better way to launch a program on keypress?
Rather than trying to read stdin of the tty, you can use linux's input device api to read them.
On linux, all input devices show up as a file under /dev/input (such as /dev/input/event0) and when one read()s from these files, structured data indicating when keys are pressed and released is returned.
In C, the libevdev library provides a wrapper around those. In python, you could use the python-evdev library. It should also be possible to read directly from the input device (though you may need to carefully read the kernel documentation & source to handle that properly).
I think that your problem is that multimedia keys do not map to terminal input.
It's possible that you could make progress by running xev to trap the key and xmodmap to map the key to a different input.
Alternatively, use something like TKinter and see if a graphical program doesn't collect the keypresses.
from Tkinter import *
root = Tk()
def key(event):
print "pressed", repr(event.char)
def callback(event):
frame.focus_set()
frame = Frame(root, width=100, height=100)
frame.bind("<Key>", key)
frame.bind("<Button-1>", callback)
frame.pack()
root.mainloop()
Another possibility is to map to an F key instead of a multimedia key. (i.e. F9)
Edit: Further research into this resulted in these two links:
Extra Keyboard Keys
Extra Keyboard Keys in Console
The console itself does not support multimedia keys. But it does support custom F keys. F30-F246 are always free. Rather than map to XF86Launch1, map to F70. Then map F70 to keyboard input in your keymap, or use the Python script you already wrote to handle it.
pycopia may be an option. I am using it with this bluetooth button and it seems to work fairly well. I am still working on getting it to reconnect to the button when the button goes to sleep and then comes back. Here's part of the script that I'm using:
keyboard.py:
from pycopia.OS.Linux import Input
from pycopia.OS.Linux import event
class Satechi(Input.EventDevice):
DEVNAME = 'Satechi'
def register_callback(self, cb):
self._callback = cb
def poll(self):
while 1:
ev = self.read()
if ev.evtype == event.EV_KEY:
self._callback(ev)
read_handler = poll
button.py
from keyboard import Satechi
def callback(event):
pass #Do something fun
if __name__ == '__main__':
pm = Satechi()
pm.find()
pm.register_callback(callback)
while 1:
try:
pm.poll()
except OSError:
pm = Satechi()
while True:
try:
pm.find()
pm.register_callback(callback)
break
except IOError:
pass
pm.close()
Where DEVNAME is the devices name in /proc/bus/input/devices.
You can print event in the callback to figure out what the code and value is for the button you are looking for
Try to read xinput test <id> stdout in a loop and catch the events you need.
Here is some example in Bash:
#!/bin/bash
keyboard_id=9 # use xinput to find your keyboard id
xinput test $keyboard_id | while read line ; do
case $line in
"key press 44") echo -e "\n == j pressed ==" ;;
"key press 45") echo -e "\n == k pressed ==" ;;
esac
done

Getting pyHook and SendKeys to work together

I'm trying to write an auto-correct mechanism in Python. I log the user's keystrokes, and when they stop typing for a second I want to erase everything and retype the corrected sentence.
The code below is working fine, except for the fact that SendKeys is running very slowly. I think the PumpMessages call is interfering with it somehow. Does anyone know how I can deal with this problem?
import threading
import pyHook
import pythoncom
from SendKeys import SendKeys
# Store typed keys. Correct words when stop typing for a bit.
def info_handler():
def event_info(e):
if e.MessageName == 'key down':
v.keys_pressed.append(e.Key)
if v.t: v.t.cancel()
v.t = threading.Timer(1, correct_words)
v.t.start()
return True
return event_info
def correct_words():
SendKeys('{BS %i}' % len(v.keys_pressed))
# Listen to keys.
class v:
keys_pressed = []
t = None
hm = pyHook.HookManager()
hm.KeyDown = info_handler()
hm.HookKeyboard()
pythoncom.PumpMessages()
Nevermind. I just needed to call hm.UnhookKeyboard() before calling SendKeys.
Edit: Somebody asked me for more info. I decided to just dump my key related experiments onto GitHub: https://github.com/JesseAldridge/Keyboard-Tricks

how to properly destroy gtk.Dialog objects/widgets

Noob # programming with python and pygtk.
I'm creating an application which includes a couple of dialogs for user interaction.
#!usr/bin/env python
import gtk
info = gtk.MessageDialog(type=gtk.DIALOG_INFO, buttons=gtk.BUTTONS_OK)
info.set_property('title', 'Test info message')
info.set_property('text', 'Message to be displayed in the messagebox goes here')
if info.run() == gtk.RESPONSE_OK:
info.destroy()
This displays my message dialog, however, when you click on the 'OK' button presented in the dialog, nothing happens, the box just freezes.
What am I doing wrong here?
#mg
My bad. Your code is correct (and I guess my initial code was too)
The reason my dialog was remaining on the screen is because my gtk.main loop is running on a separate thread.
So all I had to was enclose your code (corrected version of mine) in between a
gtk.gdk.threads_enter()
and a
gtk.gdk.threads_leave()
and there it was.
Thanks for your response.
can you give me a last chance? ;)
there are some errors in your code:
you did not close a bracket
your syntax in .set_property is wrong: use: .set_property('property', 'value')
but i think they are copy/paste errors.
try this code, it works for me. maybe did you forget the gtk.main()?
import gtk
info = gtk.MessageDialog(buttons=gtk.BUTTONS_OK)
info.set_property('title', 'Test info message')
info.set_property('text', 'Message to be displayed in the messagebox goes here')
response = info.run()
if response == gtk.RESPONSE_OK:
print 'ok'
else:
print response
info.destroy()
gtk.main()

Categories

Resources