1

User selects any text and push ctrl+c. How to autorun command after this action?

I need solutions for:

  1. How to get notification/check about the state of the clipboard
  2. After notification/check will autorun command

I haven't idea.

69 420 1970
  • 375
  • 3
  • 17
  • 2
    Does it _need_ to be Ctrl+C? In the *nix world, that is normally the signal to stop/kill a process, so it's not a good shortcut to use. Yes, some GUI tools use it for copying, but you really don't want to make a global shortcut for that. – terdon Sep 23 '22 at 16:43
  • @terdon i correct stand you: no way to check clipboard? – 69 420 1970 Sep 23 '22 at 16:53
  • Sure you can check the clipboard, but that will depend on what desktop environment and what clipboard you are using. I was just saying that you should probably not focus on Ctrl+C because breaking that as a shortcut might affect other things. – terdon Sep 23 '22 at 16:55
  • Unfortunately, this is a surprisingly complex issue on *nix, with most systems having at least 2 separate clipboards (one for Ctrl+C or right-click copy, and another for select copy). Have a look at https://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html and https://wiki.archlinux.org/title/clipboard (this one has a wide variety of clipboard managers too, maybe one of them can do what you want). – terdon Sep 23 '22 at 16:57
  • @terdon hmm thanks a lot for links (I will read) – 69 420 1970 Sep 23 '22 at 17:02
  • In what context do you want to do this? Globally or locally for a program? If it is globally it doe snot sound like a good idea, but anything is possible. – ibuprofen Sep 23 '22 at 17:05
  • @ibuprofen I just need to know: is there such a possibility or not? Just that command `echo -n "it is another text" | xsel -ib` works manually. That changed clipboard, but I need to autorun command when non-empty clipboard. Ok, globally. – 69 420 1970 Sep 23 '22 at 17:16

1 Answers1

2

X11 clipboards can be monitored. This only applies to X11 and not console copy and paste nor tmux nor anything else. So portability might be dubious and you may need to monitor all three clipboards, depending on what your needs are.

    // whenclipchange.c

    // Run something when a X11 clipboard changes. Note that PRIMARY tends
    // to be the traditional default, while certain software instead uses
    // CLIPBOARD for I don't know what incompatible reason. There is also
    // SECONDARY to make your life more interesting.
    #define WHATCLIP "PRIMARY"
    
    #include <sys/wait.h>
    
    #include <assert.h>
    #include <err.h>
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    #include <X11/Xlib.h>
    #include <X11/extensions/Xfixes.h>
    
    void WatchSelection(Display *display, Window window, const char *bufname,
                        char *argv[]);
    
    int
    main(int argc, char *argv[])
    {
    #ifdef __OpenBSD__
        if (pledge("exec inet proc rpath stdio unix", NULL) == -1)
            err(1, "pledge failed");
    #endif
    
        if (argc < 2) err(1, "need a command to run");
        argv++; // skip past command name of this program
    
        Display *display    = XOpenDisplay(NULL);
        unsigned long color = BlackPixel(display, DefaultScreen(display));
        Window window = XCreateSimpleWindow(display, DefaultRootWindow(display),
                                            0, 0, 1, 1, 0, color, color);
        WatchSelection(display, window, WHATCLIP, argv);
        /* NOTREACHED */
        XDestroyWindow(display, window);
        XCloseDisplay(display);
        exit(EXIT_FAILURE);
    }
    
    void
    WatchSelection(Display *display, Window window, const char *bufname,
                   char *argv[])
    {
        int event_base, error_base;
        XEvent event;
        Atom bufid = XInternAtom(display, bufname, False);
    
        assert(XFixesQueryExtension(display, &event_base, &error_base));
        XFixesSelectSelectionInput(display, DefaultRootWindow(display), bufid,
                                   XFixesSetSelectionOwnerNotifyMask);
        while (1) {
            XNextEvent(display, &event);
            if (event.type == event_base + XFixesSelectionNotify &&
                ((XFixesSelectionNotifyEvent *) &event)->selection ==
                  bufid) {
                pid_t pid = fork();
                if (pid < 0) err(1, "fork failed");
                if (pid) {
                    // NOTE this will block until the
                    // command finishes... so it might miss
                    // clipboard events?
                    int status;
                    wait(&status);
                } else {
                    execvp(*argv, argv);
                    exit(EXIT_FAILURE);
                }
            }
        }
    }

Compile and run with something like...

$ cc -std=c99 -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lXft -lXfixes -o whenclipchange whenclipchange.c
$ ./whenclipchange echo clipboard changed
Edgar Magallon
  • 4,711
  • 2
  • 12
  • 27
thrig
  • 34,333
  • 3
  • 63
  • 84