Why pygame keycodes are os-specific? - python

I have an engine called Ergame that has a module called erfunc. I wrote it on NT/Windows platform, and now I'm on POSIX/Linux. Since I find input on pygame considerably obscure many times, and I wanted to create an explicit distinction between IBM-STANDARD-US-PC and ABNT2 keyboard layouts, I've created several constants whose values are pygame-keycodes. I have problem.
For example, the keycode for "ACUTE/TILDE" on US-Standard Layout is 96. I've checked many times. Now, on POSIX, when I check, I get 39 (And the same applies to all the others). Which basically means: If I refer to the pygame-name, like pygame.K_UP, whatever. But if I refer to the keycodes directly, they differ according to the OS (Which basically means that I'll have to detect the OS on my engine and define the constants accordingly. Pretty boring.)
Anyway, I got curious. Why?

Let me preface this by saying I don't have any experience with input on windows or mac systems, but here is whats happening on the linux side.
Key events typically follow a three stage processing before reaching a program. The keyboard generates a scancode. The OS converts the scancode into a keycode. A keyboard map translates the keycode into a symbol.
Scancodes are hardware specific and represent a location on the keyboard
Keycodes are values the OS maps to scancodes, usually defined in /usr/include/linux/input.h
Keysyms are the symbols mapped to the keycodes, defined by your keymap. You can check them with xmodmap -pke
For SDL (which PyGame acts as a wrapper around), the scancode/keycode distinction is a little fuzzy, and not super important. What it reports as a "scancode" is actually the keycode, you'll notice pygame'sevent.scancode will match the "keycode" value printed in xev. What SDL calls "sym", pygame calls "key" and is really an SDL specific keycode. The keysym is represented by the event's "unicode" value.
The important part of this is that you are not actually getting the raw scancode, so it can be expected to be OS dependent rather than keyboard dependent. Also, if you were getting the raw scancode, you would expect scancodes to be equivalent onposition rather than character. So all row-1 col-1 keys produce the same scancode independent of keyboard layout.
While it may be boring to do OS checks and have massive constant tables, this is typically how its done. The good news is SDL does this for you, so you really should be using the pygame.K_* names. If supporting multiple keyboard layouts is an issue, consider adding an input configuration menu instead of hard coding tables for each layout.
I want to leave some links for further reading, but I'm not really sure what to link to. I'll leave the SDL Input Guide here for now.

Related

IPython 5.0 and key bindings in console

The new release of IPython does not depend any more on readline but uses the pure Python library prompt-toolkit, solving maintenance problems on Apple's and Windows' systems.
A new feature is the ability to edit a multi-line code block, using the cursor keys to move freely in the code block — with this power it comes, at least for me, a problem: because a ret inserts a new line in your code, to pass the whole block to the interpreter you have to use the shortcut alt+ret or possibly the less convenient key sequence esc followed by ret.
I say, this is a problem, because my terminal emulator of choice is the XTerm and, on many Linux distributions, the shortcut alt+ret is not passed to the application but it is directly used by the XTerm in which IPython is running, to toggle the screen-fullness of the said terminal (#ThomasDickey, xterm's mantainer and co-author pointed out that, by default, xterm doesn't care to send to the application the modifier bit on Enter even when one unbinds the Fullscreen action).
For this reason I'd like to modify at least this specific IPython key binding.
I've found instructions (sort of) for the previouos versions, the readline based ones, of IPython that do not apply to the new, 5.0 version.
What I would need are instructions that lead me to find, in IPython's user documentation, the names of the possible actions that I can bind, the names of the shortcuts to bind with the actions and the procedure to follow to configure a new key binding.
Failing to have this type of canonical answer, I may be happy with a recipe to accomplish this specific keybinding, with the condition that the recipe still works in IPython 6.0
You could change xterm's configuration.
xterm is configurable (and documented). In the xterm manual, the Default Key Bindings section shows the default binding for this key:
Alt <Key>Return:fullscreen() \n\
You can suppress that binding in more than one way:
using the omitTranslation resource to suppress the feature
setting the fullscreen resource to never
However, just suppressing it will not make it send something interesting (xterm ignores the modifier for Enter). Setting a translation resource works, e.g., in your $HOME/.Xdefaults file:
*VT100*translations: #override \n\
Alt <Key>Return: string("\033[27;3;13~")
The ctrl+j or ctrl+m keyboard shortcuts are validating the entry.
Modifying keyboard shortcuts in configuration when using prompt_toolkit is not (yet) possible; though it is pretty easy if you install IPython from source. If you look at the file IPython/terminal/shortcuts.py you will see that it contains the various logic; in particular you will find:
# Ctrl+J == Enter, seemingly
registry.add_binding(Keys.ControlJ,
filter=(HasFocus(DEFAULT_BUFFER)
& ~HasSelection()
& insert_mode
))(newline_or_execute_outer(shell))
This bind CtrlJ (enter) to the function newline_or_execute_outer which is responsible for adding new lines; it's define later in the file. In particular if you press enter twice at the end of a block of code, it should execute the block without the need to use any other shortcuts.
Strip the logic that adds new lines:
def execute_outer(shell):
def execute(event):
"""When the user presses return, insert a newline or execute the code."""
b = event.current_buffer
# some logic to also dismiss the completer
b.accept_action.validate_and_handle(event.cli, b)
return execute
Bind it around line 20-something:
registry.add_binding(Keys.ControlE,
filter=(HasFocus(DEFAULT_BUFFER)
& ~HasSelection()
& insert_mode
))(execute_outer(shell))
And enjoy. If you are unhappy with the documentation we welcome help; For example, taking the gist of the answers there and contributing them back. It is a bit hurtful to read harsh comments when we do say in release notes:
New terminal interface
The overhaul of the terminal interface will probably cause a range of minor
issues for existing users. This is inevitable for such a significant
change, and we’ve done our best to minimise these issues. Some changes that
we’re aware of, with suggestions on how to handle them:
IPython no longer uses readline configuration (~/.inputrc). We hope that
the functionality you want (e.g. vi input mode) will be available by
configuring IPython directly (see Terminal IPython options). If something’s
missing, please file an issue.
...
Helping actually improving IPython to have configurable keybinding with actions name is also appreciated, so then you will be able to answer your own question.

Unicode SendKeys Alternative (Any programming language)

Before I get to the actual question I will say that altough I'm currently working in Python I will accept a solution in ANY language. I'm mostly a Java programmer but since Java is pretty limited to its JVM I didn't think it would be possible to create this in Java.
Goal:
I'm trying to make a program that will intercept keyboard events (I've already done this part using pyHook, this is one of the main reasons I am programming this in Python). Based on these events and the context I need to write unicode characters (ancient-greek) into any focused window (Currently only on Windows OS but an uniform solution that will work on all OS's seems ideal). Basically this is a program that allows me (Classical Language Student) to type Ancient Greek.
Problems:
Everything is working great up until the point where I need to send unicode characters, like an alpha, delta or omega, using sendKeys. The hook works perfectly and SendKeys works perfectly with normal ASCII characters. I've tried the following libraries all to no avail: (Code example at the bottom)
SendKeysCtypes (contrary to what the blog says it does NOT support unicode)
win32com.client using the shell and SendKeys.
SendKeys (Another library doing basically the same thing)
Now that I've outlined my current situation I've got the following questions:
Questions
1. Is it at all possible to use unicode characters with SendKeys? (google searches thus far seem to indicate that it is impossible).
Since this is likely not the case I wonder:
2. Is there any other library capable of sending unicode characters to the focused window?
Another thing that has crossed my mind is that I might be using the wrong method altogether (the whole simulating keypress events thing). Any other solution that will help me reach, or at least get closer to, my goal are VERY welcome.
#coding: utf-8
import time
import win32com
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
shell.Run('notepad')
time.sleep(0.1)
shell.AppActivate('kladblok')
shell.SendKeys("When Unicode characters are pasted here, errors ensue", 0)
shell.SendKeys(u"When Unicode characters are pasted here, harmony shall hopefully ensue".encode("utf-16le"), 0)
You have not followed up on questions in comments, so this is necessarily speculative.

Cross-platform multimedia keys in Python

I'm just starting on an application that will need to be able to receive multimedia key (play/pause, skip, previous) presses. I'm looking to target Mac, Linux (major distros), and Windows. I've seen a solution for GNOME that appears to do what I need, but as simple as it sounds, never anything that can pick up those keys on all major platforms. I also need to be able to pick up the keys globally, since the application will run in the background and won't ever have focus.
Currently, I'm not strongly tied to Python, but since I'd like to be able to target multiple platforms, Python seemed like the way to go. Has anyone written any cross-platform libraries that can do this? I haven't been able to find any that work.
PyQT looks like a potentially viable option, but some people have hinted that global key detection may be problematic on OSX.
With PyQt (or PySide) you can use the Qt::AA_CaptureMultimediaKeys application flag to enable cross-platform capturing of multimedia keys. In principle, using that flag your Qt program should be able to receive keyboard events when the user presses multimedia keys such as Play (Qt::Key_MediaPlay), Stop (Qt::Key_MediaStop), Pause (Qt::Key_MediaPause) etc. For a full list of supported keys, have a look at the documentation.
I cannot say if all keys will be supported on all platforms, but in general Qt aims to provide very good interoperability between different operating systems. I think with a simple prototype you should be able to answer that question really quick (I don't have access to a MacOS environment so I cannot test it there, but for Windows & Linux it should work). For more information on how to process keyboard events using Qt, have a look at the documentation of the QKeyEvent class.
I took over python-mmkeys a few months ago. I actually never tried to compile it, but it was included in the code of a project.
It is PyGTK dependant, but it is available on GNU/Linux, MacOX, and Windows.
The code is pretty easy to use:
import mmkeys
keys = mmkeys.Mmkeys()
keys.connect("mm_prev", previous_cb)
keys.connect("mm_next", next_cb)
keys.connect("mm_playpause", playpause_cb)

Something like pyHook on OS X

I am actually working with pyHook, but I'd like to write my program for OS X too.
If someone know such a module ... I've been looking on the internet for a while, but nothing really relevant.
-> The idea is to be able to record keystrokes outside the python app. My application is a community statistics builder, so it would be great to have statistics from OS X too.
Thanks in advance ;)
Edit:
PyHook : Record keystrokes and other things outside the python app
http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=PyHook_Tutorial
http://pyhook.sourceforge.net/doc_1.5.0/
http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=Main_Page
As far as I know, there is no Python library for this, so you're going to be calling native APIs. The good news is that PyObjC (which comes with the built-in Python on recent OS releases) often makes that easy.
There are two major options. For either of these to work, your app has to have a Cocoa/CoreFoundation runloop (just as in Windows, a lot of things require you to be a "Windows GUI executable" rather than a "command line executable"), which I won't explain how to do here. (Find a good tutorial for building GUI apps in Python, if you don't know how, because that's the simplest way.)
The easy option is the Cocoa global event monitor API. However, it has some major limitations. You only get events that are going to another app--which means media keys, global hotkeys, and keys that are for whatever reason ignored will not show up. Also, you need to be "trusted for accessibility". (The simplest way to do that is to ask the user to turn it on globally, in the Universal Access panel of System Preferences.)
The hard option is the Quartz event tap API. It's a lot more flexible, and it only requires exactly the appropriate rights (which, depending on the settings you use, may include being trusted for accessibility and/or running as root), and it's a lot more powerful, but it takes a lot more work to get started, and it's possible to screw up your system if you get it wrong (e.g., by eating all keystrokes and mouse events so they never get to the OS and you can't reboot except with the power button).
For references on all of the relevant functions, see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nsevent_Class/Reference/Reference.html (for NSEvent) and https://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html (for Quartz events). A bit of googling should turn up lots of sample code out there in Objective C (for NSEvent) or C (for CGEventTap), but little or nothing in Python, so I'll show some little fragments that illustrate how you'd port the samples to Python:
import Cocoa
def evthandler(event):
pass # this is where you do stuff; see NSEvent documentation for event
observer = Cocoa.NSEvent.addGlobalMonitorForEventsMatchingMask_handler_(NSKeyDown, evthandler)
# when you're done
Cocoa.NSEvent.removeMonitor_(observer)
import Quartz
def evthandler(proxy, type, event, refcon):
pass # Here's where you do your stuff; see CGEventTapCallback
return event
source = Quartz.CGEventSourceCreate(Quartz.kCGEventSourceStateHIDSystemState)
tap = Quartz.CGEventTapCreate(Quartz.kCGSessionEventTap,
Quartz.kCGHeadInsertEventTap,
Quartz.kCGEventTapOptionListenOnly,
(Quartz.CGEventMaskBit(Quartz.kCGEventKeyDown) |
Quartz.CGEventMaskBit(Quartz.kCGEventKeyUp)),
handler,
refcon)
Another option, at about the same level as Quartz events, is Carbon events (starting with InstallEventHandler). However, Carbon is obsolete, and on top of that, it's harder to get at from Python, so unless you have some specific reason to go this way, don't.
There are some other ways to get to the same point—e.g., use DYLD_INSERT_LIBRARIES or SIMBL to get some code inserted into each app—but I can't think of anything else that can be done in pure Python.
A possible quick alternative maybe this
https://github.com/gurgeh/selfspy
It claims to work on both mac and windows. It is based on pyhook on the windows part.
Good luck.

What can change my floating point control word behind my back?

I have a 32 bit Windows application, written primarily in Delphi, which performs floating point numerical simulations using the 8087 FPU. I have recently added the ability to link in external Python code using the Python API through python2x.dll. This recent change has led to some very strange behaviour.
The application has a batch mode of operation where it performs multiple simulations in parallel to take advantage of multi-core architectures. As soon as Python code has been executed in the process, I start to see changes to the 8087 control word on different threads. I've checked this very carefully and I have observed the control word having changed even in a thread which has never called into the Python DLL.
I know this sounds fantastical, but, as I have discovered, there are mechanisms for this behaviour to manifest. I have learnt about signals. I first hypothesised that the Python DLL was setting process wide signal handlers (by calling signal()) and these signal handlers were responsible for changing the control word. For example, a thread, unrelated to the Python code, could perhaps cause SIGFPE and that may, in turn, modify the control word.
I have rather come to the conclusion that signal() is not the mechanism. I arranged to execute the Python code at startup. Then I set of the signal handlers back to SIG_DFL. Then I started the simulations. But still the control word changes occurred.
My question (finally) is whether anyone knows of another mechanism by which the control word could be changed in such a manner. I'm looking for interrupts, APCs etc., I think!
Update
The control word is being changed to 0x037F which is the Intel default value. This differs from the MSVC/Windows default of 0x027F. I hypothesise that something is calling FPINIT.
I also discovered Py_InitializeEx which allows the caller to stop Python setting signal handlers. The control word changes occur even if I use this approach to initialisation so I'm even more convinced that is not the mechanism.
For example, a DllMain call with DLL_THREAD_ATTACH flag, see msdn
Update
I have found a link to similar problem - DLL Load "Poisons" FPU Control Word for New Threads. But yes, it is about the threads created after Dll load.
If I remember correctly, that's Delphi's problem. There are some discussions of the issue here and here. I remember bumping into it when trying to write some VST plugins in Delphi.
I have seen a case like this where the printer driver of the default printer changed the control word in my back. When I changed the default printer, the problem went away.
To circumvent this problem I set the control word to the default value at approriate places with:
_control87(_CW_DEFAULT, _CW_DEFAULT);
I have also seen the same problem on all machines of a customer that had Norton Security 2011 installed, but the problem went away with the fix for the printer driver, so I'm not really sure if Norton was really the cause.

Categories

Resources