Вставка двоичных данных в терминал Unicode

Вставка двоичных данных в терминал Unicode

Мне нужно иметь возможность вставлять двоичные данные в терминал. По какой-то причине каждый байт за пределами диапазона ASCII ( 0x80- 0xff) вставляется как одна и та же последовательность из трех байт 0xef 0xbf 0xbd.

Например:

$ echo -en "\x80" | xclip
$ hd
<paste><EOF>
00000000  ef bf bd                                       |...|
00000004

Это как-то связано с кодировкой символов, используемой терминалом, поскольку если я изменю ее с UTF-8 на ISO 8859 или аналогичную, каждый символ в расширенном диапазоне будет переведен в 0x3f.

Есть ли у кого-нибудь идеи, как вставить произвольные двоичные данные в терминал?

Редактировать:Похоже, это очень зависит от терминала. Пример выше в Konsole. Я получаю желаемое поведение в xterm, а Gnome Terminal вообще не позволяет вставлять символы в расширенном диапазоне. Любое решение, специфичное для Konsole, все равно будет оценено.

решение1

ef bf bdэто кодировка UTF-8ЗАМЕНА ПЕРСОНАЖА(�), который «используется для замены входящего символа, значение которого неизвестно или непредставимо в Unicode».

То, что вы описываете, не является "расширенным ASCII", а скорее двоичными данными. Некоторые байты в диапазоне 0x80- 0xffне являются допустимыми ISO 8859, поэтому понятно, что некоторые программы воспринимают это как неизвестный символ.

Вы можете попробовать использовать 8-битную кодировку символов, которая использует все 255 позиций, например, кодовую страницу IBM 850.

Но тогда программа, из которой вы копируете, может также интерпретировать данные. И что произойдет, если вы вставите нулевой байт или терминальную управляющую последовательность? Весь подход, похоже, обречен на провал.

решение2

Терминалы, как правило, не предназначены для приема двоичного ввода: они ожидают, что управляющие символы будут иметь особое значение в приложениях, и сами выполняют некоторую обработку управляющих символов (в основном в несколько сигналов).

Исключением является termрежим Emacs (или один из его вариантов), который обрабатывает вставленные данные как необработанный текст, передаваемый в приложение.

Обычный метод предоставления двоичного ввода приложению — перенаправление его ввода из файла или канала. Если данные находятся в буфере обмена X, можно использовать xclipили xsel:

xclip -o | myapp
xsel -o | myapp

решение3

Ожидаемое поведение сработало здесь с использованиемякуакэтерминал. Я сделал echo -en "\x5" | xclipи затем средней кнопкой нажал на сеанс экрана с открытым на нем последовательным портом. Устройство отреагировало так же, как и ожидалось.

решение4

Есть несколько комментариев, на которые не было дано подходящего ответа. Вот некоторые моменты:

  • xterm не принимает "произвольные двоичные данные". Он принимает (в зависимости от локали) UTF-8 или ISO-8859-1. Последний соответствует ICCM, первый является расширением от XFree86. В любой кодировке xterm может интерпретировать эти символы, чтобы (попытаться) предоставить данные из выделения. При вставке текста UTF-8 из выделения в кодировку ISO-8859-1 он будет аппроксимировать наиболее часто используемые символы (включая рисование линий).

  • Выбор (и вставка) зависят как от источника (где делается выбор), так и от цели (куда вставляется текст). Оба должны согласовать формат данных для выбора/вставки. xterm предоставляет и принимает несколько форматов (см.button.cв источниках). Konsole и gnome-terminal используют меньше форматов.

  • Konsole, например, делает выбор X11 как запоздалую мысль. Он используетQClipboard::Selectionметод. Комментарии к странице Qt в разделеПримечания для пользователей X11Интересное чтение в этом отношении. Нопрочитайте коди посмотрите, что этотолькоподдерживает COMPOUND_TEXT:

    if (*format == 8 && *type == ATOM(COMPOUND_TEXT)) {
        // convert COMPOUND_TEXT to a multibyte string
        XTextProperty textprop;
        textprop.encoding = *type;
        textprop.format = *format;
        textprop.nitems = buffer_offset;
        textprop.value = (unsigned char *) buffer->data();
    
        char **list_ret = 0;
        int count;
        if (XmbTextPropertyToTextList(display, &textprop, &list_ret,
                     &count) == Success && count && list_ret) {
            offset = buffer_offset = strlen(list_ret[0]);
            buffer->resize(offset);
            memcpy(buffer->data(), list_ret[0], offset);
        }
        if (list_ret) XFreeStringList(list_ret);
    }
    
  • Аналогично, VTE GNOME используетgtk_clipboard_get_for_display, в целом следуя примеру Qt.

  • IBM 850 — это 8-битная кодировка (как ISO-8859-1), и не может представлять заменяющий символ UTF-8. Поэтому ваш терминал использует ?(символ по умолчанию).

Дальнейшее чтение:

Связанный контент