Solved

windows windows windows

Posted on 2003-11-30
32
483 Views
Last Modified: 2010-05-18
k, i'm developin code that communicates wiv a telescope over a serial link. it works but i found that sometimes the scope wouldn't stop slewing after i let go of the left mouse button.

what happens is there are 4 buttons to move the scope nsew, and what i discovered was it would not stop if i clicked on one of these buttons quickly. that is click to slew and let go straight away.

what seems to be happenin is windows isn't triggerin the mouse up event which stops the scope, and the button wont depress. so i'm thinkin bout usin a timer that triggers every 500 msecs and check if the left mouse button is up, and it if is, is the button up. if the button is down then step in and stop the scope.

this will also be handy for checkin if the scope is slewing too far. problem is i can't seem to find any reference to the mouse itself so that i can test to see if the left button is down.

tia
0
Comment
Question by:andru
  • 16
  • 10
  • 2
  • +2
32 Comments
 
LVL 1

Expert Comment

by:roknjohn
ID: 9846712
I doubt that windows is not sending the mouse up message. The problem probably lies in what you are doing in the events themselves.  Make a small test app with a button and a memo.  Add the three events below.  I bet you can't click the button fast enough to miss the mouse up.  This is just my guess anyway.  How about posting the code of your event handlers for the buttons.

procedure TForm1.Button1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 Memo1.Lines.Add('down');
end;

procedure TForm1.Button1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 Memo1.Lines.Add('up');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Memo1.Lines.Add('click');
end;

0
 
LVL 3

Expert Comment

by:JDuncan
ID: 9847022
How are you communicating with the serial port. Some serial components use threads which don't free up windows resources often enough.
0
 
LVL 2

Expert Comment

by:odissey1
ID: 9848366
Hi andru,

My guess is that you are using mouse Right button. Windows doesn't handle MouseUp event for mbRight if mouse left the form (or the component which intercepting MousUp-not sure). If this is the case, then my suggestion just to use mouse Left button (primary button) in your application. Windows handles mbLeft UP event correctly even mouse left application window.

Regards,
odissey1
0
 

Author Comment

by:andru
ID: 9849931
1: err, then why dont the button depress when i let go of the mouse button?

2: WriteFile(fh, PChar(buf)^, count, NumberWritten, nil)

3: and err, i am usin the left mouse button.

tia
0
 

Author Comment

by:andru
ID: 9849961
anyway, gnone of you have said how i can tell if the left mouse button is down.

tia
0
 
LVL 3

Expert Comment

by:JDuncan
ID: 9850204
To check if the button is down or up modify roknjohn's code
You casn also check the keys pressed with ShiftState so you can do shift + right down etc.

The events are only valid when the cursor is in the applications form and not outside it.

If you want it to work outside of the main form then you will have to intercept the windows mouse event messages directly , best using a journalhook .


procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button=mbRight then
    Memo1.Lines.Add('Right Down');
  else
    Memo1.Lines.Add('Left Down');
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button=mbRight then
    Memo1.Lines.Add('Right Up');
  else
    Memo1.Lines.Add('Left Up');
end;
0
 
LVL 1

Expert Comment

by:roknjohn
ID: 9850617
What events are you handling for the button?  OnClick, OnMouseDown, OnMouseUp?

The events triger in this order:
OnMouseDown
OnClick
OnMouseUp

If your OnClick handler takes a long time, the MouseUp event will be delayed. Try puting an Application.ProcessMessages in your OnClick handler.

The timer thing is a messy idea.  Just handle the windows messages and things will be ok.  The fact that your onclick event triggers, implies that the button received the MouseUp message.  If you don't believe me, try dragging a button (releasing the mouse button outside of the button control) and see if you get the OnClick event.
0
 
LVL 1

Expert Comment

by:roknjohn
ID: 9850648
Please paste your event handlers for a button so that we can SEE what you are doing, instead of guessing.
0
 

Author Comment

by:andru
ID: 9850690
when i click quickly on a button on a form - when i say button i don't mean the mouse button - the button goes down. but when i let go of the button - when i say button i mean the mouse button - the form button still remains pressed.

what is a journalhook?

tia
0
 
LVL 1

Expert Comment

by:roknjohn
ID: 9850948
I understand the problem that you are seeing on your screen.  Now, why not HELP US to help YOU solve it?  Post your code.  

What kind of buttons are you using, TButton?
What events are you handling for the buttons?
Is the scope supposed to slew only when the MOUSE button is down?

I suspect that you are doing something in the OnMouseDown event that takes a long time, i.e. serial comm.  This will make the a TButton appear to stick.  But who am I to guess?  Try using asynchronous communications, i.e. open with the FILE_FLAG_OVERLAPPED flag and use an OVERLAPPED structure when calling WriteFile();  Or, use a different thread altogether.






0
 
LVL 2

Expert Comment

by:odissey1
ID: 9851002
Hi rokjohn,

Could you post an example you mentioned regarding asyncronous writing file?

Sincerely,
odissey1
0
 

Author Comment

by:andru
ID: 9851072
k, tried processmessages and it dont work.

and the onmouseup event *dont* work, cos a: the button on the form remains down until i click on it a second time and b: the command to stop the telescope doesn't get sent to the server machine, but again, does when i click on the button a second time.

the problem only happens when i click and release *quickly* on the button.

tia
0
 
LVL 1

Expert Comment

by:roknjohn
ID: 9851090
I will respond when you POST your source code for the button handlers.  Until then, good luck.
0
 

Author Comment

by:andru
ID: 9851097
so your sayin that if the onmousedown event takes a long time, and subsequently if the mouse button is released before it ends, then the onmouseup event won't be triggered.

tia
0
 

Author Comment

by:andru
ID: 9851131
k, when you say use another thread you mean spawnin a thread from the onmouseup event eh, if so how?

tia
0
 

Author Comment

by:andru
ID: 9851141
and i don't use the onclick event.

tia
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:andru
ID: 9851241
procedure Tpop_scope.north_buttonMouseDown(
  Sender:TObject;
  Button:TMouseButton;
  Shift:TShiftState;
  X,
  Y:Integer);
begin
    LX200_SetSpeed(speed_group.itemindex);
    if n_s_flip_check.Checked then
      LX200_Move(south)
    else
      LX200_Move(north);
end;

Function LX200_Move(
  direction:integer)
  :boolean;
var
  count:integer;
  buf:string;
begin
  result:=false;
  PurgeBuffer(LX200_port);
  buf:='#:M';
  case direction of
    north:buf:=buf+'n#';
    south:buf:=buf+'s#';
    east:buf:=buf+'e#';
    west:buf:=buf+'w#';
  else
    exit;
  end;
  count:=length(buf);
  if WriteCom(LX200_port,buf,count)=false then
    exit;
  result:=true;
end;

procedure Tpop_scope.north_buttonMouseUp(
  Sender:TObject;
  Button:TMouseButton;
  Shift:TShiftState;
  X,
  Y:Integer);
begin
    if n_s_flip_check.Checked then
      LX200_StopDir(south)
    else
      LX200_StopDir(north);
end;

Function LX200_StopDir(
  direction:integer)
  :boolean;
var
  count:integer;
  buf:string;
begin
  result:=false;
  PurgeBuffer(LX200_port);
  case LX200_type of
    1:
      begin      // LX200
        buf:='#:Q';
        case direction of
          north:buf:=buf+'n#';
          south:buf:=buf+'s#';
          east:buf:=buf+'e#';
          west:buf:=buf+'w#';
        else
          buf:=buf+'#';
        end;
      end;
    2:
      begin      // Autostar
        buf:='#:Q#';
      end;
  end;
  count:=length(buf);
  if WriteCom(LX200_port,buf,count)=false then
    exit;
  result:=true;
end;

Function WriteCom(
  var fh:Thandle;
  var buf:string;
  var count:integer)
  :boolean;
var
  NumberWritten:Cardinal;
begin
  NumberWritten:=0;
  result:=WriteFile(fh, PChar(buf)^, count, NumberWritten, nil);
  count:=NumberWritten;
end;

tia

0
 

Author Comment

by:andru
ID: 9851290
oh

Function LX200_SetSpeed(
  speed:integer)
  :boolean;
var
  count:integer;
  buf:string;
begin
  result:=false;
  PurgeBuffer(LX200_port);
  case LX200_type of
    1:
      begin      // LX200
        buf:='#:R';
        case speed of
          0:buf:=buf+'S#';
          1:buf:=buf+'M#';
          2:buf:=buf+'C#';
          3:buf:=buf+'G#';
        else
          exit;
        end;
      end;
    2:
      begin      // Autostar
        case speed of
          0:buf:='#:Sw4#';
          1:buf:='#:Sw3#';
          2:buf:='#:Sw2#';
          3:buf:='#:Sw2#';
        else
          exit;
        end;
      end;
  end;
  count:=length(buf);
  if WriteCom(LX200_port,buf,count)=false then
    exit;
  result:=true;
end;

tia
0
 
LVL 1

Accepted Solution

by:
roknjohn earned 125 total points
ID: 9851428
Thanks for posting the code.  

What does LX200_SetSpeed() and PurgeBuffer() do?  

Add a temporary TMemo to your form and place several event tracers in your code.  Put them in both the MouseUp & MouseDown events of the button.  This will help you visualize what is actually happening.

Like this:
procedure Tpop_scope.north_buttonMouseDown(
  Sender:TObject;
  Button:TMouseButton;
  Shift:TShiftState;
  X,
  Y:Integer);
begin
    Memo1.Lines.Add('North Button Mouse Down - Begin');
    Memo1.Lines.Add('Setting Speed');
    LX200_SetSpeed(speed_group.itemindex);
    Memo1.Lines.Add('Speed Set');
    if n_s_flip_check.Checked then
      LX200_Move(south)
    else
      LX200_Move(north);
    Memo1.Lines.Add('North Button Mouse Down - End');
end;

procedure Tpop_scope.north_buttonMouseUp(
  Sender:TObject;
  Button:TMouseButton;
  Shift:TShiftState;
  X,
  Y:Integer);
begin
    Memo1.Lines.Add('North Button Mouse Up - Begin');
    if n_s_flip_check.Checked then
      LX200_StopDir(south)
    else
      LX200_StopDir(north);
    Memo1.Lines.Add('North Button Mouse Up - End');
end;

0
 
LVL 1

Expert Comment

by:roknjohn
ID: 9851519
With those tracers in place, try to get the button to "stick" with your quick click.  Then cut & paste the contents of the TMemo here, at the point where the button is stuck down.
0
 

Author Comment

by:andru
ID: 9853884
i've already done that. this is why i gnow that the onmouseup event isn't being triggered at all.

but i will try your traps, but can't test it till the weekend.

tia
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 9855232
andru,

Sounds like the "left button up" message (WM_LBUTTONUP) is getting "eaten" somewhere, perhaps the capture window is getting changed, can't say for sure...

Anyways, if you want a quick/fast way of checking the state of the mouse button, then the following can be used

  if (HiWord(GetAsyncKeyState(VK_LBUTTON)) > 0) then
     Caption:='Left button down' // Button is down...
  else
     Caption:='Left button up'; // Button is up...

Please note though, this will not work on Window 95 (per MSDN)

Windows 95: Windows 95 does not support the left- and right-distinguishing constants. If you call GetAsyncKeyState with these constants, the return value is zero

Perhaps this helps,
Russell



0
 

Author Comment

by:andru
ID: 9859203
well, that is a shame, cos our goal is for the project to work on affordable hardware and software.

are there any delphi solutions? is there any alternative button components that work faster than tbutton, or at least respond to the event cos i guess that windows gnows the mouse button is up so it could be a problem wiv delphi?

tia
0
 
LVL 1

Expert Comment

by:roknjohn
ID: 9859299
andru,

I doubt the problem lies in Delphi, or Windows for that matter.  The problem, most probably, is in the code that you wrote for the OnMouseDown event.  Don't believe me?  Then, change the code to something simple, like adding a string to a memo, or setting a variable.  Then see if you can get the button to "stick".  My money says you can't.

I would really like to help you solve the problem, but you continually fail to answer questions or provide the information requested.

>>With those tracers in place, try to get the button to "stick" with your quick click.  Then cut & paste the contents of the TMemo here, at the point where the button is stuck down.

>>What does [] PurgeBuffer() do?  
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 9859679

In regards to my post, slight mistake on my part (no one is perfect).... the GetAsyncKeyState WILL work for VK_LBUTTON on all versions of windows from Win95 on up. What MS was referring to as not working is:

VK_LSHIFT
VK_RSHIFT
VK_LCONTROL
VK_RCONTROL
VK_LMENU
VK_RMENU

On Win95, you can only check on VK_SHIFT, VK_CONTROL, VK_MENU (not the left/right versions).

But anyways, in regards to what the others have said, I would have to agree. There is something going on where the WM_LBUTTONUP is getting eaten/tossed. Is it possible that a message loop is getting run than picks off this message? I did some testing with the Sleep() procedure, and regardless of the delay, I still ended up getting the MouseUp event. It would probably help to see all the related code (ie PurgeBuffer) in order to better help with this

Regards,
Russell




0
 

Author Comment

by:andru
ID: 9860363
Procedure PurgeBuffer(
  var fh:Thandle);
var
  count:integer;
  buf:string;
  Timeout:TCOMMTIMEOUTS;
begin
  timeout.ReadIntervalTimeout:=10;
  timeout.ReadTotalTimeoutMultiplier:=0;
  timeout.ReadTotalTimeoutConstant:=10;
  timeout.WriteTotalTimeoutMultiplier:=0;
  timeout.WriteTotalTimeoutConstant:=Tot_timout;
  SetCommTimeouts(fh,timeout);
  try
    repeat
      count:=50;
      if debug then
        writeserialdebug(FormatDateTime('hh:mm:ss.zzz',now)+' Purge Buffer');
      ReadCom(fh,buf,count);
    until count=0;
  finally
    timeout.ReadIntervalTimeout:=Int_timout;
    timeout.ReadTotalTimeoutMultiplier:=0;
    timeout.ReadTotalTimeoutConstant:=Tot_timout;
    timeout.WriteTotalTimeoutMultiplier:=0;
    timeout.WriteTotalTimeoutConstant:=Tot_timout;
    SetCommTimeouts(fh,timeout);
  end;
end;

0
 

Author Comment

by:andru
ID: 9860404
Procedure PurgeBuffer(
  var fh:Thandle);
var
  count:integer;
  buf:string;
  Timeout:TCOMMTIMEOUTS;
begin
  timeout.ReadIntervalTimeout:=10;
  timeout.ReadTotalTimeoutMultiplier:=0;
  timeout.ReadTotalTimeoutConstant:=10;
  timeout.WriteTotalTimeoutMultiplier:=0;
  timeout.WriteTotalTimeoutConstant:=Tot_timout;
  SetCommTimeouts(fh,timeout);
  try
    repeat
      count:=50;
      ReadCom(fh,buf,count);
    until count=0;
  finally
    timeout.ReadIntervalTimeout:=Int_timout;
    timeout.ReadTotalTimeoutMultiplier:=0;
    timeout.ReadTotalTimeoutConstant:=Tot_timout;
    timeout.WriteTotalTimeoutMultiplier:=0;
    timeout.WriteTotalTimeoutConstant:=Tot_timout;
    SetCommTimeouts(fh,timeout);
  end;
end;

i took out writeserialdebug.

tia
0
 
LVL 1

Expert Comment

by:roknjohn
ID: 9860833
try not calling PurgeBuffer from within OnMouseDown, and see what happens.

You can call it from somewheres else, periodically.
0
 
LVL 1

Expert Comment

by:roknjohn
ID: 9860860
like this:

Function LX200_Move(
  direction:integer)
  :boolean;
var
  count:integer;
  buf:string;
begin
  result:=false;
//  PurgeBuffer(LX200_port);
  buf:='#:M';
  case direction of
    north:buf:=buf+'n#';
    south:buf:=buf+'s#';
    east:buf:=buf+'e#';
    west:buf:=buf+'w#';
  else
    exit;
  end;
  count:=length(buf);
  if WriteCom(LX200_port,buf,count)=false then
    exit;
  result:=true;
end;

Function LX200_StopDir(
  direction:integer)
  :boolean;
var
  count:integer;
  buf:string;
begin
  result:=false;
//  PurgeBuffer(LX200_port);
  case LX200_type of
    1:
      begin     // LX200
        buf:='#:Q';
        case direction of
          north:buf:=buf+'n#';
          south:buf:=buf+'s#';
          east:buf:=buf+'e#';
          west:buf:=buf+'w#';
        else
          buf:=buf+'#';
        end;
      end;
    2:
      begin     // Autostar
        buf:='#:Q#';
      end;
  end;
  count:=length(buf);
  if WriteCom(LX200_port,buf,count)=false then
    exit;
  result:=true;
end;

Function LX200_SetSpeed(
  speed:integer)
  :boolean;
var
  count:integer;
  buf:string;
begin
  result:=false;
//  PurgeBuffer(LX200_port);
  case LX200_type of
    1:
      begin     // LX200
        buf:='#:R';
        case speed of
          0:buf:=buf+'S#';
          1:buf:=buf+'M#';
          2:buf:=buf+'C#';
          3:buf:=buf+'G#';
        else
          exit;
        end;
      end;
    2:
      begin     // Autostar
        case speed of
          0:buf:='#:Sw4#';
          1:buf:='#:Sw3#';
          2:buf:='#:Sw2#';
          3:buf:='#:Sw2#';
        else
          exit;
        end;
      end;
  end;
  count:=length(buf);
  if WriteCom(LX200_port,buf,count)=false then
    exit;
  result:=true;
end;


0
 

Author Comment

by:andru
ID: 9860987
ok your suggestin somat that'll reduce the latency effect that presumably, you are suggestin is suppressing the mouseup event.

which brings me to my original idea that windows, and/or delphi is gnot triggering the onmouseup event. or rather the onmousedown event isn't exiting in time for the onmouseup event to execute. k.

but you haven't replied to one of my questions. how can i trigger a thread to deal with the 'move' command i send to the scope. that is start a thread that communicates wiv the thread allowin the onmousedown event to exit quickly.

tia
0
 

Author Comment

by:andru
ID: 9862884
sorry that last paragraph should read...

but you haven't replied to one of my questions. how can i trigger a thread to deal with the 'move' command i send to the scope. that is start a thread that communicates wiv the scope allowin the onmousedown event to exit quickly.

tia
0
 

Author Comment

by:andru
ID: 9892595
k,it turns out that whilst the onmousedown event is running the onmouseup event is called. when the onmousedown event exits, the onmouseup don't. so i'll put a loop into the start of onmouseup like

while mousedowneventisrunning do
  processmessages;

or somat like it.

tia
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now