• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 179
  • Last Modified:

ScrollLock On/Off problem

Hi

I'm using ScrollLock to signal that a certain thread is running by blinking and i have a problem that it'll not always set to off state after finishing. This is the timer function that is used to blink the LED (it's set to 200ms):

procedure TimerScrollLockTimer(Sender: TObject);
var
  KeyState : TkeyboardState;

begin
  GetKeyboardState(KeyState);
  if Opcje.MAINscrolllock then
    begin
      if KeyState[VK_SCROLL] = 0 then
        begin
          KeyState[VK_SCROLL] := 1;
          SetKeyboardState(KeyState);
          SetScroll(True);
        end
      else
        begin
          KeyState[VK_SCROLL] := 0;
          SetKeyboardState(KeyState);
          SetScroll(False);
        end;
    end
  else
    TimerScrollLock.Enabled := False;
end;

and in the thread after disabling this timer i've placed sthing like this:

    if KeyState[VK_SCROLL] <> 0 then
      SetScroll(False);


and the SetScroll procedure looks like this:

procedure TOknoGlowne.SetScroll(bState:Boolean);
var
  KeyState : TKeyboardState;

begin
  GetKeyboardState(KeyState);
  if ((bState) and (not((KeyState[VK_NUMLOCK] and 1)=1)) or ((not(bState)) and ((KeyState[VK_NUMLOCK] and 1)=1))) then
    begin
      keybd_event(VK_SCROLL, $45, (KEYEVENTF_EXTENDEDKEY or 0), 0);
      keybd_event(VK_SCROLL, $45, (KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP), 0);
    end;
end;

using this code sometimes the LED stays on and sometimes turns off. I don't know why. Anyone can tell me how can i fix this ??
0
szafran81
Asked:
szafran81
  • 4
  • 4
1 Solution
 
2266180Commented:
well ... didn't try but just by looking at the code I see one inconsistancy and possible logical error:
in your timer, in order to turn the scroll off, you do:
        begin
          KeyState[VK_SCROLL] := 0;
          SetKeyboardState(KeyState);
          SetScroll(False);
        end;
but in the other place you do just:
    if KeyState[VK_SCROLL] <> 0 then
      SetScroll(False);

try replacing that with:
    if KeyState[VK_SCROLL] <> 0 then
        begin
          KeyState[VK_SCROLL] := 0;
          SetKeyboardState(KeyState);
          SetScroll(False);
        end;

and see if that works right now :)
0
 
szafran81Author Commented:
nothing :/

tried every combination of setkeyboardstate/setscroll and also without the setkeyboardstate and none of them made my problem go away :/
0
 
2266180Commented:
can you outline the exact behaviour? like:
- give exact steps to reproduce the issue (start a thread, which starts the blinking of the led, thread finishes, bliknikg should finish, but instead of that, the led stay up - this is just an example and is what I understood)

if what I understood is correct then I have to ask you:
- how many threads are there? if more than 1, are all trheads signaling through blinking of the scroll lock? if yes, then that might be your problem.
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
szafran81Author Commented:
ok

it's like that:

i have a Timer1 - it's interval is 5mins - when it launches it starts the scroll lock timer and checks a few things and if theyre ok it upload sthing on my ftp (the ftp uplod is in a thread). timer1 waits for the thread to terminate and then goes on. on the end of timer1 scroll lock timer is disabled. only 1 thread signaling this way.

i've tried it on a temp app putting in the timer1 a sleep(10000) instead of the thread wait and the same happens... sometimes the led stays off and sometimes on

is there a way to set the led specifically on or off and not just to change it's state (like it's in the setscroll procedure) ??
0
 
2266180Commented:
hm. I think your code for "blinking" was wrong. here is the code that works just fine for me:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Timer2: TTimer;
    Memo1: TMemo;
    procedure Timer1Timer(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
  private
    { Private declarations }
    done:boolean;
    procedure mynotif(sender:tobject);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses unit2;

procedure setSLState(st:byte);
begin
  keybd_event(VK_SCROLL, st, (KEYEVENTF_EXTENDEDKEY or 0), 0);
  keybd_event(VK_SCROLL, st, (KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP), 0);
end;

procedure TForm1.mynotif(sender:tobject);
begin
  done:=true;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var t:mythread;
begin
  memo1.lines.add('timer1.start');
  timer1.enabled:=false;// make sure we don't start before we finish
                        // ftp copy may take a while
  timer2.enabled:=true;
  done:=false;
  t:=mythread.Create(true);
  t.FreeOnTerminate:=true;
  t.OnTerminate:=mynotif;
  t.Resume;// start ftp copy simulation (sleep 10 sec)
  memo1.lines.add('thread start');
  while not done do
  begin
    application.processmessages;
    sleep(100);
  end;
  // thread is freed already
  memo1.lines.add('thread end.setting scroll off');
  setSLState(0);
  timer2.enabled:=false;
  timer1.enabled:=true;
  memo1.lines.add('timer1.end');
end;

procedure TForm1.Timer2Timer(Sender: TObject);
var
  KeyState : TkeyboardState;
begin
  GetKeyboardState(KeyState);
  setSLState( (KeyState[VK_SCROLL]+1) mod 2 );
end;

end.


note that timer 1 has a 30 sec interval and timer2 has a 200ms interval. mythread just does: sleep(10000);
works like a charm.
0
 
szafran81Author Commented:
and how many times did you test it ??

it doesn't work correctly

your proc also is for changing the state and not for definately turning it off

try this:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure SetScroll(st:byte);
begin
  keybd_event(VK_SCROLL, st, (KEYEVENTF_EXTENDEDKEY or 0), 0);
  keybd_event(VK_SCROLL, st, (KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP), 0);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  SetScroll(0);
end;

end.

and launch it a few times. it doesn't matter whats in the SetScroll parameter this little proggy will always only change scroll locks led state.
0
 
2266180Commented:
I actually let it run for about 3-4 times (considering that before it always gave bad results at the second loop, and since it worked ok, I thought it's ok. mabye the timeing was of such nature that after the loop it always remained set, and the last call turned it off.

I just noticed an error in your procedure TOknoGlowne.SetScroll(bState:Boolean); procedure: in the if statement, you were testing against numlock not scroll lock :)

anyway, I made some modifications to our codes and some other code found on the net AND some stuff from MSDN so this is the final working version:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type TToggle=(tOff,tOn);

procedure SetScroll(toggle:TToggle);
var state:TToggle; KeyState:TKeyboardState;
begin
  GetKeyboardState(KeyState);
  state:=TToggle(KeyState[VK_SCROLL] mod 2);// get the low order first bit (as per MSDN)
  if (state=toggle) then
    exit;
  if (Win32Platform = VER_PLATFORM_WIN32_NT) then
  begin
    keybd_event(VK_SCROLL, MapVirtualKey(VK_SCROLL, 0), (KEYEVENTF_EXTENDEDKEY or 0), 0);
    keybd_event(VK_SCROLL, MapVirtualKey(VK_SCROLL, 0), (KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP), 0);
  end                                        else
  begin
    KeyState[VK_SCROLL]:=byte(toggle);
    SetKeyboardState(KeyState);
  end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  setscroll(tOff);
end;

end.


if you modify the if statement (num into scroll) in your initial code, it should work as well.
0
 
szafran81Author Commented:
now it works great
thank you very much for your help
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 4
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now