GNU/Linux >> LINUX-Kenntnisse >  >> Linux

C++ Get-String aus der Zwischenablage unter Linux

X11 verwendet ein flexibles, asynchrones, anwendungsseitiges Zwischenablageprotokoll mit mehreren Puffern und mehreren Formaten.

Die meisten Toolkits haben es implementiert (GTKs gtk_clipboard_get() , Qts QApplication::clipboard() , Tks clipboard_get). Sie können dies jedoch manuell mit der X11-API tun, wenn Sie beispielsweise keine Toolkits verwenden oder wenn Sie große Datenmengen durch den Zwischenablagepuffer leiten müssen, ohne sie alle gleichzeitig im Speicher zu behalten.

Theorie

Es kann viele Puffer geben, aber Sie müssen nur zwei kennen:

  • CLIPBOARD ist der übliche explizite Puffer:Sie kopieren Dinge dort mit dem Menü Bearbeiten/Kopieren und fügen sie mit dem Menü Bearbeiten/Einfügen ein.
  • PRIMARY selection ist eine implizite Mausauswahlfunktion:Text wird eingefügt, wenn er mit dem Mauscursor ausgewählt wird, und wird durch Klicken mit der mittleren Maustaste in Texteingabefelder eingefügt.

Die Primärauswahl erfordert keine Tastendrücke, daher ist sie nützlich, um kleine Fragmente zwischen Fenstern zu kopieren, die nebeneinander liegen. Diese Funktion ist hauptsächlich Unix-spezifisch, aber ich habe Putty-, Trillian- und einige GTK-Apps gesehen, die sie unter Windows OS emulieren. Auch Firefox verfügt über die Funktion "Paste &Go", wenn Sie mit der mittleren Maustaste auf einen leeren, nicht interaktiven Bereich der Seite klicken.

Um die Dinge zu optimieren, sind diese anwendungsseitig Puffer:Anstatt die gesamte Zwischenablage / Auswahl jedes Mal, wenn sie sich ändert, auf den Server zu schieben, teilt die Anwendung dem Server einfach mit, dass sie mir gehört. Um den Puffer zu erhalten, bitten Sie den Besitzer, Ihnen seinen Inhalt zu geben. Auf diese Weise nimmt auch ein großer Puffer keine Ressourcen in Anspruch, bis er tatsächlich angefordert wird.

Wenn Sie den Puffer anfordern, fragen Sie den Eigentümer nach einem bestimmten Format, das Sie benötigen. Beispielsweise kann ein aus dem Seamonkey-Browser kopiertes Bild (Rechtsklick auf ein Bild und „Bild kopieren“) in verschiedenen Formaten dargestellt werden. Es wird als Bild-URL angezeigt, wenn Sie es in das Terminal einfügen. Es würde ein Bild werden, das von dieser URL geladen wird, wenn Sie es in Libreoffice Writer einfügen. Und es wäre das Bild selbst, wenn es in Gimp eingefügt würde. Das funktioniert, weil seamonkey schlau ist und jede Anwendung mit dem Format versorgt, nach dem sie fragt:Textstring für Terminal, HTML für Libreoffice und Bilddaten für Gimp. Um das Textformat anzufordern, fragen Sie nach UTF8_STRING Format mit Fallback auf STRING .

Wenn Sie eine andere Anwendung bitten, den Puffer vorzubereiten, was einige Zeit dauern kann, ist die Anfrage asynchron :Der Eigentümer bereitet den Puffer vor, speichert ihn an einem bestimmten Ort (Fenstereigenschaft wird als temporärer Speicher verwendet) und benachrichtigt Sie mit SelectionNotify Ereignis, wenn es fertig ist.

So erhalten Sie den Puffer:

  • Puffername wählen (CLIPBOARD , PRIMARY ), Format(UTF8_STRING , STRING ) und eine Fenstereigenschaft zum Speichern des Ergebnisses
  • Rufen Sie XConvertSelection() an um den Puffer anzufordern
  • warte auf SelectionNotify Veranstaltung
  • Pufferinhalt aus Fenstereigenschaft lesen

Naive Implementierung

// gcc -o xclipget xclipget.c -lX11
#include <stdio.h>
#include <limits.h>
#include <X11/Xlib.h>

Bool PrintSelection(Display *display, Window window, const char *bufname, const char *fmtname)
{
  char *result;
  unsigned long ressize, restail;
  int resbits;
  Atom bufid = XInternAtom(display, bufname, False),
       fmtid = XInternAtom(display, fmtname, False),
       propid = XInternAtom(display, "XSEL_DATA", False),
       incrid = XInternAtom(display, "INCR", False);
  XEvent event;

  XConvertSelection(display, bufid, fmtid, propid, window, CurrentTime);
  do {
    XNextEvent(display, &event);
  } while (event.type != SelectionNotify || event.xselection.selection != bufid);

  if (event.xselection.property)
  {
    XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, False, AnyPropertyType,
      &fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);

    if (fmtid == incrid)
      printf("Buffer is too large and INCR reading is not implemented yet.\n");
    else
      printf("%.*s", (int)ressize, result);

    XFree(result);
    return True;
  }
  else // request failed, e.g. owner can't convert to the target format
    return False;
}

int main()
{
  Display *display = XOpenDisplay(NULL);
  unsigned long color = BlackPixel(display, DefaultScreen(display));
  Window window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0,0, 1,1, 0, color, color);
  Bool result = PrintSelection(display, window, "CLIPBOARD", "UTF8_STRING") ||
                PrintSelection(display, window, "CLIPBOARD", "STRING");
  XDestroyWindow(display, window);
  XCloseDisplay(display);
  return !result;
}

Dies wird für viele einfache Fälle funktionieren. Eine Sache, die hier fehlt, ist die Unterstützung für das inkrementelle Lesen großer Puffer. Fügen wir es hinzu!

Große Puffer

Einige Apps möchten möglicherweise 100 Gigabyte Textprotokolle kopieren/einfügen. Und X11 erlaubt das! Aber die Daten müssen inkrementell weitergegeben werden, aufgeteilt in Chunks.

Wenn der angeforderte Puffer zu groß ist, legt der Eigentümer eine Eigenschaft im Format INCR fest, anstatt ihn in der Fenstereigenschaft zu speichern . Wenn Sie es löschen, geht der Eigentümer davon aus, dass Sie es gelesen haben, und legt den nächsten Block in derselben Eigenschaft ab. Das geht so lange, bis der letzte Chunk gelesen und gelöscht ist. Schließlich setzt der Besitzer eine Eigenschaft der Größe 0, um das Ende der Daten zu markieren.

Um also einen großen Puffer zu lesen, löschen Sie INCR -Eigenschaft und warten Sie, bis die Eigenschaft erneut angezeigt wird (PropertyNotify Ereignis, Zustand ==PropertyNewValue ), lesen und löschen, warten, bis es wieder erscheint, und so weiter, bis es mit der Größe Null angezeigt wird.

// gcc -o xclipget xclipget.c -lX11
#include <stdio.h>
#include <limits.h>
#include <X11/Xlib.h>

Bool PrintSelection(Display *display, Window window, const char *bufname, const char *fmtname)
{
  char *result;
  unsigned long ressize, restail;
  int resbits;
  Atom bufid = XInternAtom(display, bufname, False),
       fmtid = XInternAtom(display, fmtname, False),
       propid = XInternAtom(display, "XSEL_DATA", False),
       incrid = XInternAtom(display, "INCR", False);
  XEvent event;

  XSelectInput (display, window, PropertyChangeMask);
  XConvertSelection(display, bufid, fmtid, propid, window, CurrentTime);
  do {
    XNextEvent(display, &event);
  } while (event.type != SelectionNotify || event.xselection.selection != bufid);

  if (event.xselection.property)
  {
    XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, True, AnyPropertyType,
      &fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
    if (fmtid != incrid)
      printf("%.*s", (int)ressize, result);
    XFree(result);

    if (fmtid == incrid)
      do {
        do {
          XNextEvent(display, &event);
        } while (event.type != PropertyNotify || event.xproperty.atom != propid || event.xproperty.state != PropertyNewValue);

        XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, True, AnyPropertyType,
          &fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
        printf("%.*s", (int)ressize, result);
        XFree(result);
      } while (ressize > 0);

    return True;
  }
  else // request failed, e.g. owner can't convert to the target format
    return False;
}

int main()
{
  Display *display = XOpenDisplay(NULL);
  unsigned long color = BlackPixel(display, DefaultScreen(display));
  Window window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0,0, 1,1, 0, color, color);
  Bool result = PrintSelection(display, window, "CLIPBOARD", "UTF8_STRING") ||
                PrintSelection(display, window, "CLIPBOARD", "STRING");
  XDestroyWindow(display, window);
  XCloseDisplay(display);
  return !result;
}

Zum Beispiel xsel Werkzeug verwendet INCR Übertragung für Puffer größer als 4000. Laut ICCCM ist es Sache der Anwendung, eine angemessene Größenbeschränkung zu wählen.

Derselbe Code funktioniert für PRIMARY Auswahl. Ersetzen Sie „CLIPBOARD“ durch „PRIMARY“, um PRIMARY zu drucken Auswahlinhalt.

Referenzen

  • Zusammenfassung der X-Auswahl von Jamie Zawinski
  • Xlib-Programmierhandbuch - Auswahlen
  • ICCCM - Große Datenübertragungen und INCR-Protokoll
  • https://github.com/exebook/x11clipboard - minimal XCopy() und XPaste() Implementierungen
  • xsel und xclip Quellen
  • Die Sekundärauswahl - Geschichte und Ideen von Charles Lindsey

Haben Sie versucht, nicht zuerst einen Code zu finden, sondern ein Programm mit einer Implementierung? Ich habe es für Sie getan und viele Implementierungen gefunden, die direkte X11-Aufrufe verwenden. Ich denke, das wertvollste ist dies, aber Sie können dies auch lesen. Finden Sie einfach irgendein Programm und suchen Sie nach den Quellen. Versuchen Sie, auf Wikipedia nachzusehen, welche Anwendungen das x11-Zwischenablage-/Auswahlsystem verwenden.

Die folgenden Programme arbeiten speziell mit Datenübertragungsmechanismen:

xcutsel überträgt Daten von Auswahlen in Schnittpuffer oder umgekehrt

xclipboard , glipper (Gnome), parcellite (LXDE) und klipper (KDE) sind Zwischenablage-Manager, vielleicht wmcliphist sowie xcb zeigt den Inhalt der Schnittpuffer und erlaubt dem Benutzer, sie zu manipulieren xselection,

xclip , xsel und xcopy sind Kommandozeilenprogramme, die Daten in die oder aus der X-Auswahl kopieren. xcopy hat eine Ausführlichkeitsoption, die beim Debuggen von Xselection-Problemen hilft. Parcellite hat auch die Fähigkeit, von der Befehlszeile aus bestimmte X-Auswahlen zu lesen und zu schreiben.

synergy ist ein plattformübergreifendes Tool, mit dem Sie eine Zwischenablage auf mehreren Computern mit mehreren Betriebssystemen gemeinsam nutzen können

xfce4-clipman-plugin ist ein "Clipboard History Plugin for the Xfce4panel" und auch ein Clipboard Manager xtranslate sucht Wörter in theXselection in einem mehrsprachigen Wörterbuch autocutsel synchronisiert Cut Bufferand Selection Buffer

Kurz gesagt, X11 hat theoretisch 2 "Zwischenablagen":eigentlich eine Tastatur und für Auswahlen - der Text, den Sie sofort ausgewählt haben, kann überall eingefügt werden, indem Sie die mittlere Maustaste drücken, während die eigentliche "Tastatur" für die Haupt-/Standard-Zwischenablage dient Austausch durch verschiedene Arten von Objekten.

P.S. Ich würde nach meiner Erfahrung nicht mehr mit x11 arbeiten. Viel Spaß :)


Linux
  1. Holen Sie sich die Ganzzahl der Obergrenze aus der Zahl in Linux (BASH)

  2. So erhalten Sie die gesamte CPU-Auslastung in Linux mit C++

  3. C++ erhält Linux-Distributionsname\Version

  4. Wie finde ich den vollständigen Pfad des C++-Linux-Programms von innen heraus?

  5. C++ Linux:Holen Sie sich die Aktualisierungsrate eines Monitors

Zeigen Sie zufällige Zitate von der Befehlszeile in Linux an

Wikit – Holen Sie sich Wikipedia-Zusammenfassungen von der Befehlszeile in Linux

So erhalten Sie Nachrichten sofort von der Befehlszeile in Linux

So erhalten Sie den Dateinamen aus dem vollständigen Pfad in Linux

Wie bekomme ich eine Netzmaske von Bash?

Wie zeigt man bestimmte Zeilen aus einer Textdatei in Linux an?