So I was asked to port some internal helper applications to Mac OS X 10.7.
Works all quite welll as the platform dependent code is minimal anyhow, but one application needs a system wide shortcut to function (i.e. RegisterHotkey functionality) and I can't find any documentation on how I'd do this on a Mac.
The program is using a PyQt gui with Python 3.2. and the corresponding code for windows is basically:
def register_hotkey(self):
hwnd = int(self.winId())
modifiers, key = self._get_hotkey()
user32.RegisterHotKey(hwnd, self._MESSAGE_ID, modifiers, key)
and then to receive the hotkey events:
def winEvent(self, msg):
if msg.message == w32.WM_HOTKEY:
self.handle_hotkey()
return True, id(msg)
return False, id(msg)
Note that I don't need a python variant, I can easily write a simple c extension - so C/objective-c solutions are welcome as well.
I recently coded up an extension to quodlibet capturing multimedia keys (since absorbed into quodlibet itself); for your setup the same process applies.
I used the Quartz CGEventTapCreate hook and event loop, and the Cocoa AppKit framework to decipher key codes to achieve this.
The following code registers a python callback which is passed global key presses, and starts the event loop:
import Quartz
from AppKit import NSKeyUp, NSSystemDefined, NSEvent
# Set up a tap, with type of tap, location, options and event mask
tap = Quartz.CGEventTapCreate(
Quartz.kCGSessionEventTap, # Session level is enough for our needs
Quartz.kCGHeadInsertEventTap, # Insert wherever, we do not filter
Quartz.kCGEventTapOptionListenOnly, # Listening is enough
Quartz.CGEventMaskBit(NSSystemDefined), # NSSystemDefined for media keys
keyboardTapCallback,
None
)
runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)
Quartz.CFRunLoopAddSource(
Quartz.CFRunLoopGetCurrent(),
runLoopSource,
Quartz.kCFRunLoopDefaultMode
)
# Enable the tap
Quartz.CGEventTapEnable(tap, True)
# and run! This won't return until we exit or are terminated.
Quartz.CFRunLoopRun()
I defined a tap for system defined keys only (media keys); you'll have to specify a different event mask (CGEventMaskBit with one or more Event Types); e.g. Quartz.CGEventMaskBit(Quartz.kCGEventKeyUp) for key up events.
The callback should have the following signature (it implements the CGEventTapCallBack method from the Quartz API:
def keyboardTapCallback(proxy, type_, event, refcon):
# Convert the Quartz CGEvent into something more useful
keyEvent = NSEvent.eventWithCGEvent_(event)
I converted the Quartz event into a NSEvent, because all the information I could find on Mac multimedia keys was referring to that class.
In principle you can achieve the same thing with the AppKit APIs too, but then your Python application is treated as a Mac Application (visible in the Dock with an icon and everything), while I wanted this to be kept in the background altogether.
Using the power of google, I found this snippet of code, which allows the registration of global hotkeys for Mac OS X
You'll need to add the Carbon framework, and probably a bridged cast for ARC when passing the Objective-C self pointer to the C function.
At a minimum, you'll also need to:
#import <Carbon/Carbon.h>
The keycodes can be seen on this page explaining the virtual key codes.
Why has nobody ever mentioned the hammerspoon, which supports custom global system shortcuts, which can invoke shell command or launch UI application like Safari, PHOTOSHOP.
The following is an example written by me demonstrating how to invoke shell function with global hotkeys.
https://gist.github.com/BigSully/0e59ab97f148bc167ea19dbd42ebef4b
Use hs.execute to execute shell command, either non-interactive or interactive.
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "P", function()
local output = hs.execute("toggleProxy", true)
hs.alert.show(output)
end)
or
Use hs.application.launchOrFocus to launch application
hs.application.launchOrFocus("Safari")
Related
I was looking inside the idlelib module how the Python programmers have implemented IDLE, and at some point I found the following new syntax: <<cut>> or <<copy>> inside the file EditorWindow.py. Specifically, that syntax seems to be used as an event identifier (I think) for the bind function:
text.bind("<<cut>>", self.cut)
What I am not understanding is why there are some many of them, it seems they were create specifically for that class EditorWindow:
text.bind("<<cut>>", self.cut)
text.bind("<<copy>>", self.copy)
text.bind("<<paste>>", self.paste)
text.bind("<<center-insert>>", self.center_insert_event)
text.bind("<<help>>", self.help_dialog)
text.bind("<<python-docs>>", self.python_docs)
text.bind("<<about-idle>>", self.about_dialog)
text.bind("<<open-config-dialog>>", self.config_dialog)
text.bind("<<open-module>>", self.open_module)
text.bind("<<do-nothing>>", lambda event: "break")
text.bind("<<select-all>>", self.select_all)
text.bind("<<remove-selection>>", self.remove_selection)
text.bind("<<find>>", self.find_event)
text.bind("<<find-again>>", self.find_again_event)
text.bind("<<find-in-files>>", self.find_in_files_event)
text.bind("<<find-selection>>", self.find_selection_event)
text.bind("<<replace>>", self.replace_event)
text.bind("<<goto-line>>", self.goto_line_event)
text.bind("<<smart-backspace>>",self.smart_backspace_event)
text.bind("<<newline-and-indent>>",self.newline_and_indent_event)
text.bind("<<smart-indent>>",self.smart_indent_event)
text.bind("<<indent-region>>",self.indent_region_event)
text.bind("<<dedent-region>>",self.dedent_region_event)
text.bind("<<comment-region>>",self.comment_region_event)
text.bind("<<uncomment-region>>",self.uncomment_region_event)
text.bind("<<tabify-region>>",self.tabify_region_event)
text.bind("<<untabify-region>>",self.untabify_region_event)
text.bind("<<toggle-tabs>>",self.toggle_tabs_event)
text.bind("<<change-indentwidth>>",self.change_indentwidth_event)
text.bind("<Left>", self.move_at_edge_if_selection(0))
text.bind("<Right>", self.move_at_edge_if_selection(1))
text.bind("<<del-word-left>>", self.del_word_left)
text.bind("<<del-word-right>>", self.del_word_right)
text.bind("<<beginning-of-line>>", self.home_callback)
It seems we can also define in some way our events with this syntax <<EVENT_NAME>>.
I am using Python 3.4.
Virtual events, indicated with double rather than single brackets, are part of tcl/tk and are, of course, exposed in tkinter. For instance, a ttk.Notebook can generate a "<<NotebookTabChangede>>" event.
Create virtual events with widget.add_event(virtual, sequence, ...), where virtual is a double-bracketed name and each sequence is a normal single-bracketed physical event name. Delete such associations with Widget.event_delete(virtual, sequence, ...). Get info with w.event_info(virtual=None). Bind virual events with bind just like physical events. (I got this all from here.
Virtual events avoid hard-coding physical events to actions. In Idle, Options -> Idle preferences -> General -> Custom Key Setting is a table of actions and key bindings. Each action is both a virtual event and the event handler it is bound to. Those are fixed, but the key-binding to invoke the events are not. If you change the key bindings, event_delete and event_add are called as appropriate (and a custom set of key bindings is created or changed and saved to ~/.idlerc/config-keys.cfg).
<<..>> is not anything Python specific. It is specific to the Tk widget toolkit. Events with double chevrons are virtual events.
The editor window is a complex widget, and IDLE needs to handle many different events in that widget in order to implement code editing effectively.
I am developing a python script to drive a prototype I'm developing, and my current stumbling block is attempting to continuously write to the MouseSensitivity register in Windows. I'm using Windows 7, for specificity.
Unfortunately, I've hit some dead ends.
I've attempted to use pywin32 to write to the registry, but have not succeeded. After some searching, I've come across the SystemParametersInfo Function, but have not had any success with that either.
Essentially, for the purpose of solving this crisis, I've installed pyserial, pywin32, and ctypes (it appears that pywin32 may not be required). Assume I have an integer variable that will be between (and including) 1 to 20.
What I have for code right now is listed below. Much of it has been modified from here, as it appears that the author was using python, ctypes, user32.dll, and the SystemParametersInfo Function. However, when I run the code below, the shell enters a loop where the next line gets two tabs of space, and the cursor sits blinking until I keyboard interrupt. Any ideas?
import sys
import ctypes
import ctypes.wintypes
num = 12 # Between 1 and 20
SystemParametersInfo = ctypes.windll.user32.SystemParametersInfoW
SystemParametersInfo.argtypes = (
ctypes.wintypes.UINT,
ctypes.wintypes.UINT,
ctypes.c_void_p,
ctypes.wintypes.UINT,
)
SPI_SETMOUSESPEED = 0x0071
SystemParametersInfo(SPI_SETMOUSESPEED, 0, ctypes.cast(num, ctypes.c_void_p, 0)
I'm trying to maximize a specific window with python...
Here is the deal:
I have a script that opens 2 firefox windows (selenium rc), and I need to maximize the second window, the last one that opens...
How can I do it?
I'm using this command
window = win32gui.GetForegroundWindow()
win32gui.MoveWindow(window, 0, 0, 1440, 900, True)
that works perfectly, but only with the focus window... and the second window of firefox witch opens with the script doesnt get focused...
This should work
import win32gui, win32con
hwnd = win32gui.GetForegroundWindow()
win32gui.ShowWindow(hwnd, win32con.SW_MAXIMIZE)
If you don't want to install separate modules you could use the inbuilt ctypes module. The usage is not that different from the accepted answer above, except that you interact with the DLLs themselves and don't have to install anything else.
First here is the code:
import ctypes
user32 = ctypes.WinDLL('user32')
SW_MAXIMISE = 3
hWnd = user32.GetForegroundWindow()
user32.ShowWindow(hWnd, SW_MAXIMISE)
Now the explanation:
Get ctypes module.
Get the appropriate runtime, for reference use the Windows documentation and look under "Requirements".
Set the SW_MAXIMISE value to 3 since this is the value (indicated in the documentation) to set the window to maximum.
hWnd = user32.GetForegroundWindow() retrieves the foreground window (the window that is in front of all the others) - see here for the complete description on the function.
Use ShowWindow() to control the windows show state. This takes two arguments, the handle to the window (defined above as hWnd) and how the window should be seen (set as 3 in SW_MAXIMISE = 3). You can see the documentation for a more complete list of the various options.
You could of course put this into a function to make it easy to use.
Another approach:
Since in this case there are no worries about being cross platform, you could build a C or C++ extension instead.
Benefits:
no ctypes (which is sometimes worth considering, see the answers to this question)
Downfalls:
needs to be compiled (since it's on Windows only, you only need to worry about compiling for x32 bit and x64 bit)
must be a module (i.e. you can't intergrate it in one file)
requires a minimum knowlege of either C or C++ as well as the Python api itself
The actual function to be called should not be that difficult:
static PyObject * max_win(PyObject *self, PyObject *args) {
ShowWindow(GetForegroundWindow(), SW_MAXIMISE);
return Py_BuildValue(""); // Return nothing
}
Note that this is only a fragment of the actual code needed
How do I switch between my window manager's workspaces using Python with Xlib module?
This is my most promising attempt:
#!/usr/bin/python
from Xlib import X, display, error, Xatom, Xutil
import Xlib.protocol.event
screen = Xlib.display.Display().screen()
root = screen.root
def sendEvent(win, ctype, data, mask=None):
""" Send a ClientMessage event to the root """
data = (data+[0]*(5-len(data)))[:5]
ev = Xlib.protocol.event.ClientMessage(window=win, client_type=ctype, data=(32,(data)))
if not mask:
mask = (X.SubstructureRedirectMask|X.SubstructureNotifyMask)
root.send_event(ev, event_mask=mask)
# switch to desktop 2
sendEvent(root, Xlib.display.Display().intern_atom("_NET_CURRENT_DESKTOP"), [2])
The above code is shamelessly stolen from various places in the PyPanel source; unfortunately, it doesn't do anything, not even generate a warning / exception. Am I missing something here?
I'm using Python and PyGTK. Xlib seems to be the right choice for switching desktops. I don't intend to use wnck (buggy Python module) or similar, but I'd appreciate any pointers anyway.
I might add that this is my first attempt at writing a Python application using Xlib (or PyGTK).
Apparently you need to work on the same Display object and then flush it at the end. Something like:
display = Xlib.display.Display()
screen = display.screen()
root = screen.root
# ...
sendEvent(root, display.intern_atom("_NET_CURRENT_DESKTOP"), [1, X.CurrentTime])
display.flush()
Credit: Idea from a very similar thread (which almost works).
P.S. By the way, the desktop number starts from 0.
I develop a critical application used by a multi-national company. Users in offices all around the globe need to be able to install this application.
The application is actually a plugin to Excel and we have an automatic installer based on Setuptools' easy_install that ensures that all a project's dependancies are automatically installed or updated any time a user switches on their Excel. It all works very elegantly as users are seldom aware of all the installation which occurs entirely in the background.
Unfortunately we are expanding and opening new offices which all have different proxy settings. These settings seem to change from day to day so we cannot keep up with the outsourced security guys who change stuff without telling us. It sucks but we just have to work around it.
I want to programatically detect the system-wide proxy settings on the Windows workstations our users run:
Everybody in the organisazation runs Windows XP and Internet Explorer. I've verified that everybody can download our stuff from IE without problems regardless of where they are int the world.
So all I need to do is detect what proxy settings IE is using and make Setuptools use those settings. Theoretically all of this information should be in the Registry.. but is there a better way to find it that is guaranteed not to change with people upgrade IE? For example is there a Windows API call I can use to discover the proxy settings?
In summary:
We use Python 2.4.4 on Windows XP
We need to detect the Internet Explorer proxy settings (e.g. host, port and Proxy type)
I'm going to use this information to dynamically re-configure easy_install so that it can download the egg files via the proxy.
UPDATE0:
I forgot one important detail: Each site has an auto-config "pac" file.
There's a key in Windows\CurrentVersion\InternetSettings\AutoConfigURL which points to a HTTP document on a local server which contains what looks like a javascript file.
The pac script is basically a series of nested if-statements which compare URLs against a regexp and then eventually return the hostname of the chosen proxy-server. The script is a single javascript function called FindProxyForURL(url, host)
The challenge is therefore to find out for any given server which proxy to use. The only 100% guaranteed way to do this is to look up the pac file and call the Javascript function from Python.
Any suggestions? Is there a more elegant way to do this?
Here's a sample that should create a bullet green (proxy enable) or red (proxy disable) in your systray
It shows how to read and write in windows registry
it uses gtk
#!/usr/bin/env python
import gobject
import gtk
from _winreg import *
class ProxyNotifier:
def __init__(self):
self.trayIcon = gtk.StatusIcon()
self.updateIcon()
#set callback on right click to on_right_click
self.trayIcon.connect('popup-menu', self.on_right_click)
gobject.timeout_add(1000, self.checkStatus)
def isProxyEnabled(self):
aReg = ConnectRegistry(None,HKEY_CURRENT_USER)
aKey = OpenKey(aReg, r"Software\Microsoft\Windows\CurrentVersion\Internet Settings")
subCount, valueCount, lastModified = QueryInfoKey(aKey)
for i in range(valueCount):
try:
n,v,t = EnumValue(aKey,i)
if n == 'ProxyEnable':
return v and True or False
except EnvironmentError:
break
CloseKey(aKey)
def invertProxyEnableState(self):
aReg = ConnectRegistry(None,HKEY_CURRENT_USER)
aKey = OpenKey(aReg, r"Software\Microsoft\Windows\CurrentVersion\Internet Settings", 0, KEY_WRITE)
if self.isProxyEnabled() :
val = 0
else:
val = 1
try:
SetValueEx(aKey,"ProxyEnable",0, REG_DWORD, val)
except EnvironmentError:
print "Encountered problems writing into the Registry..."
CloseKey(aKey)
def updateIcon(self):
if self.isProxyEnabled():
icon=gtk.STOCK_YES
else:
icon=gtk.STOCK_NO
self.trayIcon.set_from_stock(icon)
def checkStatus(self):
self.updateIcon()
return True
def on_right_click(self, data, event_button, event_time):
self.invertProxyEnableState()
self.updateIcon()
if __name__ == '__main__':
proxyNotifier = ProxyNotifier()
gtk.main()
As far as I know, In a Windows environment, if no proxy environment variables are set, proxy settings are obtained from the registry's Internet Settings section. .
Isn't it enough?
Or u can get something useful info from registry:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyServer
Edit:
sorry for don't know how to format comment's source code, I repost it here.
>>> import win32com.client
>>> js = win32com.client.Dispatch('MSScriptControl.ScriptControl')
>>> js.Language = 'JavaScript'
>>> js.AddCode('function add(a, b) {return a+b;}')
>>> js.Run('add', 1, 2)
3