Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "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.486 c
2-1175592127
SergeyAlexandrovich
2007-04-03 13:22
2007.04.22
проблема с СИшной функцией


15-1174644621
Post_
2007-03-23 13:10
2007.04.22
Крякалка


2-1175499588
Knock
2007-04-02 11:39
2007.04.22
record в record е


2-1175235619
vegarulez
2007-03-30 10:20
2007.04.22
Подскажите про DBGridKeyPress.


1-1172734536
Салат
2007-03-01 10:35
2007.04.22
Конвертировать IP адрес из строки в какой ни числовой тип... ;)





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский