1

The short of it is that I am trying to add a keybinding to my program that will edit the clipboard and then paste the changes to whatever window you have active. On Windows I think I can probably do it with message passing, but X doesn't use message passing like that, so in order to do this, I'm just using python-evdev to send a ctrl+v event to uinput. This works reasonably well when you just run it, but I need it to run on a keybinding, in this case super+v. The problem becomes that when you send the ctrl and v events to uinput, the super mask is still active, so instead of send ctrl+v to the window, it sends ctrl+super+v, which doesn't actually do anything. Here's minimal code to explain exactly what i'm talking about:

import evdev,time,keybinder,gtk

def callback():
    with evdev.UInput() as uinput:
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTCTRL, 1)
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_V, 1)
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_V, 0)
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTCTRL, 0)
        uinput.syn()

keybinder.bind("<super>v",callback)
keybinder.bind("Escape",gtk.main_quit)
gtk.main()

If you release super quickly enough you can actually get it to work, but it's pretty fast and obviously not acceptable for an actual application. I've tried to release super but that raises a few problems; it's not very generic, it raises the problem of what to do afterwards (Leave it released? Press it again? What if they released within the time between you releasing and then pressing it again?), and, most importantly, it doesn't really seem to work.

Anyways, I guess the question is, is there any way around this? Perhaps a way to send keypress events that won't combine with the physical keyboard(unlikely)? If not, is there any better way to get it to paste generically on Linux?

Claudio
  • 10,614
  • 4
  • 31
  • 71
Josiah
  • 3,266
  • 24
  • 24

2 Answers2

0

I don't think this has a solution. As you clearly already understand, Ctrl-V is not an IPC mechanism used to initiate a "paste" operation, it's just a common keybinding to do that (note that your trick won't work if you happen to have emacs running in the foreground, where your gadget will just scroll the window up by a page). And I think you're right, there are no standards (e.g. something at freedesktop.org) to ask a window to "paste right now", nor really should there be.

At least as commonly understood and implemented by apps, paste is a user-initiated action. No app is going to expect it to be driven by an external tool. What's the actual problem you're trying to solve? Can't you bind something to run in your client apps or maybe hook an accessibility/input method framework instead?

That said: I think you have the right approach if you want to make this particular hack work. Query they keymap at the start of the operation, clear the state of any modifier keys, send your events, then reset the state. You still have an unsolvable race vs. the hardware keyboard obviously, but I suspect in practice that won't be a huge problem.

Andy Ross
  • 11,699
  • 1
  • 34
  • 31
  • Unfortunately, what "I'm really trying to do" is exactly what I said, I tried to be very candid. I am not using this as a clever way of sending text or trying to solve a problem in a roundabout way, I'm getting clipboard data and I am trying to paste it. The problem is that you don't necessarily want to use this app's paste function every time, otherwise I'd just populate the clipboard and let the user have at it. As for the emacs problem, the app is user scriptable, so they could add a keybinding (e.g. super+shift+v) that would allow it to paste to places that wouldn't normally work. Thanks – Josiah Jun 06 '13 at 03:22
  • Blah, I keep reading that last comment as dickish. I really couldn't think of a better way to word it and I accidentally submitted it when trying to insert a newline so I didn't have time to fix it. Just know that it is not meant to be that, I appreciate your response. – Josiah Jun 06 '13 at 03:25
0

You need to find a way to ascertain if the <super> key is currently held down.
In wxpython that would be Super = wx.GetKeyState(wx.WXK_META), I don't know what that would be in Gtk.
Then your code would be as follows:

def callback():
   Super = wx.GetKeyState(wx.WXK_META) # Here you require the Gtk equivalent 
   with evdev.UInput() as uinput:
        if Super:
            uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTMETA, 0)
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTCTRL, 1)
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_V, 1)
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_V, 0)
        uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTCTRL, 0)
        if Super:
            uinput.write(evdev.ecodes.EV_KEY, evdev.ecodes.KEY_LEFTMETA, 1)
        uinput.syn()

As you can see, you were within a gnat's tadger of getting it.
The added code, simply turns the Super key off before your required Ctrl+v and then back on again, afterwards.

Rolf of Saxony
  • 21,661
  • 5
  • 39
  • 60
  • Well, this app is basically abandoned at this point. I think I tried this (been a while, but the question seems to mention it) but I ran into the problem of a race condition. If the user was holding super before pasting, I could put it back, but they could also release super after pasting, but before it finishes writing. Then your super button is stuck pressed until you press it again. If I don't replace it, you can't paste more than once. I believe my final solution was to have the user manually choose to populate the clipboard from the context menu, or set an option to do so automatically. – Josiah Apr 18 '16 at 22:33