windows windows windows

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
andruAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

roknjohnCommented:
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
JDuncanCommented:
How are you communicating with the serial port. Some serial components use threads which don't free up windows resources often enough.
0
odissey1Commented:
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
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

andruAuthor Commented:
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
andruAuthor Commented:
anyway, gnone of you have said how i can tell if the left mouse button is down.

tia
0
JDuncanCommented:
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
roknjohnCommented:
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
roknjohnCommented:
Please paste your event handlers for a button so that we can SEE what you are doing, instead of guessing.
0
andruAuthor Commented:
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
roknjohnCommented:
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
odissey1Commented:
Hi rokjohn,

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

Sincerely,
odissey1
0
andruAuthor Commented:
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
roknjohnCommented:
I will respond when you POST your source code for the button handlers.  Until then, good luck.
0
andruAuthor Commented:
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
andruAuthor Commented:
k, when you say use another thread you mean spawnin a thread from the onmouseup event eh, if so how?

tia
0
andruAuthor Commented:
and i don't use the onclick event.

tia
0
andruAuthor Commented:
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
andruAuthor Commented:
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
roknjohnCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
roknjohnCommented:
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
andruAuthor Commented:
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
Russell LibbySoftware Engineer, Advisory Commented:
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
andruAuthor Commented:
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
roknjohnCommented:
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
Russell LibbySoftware Engineer, Advisory Commented:

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
andruAuthor Commented:
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
andruAuthor Commented:
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
roknjohnCommented:
try not calling PurgeBuffer from within OnMouseDown, and see what happens.

You can call it from somewheres else, periodically.
0
roknjohnCommented:
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
andruAuthor Commented:
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
andruAuthor Commented:
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
andruAuthor Commented:
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.