|
Понимаю, почему в turboconf используется буфер обмена как ячейка для чтения/записи текста в окна UIAutomation. Но многие пользователи и я в их числе использует ведение истории буфера обмена для повторного использования клипов. После обновления где то с начала февраля к сожалению даже всякие защитные меры писателей истории буфера не спасают от регистрации мусора от турбоконфа в этой истории.
Предлагаю описать тут способы, которыми turboconf изменяет содержимое буфера обмена. Попробуем найти оптимальное решение, включая возможную адаптацию представителя второй стороны - ClipAngel.
Так отправляет же не только turboconf, но и сам процесс конфигуратора после получения команды CTRL+C от turboconfа.
К тому же у буфера обмена нет атрибута "Процесс-источник" к сожалению. Поэтому программы для ведения истории считают отправителем клипа активное окно. А оно уже может измениться в момент обработки события обновления буфера обмена подписантом. Поэтому 100% определять отправителя клипа невозможно. Особенно в случае с турбоконфом который свои окна быстро скрывает после завершения команды.
(2) tormozit, CTRL+C для получения данных не используется для платформы >= 8.3.8. Раньше да только через буфер получались данные.
Если в буфер помещает непосредственно turboconf, то можно ставить специальный флаг типа "не добавлять в историю". Это неофициальный стандарт среди менеджеров буфера обмена . Подробнее тут http://www.clipboardextender.com/developing-clipboard-aware-programs-for-windows/ignoring-clipboard-updates-with-the-cf_clipboard_viewer_ignore-clipboard-format
У меня чаще всего в историю попадает список методов модуля, т.к. я вызываю скрипт "Процедуры и функции". Я думал ты как раз через буфер обмена из штатного окна получаешь список. Раз ты получаешь оттуда текст напрямую, то непонятно почему он в буфер обмена попадает.
(6) tormozit, согласен, не везде через UIAutomation, в таких списках через буфер.
(5) tormozit, у тебя же на C# ClipAngel, ты используешь этот флаг при вставке?
Опять же как это поможет при Ctrl+C, там же 1С помещает в буфер и флага не будет никакого.
(8) bolsun, при вставке флаг не использую, т.к. я не делаю временного изменения содержимого буфера. А при захвате я его проверяю.
(7) bolsun, насколько сложно будет избавиться от использования буфера обмена для чтения текста из окон конфигуратора хотя бы в этом месте?
(11) tormozit, кроме как через буфер список не получить. Тут только типа какого-то костыля можно сделать.
Обычно сразу после копирования в буфер, идет восстановление буфера предыдущим значением.
Может удалять эти 2 операции если они идут вместе.
2-й вариант зарегистрировать свой формат, говорящий что нужно удалить это и предыдущее значение. И когда я восстанавливаю буфер, добавлять этот флаг.
Предлагаю следующую систему сигнализации. Перед изменением текстового содержимого буфера обмена устанавливай в буфер обмена единственный формат с именем "ClipboardTempChange" и текстовым значением "Begin.<PID>" c ID процесса окна, которое будет слать временные данные в буфер. При восстановлении содержимого буфера обмена вместе с установкой туда оригинальных форматов добавляй формат с именем "ClipboardTempChange" и текстовым значением "End.<PID>" c ID процесса окна, которое завершило слать временные данные в буфер.
(12) bolsun, у тебя большие паузы бывают (более 400мс) между этими изменениями буфера. Такие вполне может делать и намеренно человек, который уверен, что все сохранилось в истории. Поэтому просто всегда удалять предыдущий клип тут будет нехорошо.
(14) tormozit, не знаю даже, работа с буфером и так нестабильна, приходится делать задержки, даже что бы одно значение установить, а тут придется на 2 операции больше делать.
(16) bolsun, на 1 обновление буфера больше, а не на 2. Согласен, что лишнее изменение буфера обмена - относительно высокая плата за такое исправление. Тогда предлагаю начать с добавления только второго сигнала -
При восстановлении содержимого буфера обмена вместе с установкой туда оригинальных форматов добавляй формат с именем "ClipboardTempChange" и текстовым значением "End.<PID>" c ID процесса окна, которое завершило слать временные данные в буфер.
(17) tormozit, флаг добавить можно, но что даст ID процесса? Ведь копирований при выполнении скрипта может быть несколько. Как понять какие отменять, а какие нет. Причем есть скрипты, которые по времени могут занимать достаточно продолжительное время.
"Clipboard Viewer Ignore" я попробовал добавить, вроде работает. Твоя программа не регистрирует такие изменения буфера.
(18) bolsun, в буфер обмена могут писать разные процессы. Будет нехорошо удалять клип от чужого процесса, который успел попасть между помещением тобой в буфер временного клипа и его восстановлением тобой.
Про то, что обновлений буфера (помимо восстановления) с твоей стороны может быть несколько для одной команды пользователя, ты впервые сообщаешь. Поэтому еще придется передавать момент начала с точностью до милисекунд. Теперь получается так -
При восстановлении содержимого буфера обмена вместе с установкой туда оригинальных форматов добавляй формат с именем "RemoveClipsFromHistory" и текстовым значением JSON:
PID=<PID>
TimeStart=<TimeBeginWithMiliseconds>
TimeEnd=<TimeEndWithMiliseconds>
где TimeStart - момент времени непосредственно перед отправкой в окно 1С первой команды CTRL+C из серии, а TimeEnd - момент времени сразу после считывания помещенного окном 1С текста в буфер после последней команды серии.
(19) bolsun, Так вроде уже много раз мы установили, что ты отправляешь в окно 1С CTRL+C и уже непосредственно оно отправляет данные в буфер обмена. Там ты не сможешь повлиять на установленные форматы. Их состав полностью определяет процесс конфигуратора.
(20) tormozit, слишком сложно и также без гарантированного результата из-за задержек. Что если я нажал Ctrl+C и через 100 мс, сразу запустил скрипт, который тоже нажал Ctrl+C.
Скрипты также пишут пользователи для себя, сколько раз, как, что и в каком окне (процессе) они там будут копировать никому не известно.
ИМХО просто отменять предыдущую вставку (после получения CF_CLIPBOARD_VIEWER_IGNORE от ТК), если время между ними в пределах какого-то небольшого интервала (200-300 мс). Во время выполнения скриптов, я блокирую ввод. Поэтому вероятность, что какие-то полезные данные будут скопированы пользователем в это время - минимальная.
Настройку можно сделать опциональной во вьювере.
(22) bolsun, видимо я просто чего то не знаю или не достаточно подробно описал.
Ты запускаешь скрипт по команде пользователя и сразу блокируешь ввод в окне конфигуратора. В какой то момент в скрипте идет отправка первой команды CTRL+C в конфигуратор. Вот перед ней нужно зафиксировать отметку времени. Дальше скрипт делает много всего и с буфером обмена в том числе, но ввод пользовательских команд заблокирован. В конце скрипт перед восстановлением буфера обмена и разблокировкой ввода пользователя также фиксирует отметку времени. Затем он восстанавливает содержимое буфера обмена и при этом добавляет новый формат с данными о периоде замусоривания буфера обмена. Мне схема кажется простой и понятной и достаточно надежной. Дополнительных обновлений буфера обмена не вызывает. Сложных алгоритмов не добавляет. Твоя программа будет предоставлять все нужные данные для наблюдателей за буфером, чтобы они могли убрать мусор из своей истории.
По поводу пользовательских скриптов - ну тут конечно можно нагородить что угодно и сломать что угодно. Поэтому принимать их в расчет не нужно, чтобы не добавлять 10-кратной сложности ради 10% случаев у 10% пользователей.
(23) bolsun, Использовать флаг CF_CLIPBOARD_VIEWER_IGNORE для удаления создаваемых твоей программой мусорных клипов - нехорошо, ведь этот флаг как я объяснял ранее является неофициальным стандартом и взводится многими программами, которые имеют другую логику работы и например там вредно будет удалять предыдущий клип. Если делать самый простой вариант, то все равно нужно свой флаг делать - например "RemoveLastClipFromHistory" и очень желательно PID все равно предоставлять, т.к. юзер мог переключиться на другое приложение, пока твой скрипт работал и там поместить что то полезное в буфер обмена.
(25) tormozit, со стороны задача кажется всегда проще чем есть на самом деле. Я как минимум несколько проблем вижу и изменения в алгоритмах достаточно существенные.
(27) bolsun, если все так сложно, то значит просто бери на заметку. Как будешь что то связанное править, может и этот сложный механизм сделаешь. А пока тогда остановимся на простейшем варианте (26)
(28) tormozit, тут еще нужно подумать хорошенько.
RemoveLastClipFromHistory - не очень хорошо, а если копирования по какой-то причине не было, что будет удалено?
или интервал будет учитываться?
Предлагаю попробовать флаг сделать 'RemoveClipsFromHistory', а значение которого - период в ms. Я сам могу тогда задавать интервал за который удалить.
Можешь сделать мне тестовую сборку с этим флагом? Я попробую как это работает.
(31) bolsun, период задавать не очень хорошо, т.к. я могу обработать это событие тоже не сразу, например из-за того что буфер не сразу разблокируется (такое бывает). Поэтому желательно все таки иметь абсолютные отметки времени конца и начала.
(33) tormozit, ну давай значит в том формате
PID=<PID>
TimeStart=<TimeBeginWithMiliseconds>
TimeEnd=<TimeEndWithMiliseconds>
если PID = 0 то значит удалять от всех процессов за этот период.
и еще уточни время локальное или UTC и в каком формате.
(35) bolsun, предлагаю взять локальное время по формату из примера
string format = "dd/MM/yyyy HH:mm:ss.ff";
string str = DateTime.Now.ToString(format, CultureInfo.InvariantCulture);
DateTime date = DateTime.ParseExact(str, format, CultureInfo.InvariantCulture);
string str1 = date.ToString(format, CultureInfo.InvariantCulture);
(36) tormozit, ок, жду тогда сборку.
Готово. Формат буфера назвал - RemoveTempClipsFromHistory. Сериализацию все таки сделал через JSON формат - и тебе и мне меньше забот по сериализации/десериализации.
Рекомендую добавить в проект пакет Newtonsoft.Json (лицензия MIT). Тогда сформировать транспортную строку будет очень просто - пример
public struct removeClipsFilter
{
public int PID;
public DateTime TimeStart;
public DateTime TimeEnd;
}
...
removeClipsFilter removeClipsFilter = new removeClipsFilter
{
PID = 54635
TimeStart = DateTime.Now.AddMilliseconds(-1000),
TimeEnd = DateTime.Now
};
dataString = JsonConvert.SerializeObject(removeClipsFilter);
(38) tormozit, посмотрю. Конечно я использую Newtonsoft.Json. Все сишарперы его используют ))
посмотрел ради интереса Newtonsoft.Json - 936 000 000 установок ))
(38) tormozit, PID = 0 поддерживается?
(41) bolsun, да
(41) bolsun, тогда что-то не работает.
Как у тебя выглядит RegisterClipboardFormat? какая строка?
Имя формата 'RemoveTempClipsFromHistory' ?
(44) bolsun, у меня ее нет. Это должен звать создатель клипов этого формата.
(45) tormozit, я регистрирую "RemoveTempClipsFromHistory"
но ничего не удаляется,
"Clipboard Viewer Ignore" работает
Ты можешь вывести алерт, если есть RemoveTempClipsFromHistory и параметры?
(48) bolsun, поставь CLCL - там удобно смотреть текущие форматы в буфере
Виноват. Отправил тебе из релизной папки сброку. А тестил на дебаге. Сейчас исправлюсь.
del
(51) tormozit,
(53) bolsun, Может ты null вместо 0 передал в PID?
(54) tormozit, мой косяк, не то передал. Но падать все равно не нужно )
(55) bolsun, ну если бы я не показал ошибку, то мы тут еще бы 3 часа разбирались. Поэтому я за "здоровое" падение.
Теперь удаляет, но есть проблема. Не удаляет тот текст, который приходит при восстановлении буфера.
Если добавить флаг ClipboardIgnoreFormatString, то игнорирует текст, но не удаляет предыдущие.
А зачем удалять текст, который приходит при восстановлении буфера? Об этом речи не шло. Можешь на примере текстом пояснить?
(58) tormozit, ну да, согласен, похоже не нужно.
bolsun изменил статус на Закрыто
При захвате мусорных клипов в локальном сеансе из дистанционного (например RDP), время локальное и дистанционное может сильно отличаться даже в одном часовом поясе. Поэтому в структуре, которую ты кидаешь в буфер для удаления мусорных клипов прошу добавить CurrentTime (текущее время), чтобы я мог хоть как то сориентироваться в смещении времени. А PID в связи с этим можно удалить (только сообщи мне, чтобы я у себя продублировал).
bolsun изменил статус на Открыто
(61) tormozit, CurrentTime получается будет совпадать с TimeEnd
Ты всегда сразу после последнего мусорного клипа отправляешь этот служебный клип? Если да, то я сделаю расчет смещения времени через TimeEnd.
(64) tormozit, я при каждой вставке, которую нужно исключить добавляю эти служебные данные.
Да. TimeEnd оказалось вполне достаточно чтобы смещение считать.
bolsun изменил статус на Закрыто
Добавить TurboConf в исключения, не помогает?