Solved

windows windows windows

Posted on 2003-11-30
32
488 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

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
 

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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
In this video, viewers will be given step by step instructions on adjusting mouse, pointer and cursor visibility in Microsoft Windows 10. The video seeks to educate those who are struggling with the new Windows 10 Graphical User Interface. Change Cu…
Add bar graphs to Access queries using Unicode block characters. Graphs appear on every record in the color you want. Give life to numbers. Hopes this gives you ideas on visualizing your data in new ways ~ Create a calculated field in a query: …

728 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