Форум: "WinAPI";
Текущий архив: 2007.04.22;
Скачать: [xml.tar.bz2];
Внизесть ли разница между onKeyUp и onKeyPress? Найти похожие ветки
← →
Creative (2006-11-27 17:06) [0]Пытаюсь описать собственный класс окна. Все работает, но удивляет одна вещь. У меня обрабабывается событие onKeyPress, пишу аналогичную обработку событие onKeyUp. Результат - тот же самый. Все событие, которе должны происходить, происходят, пока клавише нажата. Разве они не должны происходить только при ее отпускании? Почему так происходит?
type TWndCore = class
private
......//все нужные поля
OnKeyPress : procedure;
OnKeyUp : procedure;
constructor CreateWnd(Width, Height : integer; FullScreen, VSync : boolean; ColorDepth, Freq : integer);
destructor Destroy(); override;
function MessageOperations(hInstance : HINST; hPrevInstance : HINST; lpCmdLine : PChar; nCmdShow : Integer) : Integer; stdcall;
===============
function TWndCore.MessageOperations(hInstance, hPrevInstance: HINST;
lpCmdLine: PChar; nCmdShow: Integer): Integer;
var Msg : TMsg;
begin
.........
if @OnKeyPress <> nil then OnKeyPress;
if @OnKeyUp <> nil then OnKeyUp;
end;
Основной код
procedure KeyUp;
begin
if Keys[VK_UP] then DoSmth1;
end;
procedure KeyPress;
begin
if Keys[VK_UP] then DoSmth2;
end;
begin
Wnd := TWndCore.CreateWnd(640, 480, false, true, 32, 60);
Wnd.OnKeyPress := KeyPress;
Wnd.OnKeyUp := KeyUp;
Wnd.MessageOperations(hinstance, hprevinst, cmdline, cmdshow)
end.
← →
Игорь Шевченко © (2006-11-27 17:15) [1]
> есть ли разница между onKeyUp и onKeyPress?
Есть.
> Пытаюсь описать собственный класс окна
> ...
> Почему так происходит?
Потому что кривой класс окна ?
← →
Creative (2006-11-27 17:25) [2]
> > Почему так происходит?
> Потому что кривой класс окна ?
а здесь можно как-то прикрепить файл? можно было бы предъявить исходник.
← →
Игорь Шевченко © (2006-11-27 17:27) [3]Creative (27.11.06 17:25) [2]
Нет, файл здесь нельзя прикрепить, можно только код в сообщение вставить.
Но судя по всему, у тебя какая-то своя обработка, которой в приведенном коде не видно. Событие OnKeyUp срабатывает в ответ на сообщение WM_KEYUP, а OnKeyPress на сообщение WM_CHAR. Как видишь, разница есть.
← →
Creative (2006-11-27 17:35) [4]Проблема в том, что конкетно обработку событий я стянула из чужого кода и в том-то и дело что в нем НЕ БЫЛО никакой своей обработки. Я привела в первом посте все, что касалось событий. Поэтому я и думала, что описанные приемы - это что-то принятое и понятное системе и достаточно только написать то, что мне нужно, аналогичным образом - и все будет работать.
← →
Игорь Шевченко © (2006-11-27 17:37) [5]Creative (27.11.06 17:35) [4]
> Проблема в том, что конкетно обработку событий я стянула
> из чужого кода
Два варинта - либо криво стянула, либо чужой код крив. Я не увидел в приведенном фрагменте ничего, что бы относилось к обработке этих событий, а с телепатией у меня в понедельник плохо. Что знал - рассказал, будет больше кода, будет больше рассказов
← →
Creative (2006-11-27 17:40) [6]Да я-то с удовольствием, но он велик слишком. Не лучше будет по почте?
← →
Игорь Шевченко © (2006-11-27 17:47) [7]Creative (27.11.06 17:40) [6]
Во-первых, можно кусками. До 7168 байт в сообщение можно вставить. Не относящиеся к проблеме части кода можно убрать. Во-вторых, выкладывая код в форум ты привлекаешь всех посетителей. В третьих, посылая что-то по почте, ты просишь техподдержку, вынуждая конкретного адресата заниматься твоей пролемой.
← →
Creative (2006-11-27 17:49) [8]Спасибо, убедительно. С учетом того, что я не очень понимаю, какие именно куски кода не относятся к проблеме, я пожалуй его весь выложу.
unit Core;
interface
uses Windows, Messages, OpenGL;
const ApplicationName = "RenderPort";
var keys : Array[0..255] of Boolean;
type TWndCore = class
private
FHandle : HWND;
FHDC : HDC;
FGLRC : HGLRC;
FWidth : integer;
FHeight : integer;
FRenderPort : TWndClass;
FoldScreenWidth : integer;
FoldScreenHeight : integer;
FScrMode : TDeviceMode;
FMainAction : Pointer;
FFullScreen : boolean;
FBPP : integer;
FFreq : integer;
FVertSync : boolean;
WGL_EXT_swap_control : boolean;
FActive : boolean;
protected
procedure GraphicInit;
procedure GraphicFree;
procedure RefreshRenderPort;
function ChangeDisplayMode(Width, Height, BPP, Freq : integer) : boolean;
public
OnBeforeRender : procedure;
OnRender : procedure;
OnAfterRender : procedure;
OnKeyPress : procedure;
constructor CreateWnd(Width, Height : integer; FullScreen, VSync : boolean; ColorDepth, Freq : integer);
destructor Destroy(); override;
procedure PreparePort(FullScreen : boolean; ColorDepth : integer);
procedure SwapBuffers;
procedure ResizePort(Width, Height : integer);
function MessageOperations(hInstance : HINST; hPrevInstance : HINST; lpCmdLine : PChar; nCmdShow : Integer) : Integer; stdcall;
end;
← →
Creative (2006-11-27 17:50) [9]
var ScrWidth,
ScrHeight,
ScrBPP,
ScrFreq : integer;
glext : string;
wglGetSwapIntervalEXT : function : GLint; stdcall;
wglSwapIntervalEXT : function(interval : GLint) : Boolean; stdcall;
implementation
{ TWndCore }
constructor TWndCore.CreateWnd(Width, Height: integer; FullScreen, VSync: boolean; ColorDepth, Freq: integer);
var dwstyle : DWORD;
dwexstyle : DWORD;
h_Inst : HINST;
function MainAction(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
Result := 0;
case (Msg) of
WM_CREATE:
begin
//
end;
WM_CLOSE:
begin
PostQuitMessage(0);
Result := 0
end;
WM_KEYDOWN:
begin
keys[wParam] := True;
Result := 0;
end;
WM_KEYUP:
begin
keys[wParam] := False;
Result := 0;
end;
WM_SIZE:
begin
ResizePort(LOWORD(LPARAM), HIWORD(LPARAM));
Result := 0;
end;
WM_LBUTTONDOWN:
begin
//
end;
WM_LBUTTONUP:
begin
//
end;
WM_MOUSEMOVE:
begin
//
end;
WM_TIMER :
begin
Result := 0;
end;
else
Result := DefWindowProc(hWnd, Msg, wParam, lParam);
end;
end;
← →
Creative (2006-11-27 17:53) [10]Пропущены стандартные условия создания окна (if FullScreenб ChangeDisplayMode и всякое такое) и подготовка контекста устройства (окно пишется для последующей работы с OpenGL)
function TWndCore.MessageOperations(hInstance, hPrevInstance: HINST;
lpCmdLine: PChar; nCmdShow: Integer): Integer;
var Msg : TMsg;
begin
FActive := true;
while FActive do begin
if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then begin
if (msg.message = WM_QUIT) or (msg.message = WM_CLOSE) then
FActive := false
else begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
end;
RefreshRenderPort;
if @OnRender <> nil then OnRender;
if @OnKeyPress <> nil then OnKeyPress;
SwapBuffers;
end;
Destroy();
Result := Msg.wParam;
end;
← →
Игорь Шевченко © (2006-11-27 17:53) [11]И зачем тебе требуется OnKeyPress при такой обработке ? Насколько я вижу, этот код позволяет узнать нажата ли в данный момент кнопка, а не вызвать пользовательский обработчик по нажатию/отпусканию кнопки.
В чем задача-то ?
← →
Creative (2006-11-27 17:55) [12]Соственно основной код. Код исходный, без моих искажений.
program Start;
uses Windows, Core, OpenGL;
var Wnd : TWndCore;
C: TCube;
{$R *.res}
procedure DrawCube;
begin
C.Render;
end;
procedure KeyPress;
begin
if Keys[VK_LEFT] then C.RotateY(-3);
if Keys[VK_RIGHT] then C.RotateY(3);
if Keys[VK_DOWN] then C.Move(-0.1);
end;
begin
Wnd := TWndCore.CreateWnd(640, 480, false, true, 32, 60);
C:= TCube.Create;
Wnd.OnRender := DrawCube;
Wnd.OnKeyPress := KeyPress;
Wnd.MessageOperations(hinstance, hprevinst, cmdline, cmdshow)
end.
← →
Creative (2006-11-27 17:58) [13]
> Игорь Шевченко © (27.11.06 17:53) [11]
> В чем задача-то ?
Задачка в том, что мне нужно, чтобы по нажатию клавиши последовательно перерисовывались картинки. Но если я использую это событие onKeyPress - они перерисовываются слишком быстро, не успеваешь клавишу оторвать, уже несколько мелькнуло. Мне посоветовали повесить обработчик на onKeyUp.
А конкретно этот код понравился мне (в отличие от стандартного Winmin`а) тем, что в отновном проекте не болтается бешеное количество служебных процедур.
← →
Игорь Шевченко © (2006-11-28 10:22) [14]Creative (27.11.06 17:58) [13]
> Задачка в том, что мне нужно, чтобы по нажатию клавиши последовательно
> перерисовывались картинки. Но если я использую это событие
> onKeyPress - они перерисовываются слишком быстро, не успеваешь
> клавишу оторвать, уже несколько мелькнуло. Мне посоветовали
> повесить обработчик на onKeyUp.
Для этой задачки этот код вроде не подходит. Этот код подходит для того, чтобы в программе путем опроса определять, нажата ли в текущий момент определенная клавиша. Но никакой реакции на момент нажатия (или отпускания) клавиши этот код не подразумевает.
Может быть, попробовать стандартный способ ?
← →
Creative (2006-11-28 11:08) [15]
> Этот код подходит для того, чтобы в программе путем опроса
> определять, нажата ли в текущий момент определенная клавиша.
> Но никакой реакции на момент нажатия (или отпускания) клавиши
> этот код не подразумевает.
> Может быть, попробовать стандартный способ ?
Да, но в действие то происходит момент нажатия клавиши. Как же так?
Стандартный способ - вы имеете в виду нечто, аналогичное тому как обрабатываются событие в VCL? Потому что я сейчас как раз думаю рассмотреть как это сделано там, и переписать для себя. Если это не очень глупо.
← →
Игорь Шевченко © (2006-11-28 11:57) [16]Creative (28.11.06 11:08) [15]
> Да, но в действие то происходит момент нажатия клавиши.
> Как же так?
Из приведенного кода я не вижу, что действие (хоть какое-то) происходит в момент нажатия клавиши. По приведенному коду (в посте[0]) мне непонятно, в какой момент производится вызов твоих обработчиков OnKeyUp и OnKeyPress.
Может, тебе подойдет такой способ:function MainAction(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
WndCoreInstance: TWndCore;
begin
Result := 0;
WndCoreInstance := TWndCore(GetWindowLong(hWnd, GWL_USER));
case (Msg) of
WM_NCCREATE:
begin
WndCoreInstance := TWndCore(
PCreateStruct(LParam)^.lpCreateParams);
SetWindowLong(hWnd, GWL_USER, Integer(WndCoreInstance));
end;
WM_CREATE:
begin
//
end;
WM_CLOSE:
begin
PostQuitMessage(0);
Result := 0
end;
WM_KEYDOWN:
begin
keys[wParam] := True;
Result := 0;
if Assigned(WndCoreInstance) and Assigned(WndCoreInstance.OnKeyDown) then
WndCoreInstance.OnKeyDown(WndCoreInstance);
end;
WM_KEYUP:
begin
keys[wParam] := False;
Result := 0;
if Assigned(WndCoreInstance) and Assigned(WndCoreInstance.OnKeyUp) then
WndCoreInstance.OnKeyUp(WndCoreInstance);
end;
...........
end;
И в том месте, где в WndCore создается окно, в CreateWindow или в CreateWindowEx последним параметром вставить Self
← →
Creative (2006-11-28 12:08) [17]
> Из приведенного кода я не вижу, что действие (хоть какое-
> то) происходит в момент нажатия клавиши. По приведенному
> коду (в посте[0]) мне непонятно, в какой момент производится
> вызов твоих обработчиков OnKeyUp и OnKeyPress.
>
> Может, тебе подойдет такой способ:
Если честно, из кода мне тоже это непонятно, поэтому я здесь. Я просто вижу, что оно происходит, но не могу объяснить почему.
А ваш способ обязательно сейчас попробую.
← →
Creative (2006-11-28 12:16) [18]
> WM_NCCREATE:
а что это такое?
← →
Creative (2006-11-28 12:22) [19]Есть два затруднения:
1. GWL_USER - undeclared identifier
2. WndCoreInstance.OnKeyDown(WndCoreInstance) - too many actual parameters
← →
Игорь Шевченко © (2006-11-28 12:27) [20]Creative (28.11.06 12:08) [17]
> > WM_NCCREATE:
>
>
> а что это такое?
Это сообщение Windows
> 1. GWL_USER - undeclared identifier
Виноват, GWL_USERDATA
← →
Игорь Шевченко © (2006-11-28 12:28) [21]
> 2. WndCoreInstance.OnKeyDown(WndCoreInstance) - too many
> actual parameters
Тогда просто WndCoreInstance.OnKeyDown; и WndCoreInstance.OnKeyUp;
← →
Creative (2006-11-28 12:34) [22]а с избыточностью параметров как быть?
← →
Creative (2006-11-28 12:36) [23]Откомпилиться-то он откомпилился, но при запуске выдает ошибку:
Failed to get a FB render port context.
← →
Creative (2006-11-28 12:39) [24]...и выдает он ее в соответствии вот с этим кодом:
if FHandle = 0 then begin
MessageBox(FHandle, "Failed to get a FB render port context.", "Fatal error", MB_OK or MB_ICONERROR);
Destroy();
exit;
Насколько я поняла, это потому что
FHandle := CreateWindowEx(dwexstyle, ApplicationName, ApplicationName, dwstyle, 0, 0, Width, Height, 0, 0, h_Inst, self);
либо вообще не происходит, либо происходит как-то криво
← →
Creative (2006-11-28 12:41) [25]И начинается эта кривизна, как только в коде появляется обработка сообщения WM_NCCREATE
← →
Игорь Шевченко © (2006-11-28 12:53) [26]В обработку сообщения WM_NCCREATE добавь перед end строку:
Result := DefWindowProc(hWnd, Msg, wParam, lParam);
← →
Creative (2006-11-28 13:05) [27]Отчет.
Все запускается, но работает следующим образом:
1. KeyDown работает точно, при этом очень хорошо заметно, насколько он отличается от KeyPress.
2. KeyUp - не работает вовсе. Она начинает работать, если в MessageOperations написать строку if @OnKeyUp <> nil then OnKeyUp; (аналогично if @OnKeyPress <> nil then OnKeyPress, которая стояла там раньше), но при этом она и работает как KeyPress. по-моему это неправильно.
Как заставить работать KeyUp?
← →
Игорь Шевченко © (2006-11-28 13:17) [28]Creative (28.11.06 13:05) [27]
В MessageOperations наверное вообще ничего не надо писать ? Какой смысл вызывать процедуру, реагирующую на нажатие кнопок, при обработке каждого сообщения ?
А зачем ее (процедуру OnKeyUp) вообще вызывать ?
← →
Creative (2006-11-28 13:29) [29]
> А зачем ее (процедуру OnKeyUp) вообще вызывать ?
Если я правильно понимаю, то все равно придется вернуться к тому, что собственно в WM_KEYUP писать обработку нажатий всех клавиш, которые мне нужны. Или нет? Извините, пожалуйста, но я не совсем ясно вас понимаю.
← →
Игорь Шевченко © (2006-11-28 13:43) [30]Creative (28.11.06 13:29) [29]
Если тебе надо по нажатию на кнопку делать какие-то действия, то и делай. Зачем делать что-то по ее (кнопки) отпусканию ?
← →
Creative (2006-11-28 13:49) [31]Вы знаете, я посмотрела и решила, что действительно - KeyDown вполне достаточно. Спасибо вам большое.
У меня только один вопрос еще: не могли бы вы объяснить, что сейчас происходит в обработке сообщения WM_NCCREATE?
← →
Игорь Шевченко © (2006-11-28 13:55) [32]Creative (28.11.06 13:49) [31]
В обработчике сообщения NCCREATE происходит установка соответствия между окном и экземпляром класса TWndCore, для того, чтобы потом, зная HWND окна, можно было легко и просто узнать экземпляр класса WndCore, создавший это окно.
← →
Creative (2006-11-28 14:01) [33]Скажите, а я могу аналогичным образом
(if Assigned(WndCoreInstance) and Assigned(WndCoreInstance.OnKeyDown) then
WndCoreInstance.OnKeyDown;)
обрабатывать и другие сообщения?
← →
Creative (2006-11-28 14:04) [34]Извиняюсь, выяснила, что кажется могу :-)
← →
Игорь Шевченко © (2006-11-28 14:08) [35]Creative (28.11.06 14:01) [33]
> Скажите, а я могу аналогичным образом
> (if Assigned(WndCoreInstance) and Assigned(WndCoreInstance.
> OnKeyDown) then
> WndCoreInstance.OnKeyDown;)
> обрабатывать и другие сообщения?
Безусловно
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2007.04.22;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.045 c