Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2012.03.25;
Скачать: CL | DM;

Вниз

Как отловить нажатие VK_SNAPSHOT?   Найти похожие ветки 

 
antonn ©   (2010-11-14 00:46) [0]

В программе нужно поймать нажатие кнопки PrintScreen, ничего не подменять и прочего, работать только когда окно в фокусе (не "глобально"). Получить тот же функционал, что и в событиях OnKeyPress() - т.е. кнопка нажата и повторы нажатий (если они есть, как с буквами), т.е. GetAsyncKeyState() в каком нибудь таймере не подойдет.
Покопался в интернете, нашел раскопипащенный способ через хоткей ( http://www.delphimaster.ru/cgi-bin/faq.pl?look=1&id=988620866&n=15 ), но у меня этот способ работает "глобально" и при этом, видимо, "глушит" для остальных эту кнопку (по крайней мере в буфере все чисто, что уже не подходит). С хуками связываться не очень хочется... Реализация через другой раскопипащенный пример с обработкой в AppIdle() за одно быстрое нажатие выдает разом десяток "срабатываний" (ну там и GetAsyncKeyState()).
Есть ли какой проверенный способ узнать о нажатии этой кнопки, максимально независимый от всяких прав на действия (касперский спрашивает, хочу ли я позволить приложению установить ловушку :( ) и чтобы работало от win2k и выше?


 
sniknik ©   (2010-11-14 10:21) [1]

> Есть ли какой проверенный способ
ну, не скажу что это очень правильно, и точно не проверено (пару раз мной, на одной машине, не считается)  
но исправил немного этот
> нашел раскопипащенный способ через хоткей

var
 HookHandle: hHook = 0;

function WMHotKey(Code: integer; wParam: WPARAM; lParam: LPARAM): LongInt; stdcall;
begin
 if Code >= 0 then begin
   if wParam = VK_SNAPSHOT then ShowMessage("GotIt");
   result:= 0;
 end else
   result:= CallNextHookEx(HookHandle, Code, wParam, lParam);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 //RegisterHotKey(Handle, id_SnapShot, 0, VK_SNAPSHOT);
 HookHandle:= SetWindowsHookEx(wh_Keyboard, @WMHotKey, hInstance, 0);
 if HookHandle = 0 then
   ShowMessage("Ошибка установки хука");
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 //UnRegisterHotKey(Handle, id_SnapShot);
 if HookHandle <> 0 then
   UnhookWindowsHookEx(HookHandle);
end;


> при этом, видимо, "глушит"
этот, у меня (на моей машине - xp) не глушит, но что будет в win 7 не знаю.


 
antonn ©   (2010-11-14 14:20) [2]

А тот что в ФАКе не вставляет в буфер скриншот если хоткей повесить на окно? Хотелось бы знать это так и должно быть или у меня "что-то глючит" :)

С хуком касперский задает вопрос о допустимости установки ловушки. У меня программа может отправлять данные в интернет, и если такие сообщения будут вылезать - подозрительно будет выглядеть. Точнее я бы, если бы не знал что делает программа, не стал ей это разрешать :)


 
sniknik ©   (2010-11-14 18:20) [3]

> А тот что в ФАКе не вставляет в буфер скриншот если хоткей повесить на окно? Хотелось бы знать это так и должно быть или у меня "что-то глючит" :)
у меня не вставляет, т.что ... не знаю. инхеритед не помогает, результ другой возвращать тоже, только то что выше, или "в лоб", как ниже.

procedure SimulateKeystroke(Key : byte; extra : DWORD);
begin
 keybd_event(Key, extra, 0, 0);
 keybd_event(Key, extra, KEYEVENTF_KEYUP, 0);
end;

procedure TForm1.WMHotKey (var Msg: TWMHotKey);
begin
 if Msg.HotKey = id_SnapShot then begin
   ShowMessage("GotIt");

   UnRegisterHotKey(Handle, id_SnapShot);
   try
      SimulateKeystroke(VK_SNAPSHOT, 0);
   finally
     RegisterHotKey(Handle, id_SnapShot, 0, VK_SNAPSHOT);
   end;
 end;
end;


 
antonn ©   (2010-11-14 20:47) [4]

Волшебный костыль :))
Да, была идея самому делать "принтскрин" в это время, но постеснялся такое воротить :)

На другом форуме предложили в оконной проедуре ловить, он ловится до тех пор, пока на форме нет других оконных компонент :( Ну да ладно, конкретно для своей задачи я поудалял все компоненты, но хотелось универсального красивого решения :(


 
sniknik ©   (2010-11-14 21:29) [5]

> предложили в оконной проедуре ловить
стоп... ты же в [0] условие поставил, что не в окне(/форме)... нет?

> он ловится до тех пор, пока на форме нет других оконных компонент
в смысле? это уже на 17ю строку смахивает... подробнее нельзя?


 
sniknik ©   (2010-11-14 21:37) [6]

кажется будет к месту
http://www.gunsmoker.ru/2008/10/x-y-z.html


 
sniknik ©   (2010-11-14 21:38) [7]

> используя шаманский бубен, миелофон, шестое чувство, телепатор и прочие БС (Божественные Силы)
KeyPreview?


 
antonn ©   (2010-11-14 22:08) [8]


> sniknik ©   (14.11.10 21:29) [5]
>
> > предложили в оконной проедуре ловить
> стоп... ты же в [0] условие поставил, что не в окне(/форме).
> .. нет?

в данном случае форма есть


> кажется будет к месту

Нет, не к месту :)
Мне бы хотелось отлавливать принтскрин, будь хоть оконное приложение, хоть безоконное, иметь универсальный пример. Ну и как бы хотелось чтобы этому примеру было все равно есть ли окно в приложении или нет. Если это невозможно, и реализации с окном и без него "не пересекаются", то я думаю отвечающие (не только в этой теме) меня бы предупредили и давали советы "для окна" и "без него".
На данный момент у моего приложения есть окно, если это имело значение - надо было уточнить, извиняюсь :) Однако я же не зря привел ссылку на фак, там оконное приложение. Начал с малого :)

KeyPreview? Разумеется поставил св-во в true (в инспекторе, ну и в создании формы повторил, для проверки), но не доходит... Вообще ничего
type
 TForm1 = class(TForm)
   SpeedButton1: TSpeedButton;
   Button1: TButton;
   Memo1: TMemo;
   procedure FormCreate(Sender: TObject);
   procedure WndProc(var Message: TMessage); override;
 private
   { Private declarations }
 public
   { Public declarations }
 end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 KeyPreview:=true;
end;

procedure TForm1.WndProc(var Message: TMessage);
begin
 if(Message.msg=WM_KEYUP)and(Message.wParam=VK_SNAPSHOT) then begin
    memo1.Lines.Add(inttostr(random(65535)));
    caption:=inttostr(random(65535));
 end else
 if(Message.msg=WM_KEYUP)and(Message.wParam=VK_LEFT) then begin
    memo1.Lines.Add(inttostr(random(65535)));
    caption:=inttostr(random(65535));
 end;
 inherited WndProc(Message);
end;


 
antonn ©   (2010-11-14 22:13) [9]

вот идиот, не в FormKeyDown ловлю =)))


 
antonn ©   (2010-11-14 22:15) [10]

но все же хреново работает, на форме без контролов ввода (пара кнопок) опять же не отлавливается


 
sniknik ©   (2010-11-15 00:14) [11]

> вот идиот, не в FormKeyDown ловлю =)))
надо в FormKeyUp, даун занят принтскрином.

> WndProc
зачем усложнять (+ возможные ошибки вставлять), просто в событии формы достаточно.


 
antonn ©   (2010-11-15 00:51) [12]


> зачем усложнять (+ возможные ошибки вставлять), просто в
> событии формы достаточно.

она все равно перекрыта, но почему в событии срабатывает, а в WndProc нет?

И по моему разумнее делать скрин в момент нажатия, проще ловить момент, чем нажать и ждать отжатия :(


 
sniknik ©   (2010-11-15 07:55) [13]

>  почему в событии срабатывает, а в WndProc нет?
ошибка в твоей WndProc? почему бы не посмотреть как в vcl реализовано для того же события из формы.

> И по моему разумнее делать скрин в момент нажатия, проще ловить момент, чем нажать и ждать отжатия :(
а по моему разумнее делать так как работает в соответствии с системой.

и потом скрин как раз там и делается, в нажатии, это тебе предлагается ловить отжатие чтобы узнать, что он сделался...
или опять изменение планов? теперь ты уже ловишь чтобы делать скрин сам? тогда к чему тебе срабатывание системного? оно в первоначальном варианте как раз переопределяет нажатие и считает, что  на этом все скрин ты сделаешь и не нужно системный вызывать чтобы не перетереть твое.


 
antonn ©   (2010-11-15 09:02) [14]


> и потом скрин как раз там и делается, в нажатии, это тебе
> предлагается ловить отжатие чтобы узнать, что он сделался.
> ..
> или опять изменение планов? теперь ты уже ловишь чтобы делать
> скрин сам? тогда к чему тебе срабатывание системного? оно
> в первоначальном варианте как раз переопределяет нажатие
> и считает, что  на этом все скрин ты сделаешь и не нужно
> системный вызывать чтобы не перетереть твое.
>

Моя программа сохраняет в папку со скриншотами свой битмап, использование для этого системной кнопки лишь дань удобству и привычкам пользователям. Игра это


 
sniknik ©   (2010-11-15 09:41) [15]

вот вот, тогда зачем вообще тебе нужен системный вызов? раз уже сам "снял" скриншот, осталось только добавить его же в буфер обмена. а чтобы работал системный когда твоя игра не активна, то установку/снятие хука делать на активации/деактивации.


 
antonn ©   (2010-11-15 12:31) [16]


> раз уже сам "снял" скриншот, осталось только добавить его
> же в буфер обмена.

Нет, я не хочу вмешиваться в событие снятия скриншота. Юзер может сфотографировать какое нибудь AV (или банальный дефект от перерисовки на которое повлияла тема оформления, или вообще сделать снимок экрана, а не моего окна), а я ему буду подсовывать свой буфер? Тут есть один товарищ - он ведь и "морду набить" может за такое :)
Мне лишь была нужна реакция на кнопку, отловить ее нажатие.
Если бы я хотел, чтобы в буфер обмена помещался мой скриншот - я бы сделал поддержку Ctrl+C в своем окне.

Хук отлавливается всякими касперскими, я выше написал почему это может быть плохим методом. К тому же юзер может запретить один раз в этом самом касперском, а потом обратно разрешить задача не тривиальная для домашнего пользователя (речь конкретно об КИС8/9/10). А скрины сохраненные на диск сразу в png без не_клиентской части окна - удобно.


 
sniknik ©   (2010-11-15 13:02) [17]

> Мне лишь была нужна реакция на кнопку, отловить ее нажатие.
ты ее отлавливаешь в первом же -
> раскопипащенном способе через хоткей
сам же привел.

> не хочу вмешиваться в событие снятия скриншота.
в своей программе ты однозначно вмешиваешься, т.что добавить в буфер обмена то что уже есть меньшее зло, чем искать способ дать другим сделать дублирующуюся работу.
а чтобы не влиять на другие -
> а чтобы работал системный когда твоя игра не активна, то установку/снятие хука делать на активации/деактивации.

> а не моего окна
тогда ловить нужно Alt+PrintScreen, если окно.
по [3] аналог SimulateKeystroke(VK_SNAPSHOT, 1);

p.s. в общем проблема "высосана из пальца", в системе похоже специально ограничения на такой случай, типа "защиты от дурака", и делай либо правильно либо никак...


 
antonn ©   (2010-11-15 15:20) [18]


> > не хочу вмешиваться в событие снятия скриншота.
> в своей программе ты однозначно вмешиваешься

Нет, не вмешиваюсь, я даю пользователю возможность "щелкать" игровые скриншоты, предлагая делать это по стандартной (для игр, по крайней мере) клавише. Но так же пользователь может привычно для себя "фотографировать" экран в котором присутствует мое окно, в том случае если мое окно не "полноэкранное". Повторюсь так же, что если пользователь захочет сфотографировать окно, то он щелкнет Alt+PrintScreen, у меня же сохраняется в файл не окно, а только игровой контент.
Игровой скриншот<>Alt+PrintScreen, потому что содержит только битмап игровой сцены, без кепшенов и бордюров формы.

Отсюда мне требовалось лишь узнать о том, что был нажата кнопка, без каких либо перехватов (ууу, за одно упоминание такого мне бы уже "набили морду"..) и переопределений. Переназначить кнопку снятия игрового скриншота я могу, оставалась проблема узнать о ее нажатии. И сабжевую кнопку в качестве "скриноснимателя" выбирает подавляющее большинство игроков.

Могу так же порекомендовать глянуть другие продукты похожей направленности, так некий "ScreenshotCaptor" аналогично делает скрины всего экрана (или части) сохраняя их сразу в файл, и при этом в буфере обмена остается то, что должно было снято кнопкой printscreen. Никто ничего не заменяет в буфере, потому что это не их дело что туда занесли и кто.


 
sniknik ©   (2010-11-15 17:42) [19]

> так некий "ScreenshotCaptor" аналогично делает скрины
а как оно внутри работает? ты что ли его писал? то что видно "сверху" аналогично, не значит что "внутрях" все по твоим понятиям сделано (вот лично я бы попытался минимизировать работу, и не делать двойных действий).

> Никто ничего не заменяет в буфере, потому что это не их дело что туда занесли и кто.
а тебе что то другое предлагали? тебе предлагали вставлять туда только когда действия совпадают. активно твое приложение, и получается твой скриншот = тому что снимет система.

хотя ладно, не хочешь понимать, твое дело.


 
antonn ©   (2010-11-15 18:01) [20]


> активно твое приложение, и получается твой скриншот = тому
> что снимет система.

нет, мой скриншот сохраненный мною - игровая сцена. Которая выводится в обычное окно, которое не максимизировано. Без кепшенов и прочего, а принтскрином делается снимок окна (только моего или рабочего стола - не важно).
И так же работает в какй либо другой вменяемой игрушке, если игра идет в окне, то принтскрин делает скриншот экрана (окна), а игра сохраняет только буфер вывода.


> а как оно внутри работает?

отслеживает клавишу и снимает снимок, переводит в палитру pf24bit и дальше сохраняет в заранее выбранном формате в выбраную папку. В буфере остается исходное изображение (иногда с модифицированной палитрой, вставку которого из буфера не переваривает ни один из моих редакторов (палитра 256 цветов, вставляется черный квадрат, это тоже игра, но старая), а вот эта программа позволяет снять без геморроя).



Страницы: 1 вся ветка

Текущий архив: 2012.03.25;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.007 c
11-1242542465
hroot
2009-05-17 10:41
2012.03.25
Anchors &amp; wsMaximized


2-1323521292
3asys
2011-12-10 16:48
2012.03.25
Открытие файлов в TWebBrowser


2-1323374485
Gu
2011-12-09 00:01
2012.03.25
Openfolder


2-1323433650
_qwerty_
2011-12-09 16:27
2012.03.25
DataSet.Edit - Dataset.Post - DataSet.Cancel


15-1322570922
OW
2011-11-29 16:48
2012.03.25
Откуда пробел?