Hi,
I'm trying to flash the keyboard LEDs on WinXP:



invoke keybd_event,VK_NUMLOCK,0,1,0


IF I have the NUMLOCK LED on this will turn it off else it will turn it on.
I cannot execute this twice because it will turn it on but never off again.
Then, if I want to turn it off via keyboard it takes two key-presses which
makes me figure that is not remembered wherever it should be (kb driver,
some place in XP).

Somebody know a solution ?

Thanks,

goofee
Posted on 2002-07-23 16:18:02 by goofee
Hmmm...
i just found a little program made by stefan krause (alias YaWNS) to change the state of the different leds on a keyboard. this is what i found in the source:



.if ax == 300
invoke MessageBox,NULL,offset Sorry2,offset Sorry1,MB_OK
; invoke keybd_event,VK_NUMLOCK,90h,KEYEVENTF_EXTENDEDKEY,0
; invoke keybd_event,VK_NUMLOCK,90h,KEYEVENTF_KEYUP,0


he just commented out the two lines to change the state of the led and displays a messagebox with the text that it isn't possible to toggle the NUMLOCK led with this function. i don't know what's wrong (i didn't try the two functions either), perhaps he can tell you what prevented this two functions to work.

a thing that make your life even more difficult is, that you're using xp... perhaps you can use Win I/O (made by thomas http://www.madwizard.org ?) to set the leds, but you gotta know the ports and stuff... i don't know much about that.

sorry that this won't help you much (i think)..

bye
Posted on 2002-07-23 16:31:13 by NOP-erator
Hmm..... did you look up the API on MSDN? There is a C example right under it ;)



#include <windows.h>

void SetNumLock( BOOL bState )
{
BYTE keyState[256];

GetKeyboardState((LPBYTE)&keyState);
if( (bState && !(keyState[VK_NUMLOCK] & 1)) ||
(!bState && (keyState[VK_NUMLOCK] & 1)) )
{
// Simulate a key press
keybd_event( VK_NUMLOCK,
0x45,
KEYEVENTF_EXTENDEDKEY | 0,
0 );

// Simulate a key release
keybd_event( VK_NUMLOCK,
0x45,
KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
0);
}
}

void main()
{
SetNumLock( TRUE );
}

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/keybd_event.asp


P.S.: Nop, WinIO (www.internals.com, headers at www.madwizard.org) is a bit overkill, just to simulate a keypress :)
Posted on 2002-07-24 03:57:06 by bazik
P.S.: Nop, WinIO (www.internals.com, headers at www.madwizard.org) is a bit overkill, just to simulate a keypress :)


:grin:
Posted on 2002-07-24 04:11:24 by NOP-erator
Thats how I enable Numlock on all consoles on my Linux box:



case `tty` in
/dev/tty[0-9]) setleds -D +num
;;
esac


:)
Posted on 2002-07-24 04:17:16 by bazik
OK, thanks everyone.
I did search Google extensively and I also searched the board.
I'm glad there is an easier way than WinIO :grin:
So here is SetNumLock rewritten:



SetNumLock PROC bOnOff :DWORD

LOCAL keyState[256] :BYTE

invoke GetKeyboardState, addr keyState
lea eax,keyState
mov al,byte ptr [eax+VK_NUMLOCK]
and eax,0FFh
xor eax,1
cmp eax,bOnOff
jnz @F
invoke keybd_event,VK_NUMLOCK,45h,KEYEVENTF_EXTENDEDKEY or 0,0
invoke keybd_event,VK_NUMLOCK,45h,KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP,0
@@:
ret
SetNumLock ENDP
Posted on 2002-07-24 06:32:00 by goofee
in MSDN we can read about keyb_event :
Windows NT/2000/XP: This function has been superseded. Use SendInput instead.


So, using SendInput I figured out this:
1. as with keyb_event, You'll need to simulate both 'press' and 'release' ;



[size=9]
.586p
.model flat,STDCALL
OPTION CASEMAP:NONE
UNICODE = 0

include WINDOWS.inc
;include APImacro.mac
include INPUTDEF.inc

include Kernel32.inc
include User32.inc
includelib Kernel32.lib
includelib User32.lib

KEYEVENTF_UNICODE EQU 0004h
KEYEVENTF_SCANCODE EQU 0008h

KEYBDINPUT STRUC
wVk WORD ?
wScan WORD ?
dwFlags DWORD ?
time DWORD ?
dwExtraInfo LPLONG ?
KEYBDINPUT ENDS

INPUT STRUC
_type DWORD ?
UNION
mi MOUSEINPUT <>
ki KEYBDINPUT <>
hi HARDWAREINPUT <>
ENDS
INPUT ENDS

.DATA
inputevtcode INPUT <INPUT_KEYBOARD, <{?}>>

.CODE
Start:
mov inputevtcode.ki.wVk, 0
mov inputevtcode.ki.dwFlags, KEYEVENTF_SCANCODE
mov inputevtcode.ki.time, 0
mov inputevtcode.ki.dwExtraInfo, 0

invoke MapVirtualKey, VK_NUMLOCK, 0
mov inputevtcode.ki.wScan, ax
invoke SendInput, 1, offset inputevtcode, sizeof inputevtcode

mov inputevtcode.ki.dwFlags, KEYEVENTF_SCANCODE+KEYEVENTF_KEYUP
invoke SendInput, 1, offset inputevtcode, sizeof inputevtcode

invoke ExitProcess, eax

End Start
[/SIZE]
Posted on 2002-07-24 09:05:20 by Andycar
Or even better:


Set_vKey PROC uses esi wVkey:DWORD,bOnOff:DWORD
LOCAL inputevtcode:INPUT
LOCAL keyState[256]:BYTE

invoke GetKeyboardState, addr keyState
lea eax,keyState
mov ecx, wVkey
mov al,byte ptr [eax+ecx]
and eax,0FFh
xor eax,1
cmp eax,bOnOff
jnz @F

lea esi, inputevtcode
ASSUME esi: PTR INPUT
mov [esi]._type, INPUT_KEYBOARD
mov [esi].ki.wVk, 0
mov [esi].ki.dwFlags, KEYEVENTF_SCANCODE
mov [esi].ki.time, 0
mov [esi].ki.dwExtraInfo, 0

invoke MapVirtualKey, wVkey, 0
mov [esi].ki.wScan, ax
;simulate a key press
invoke SendInput, 1, esi, sizeof inputevtcode
or [esi].ki.dwFlags, KEYEVENTF_KEYUP
;simulate a key release
invoke SendInput, 1, esi, sizeof inputevtcode
@@:
ret
Set_vKey ENDP
Posted on 2002-07-24 09:42:16 by Andycar
I forgot,
This would define some structures & constants not presently there in WINDOWS.inc:
Posted on 2002-07-24 10:15:04 by Andycar
Sorry to dig this back out but none of the solutions work satisfactory.
I've tried all the solutions (keybd_event,SendInput) but like I said
I need to make num lock 'flash'. So I need to turn it on AND off again.

Using Andycars method (or keybd_event):




invoke Set_vKey,VK_NUMLOCK,TRUE
invoke Sleep,500
invoke Set_vKey,VK_NUMLOCK,FALSE


will not turn it on and off within one run of the program.
Restarting it will eventually turn it off.

Here is the program using Andycars code:
Posted on 2002-08-03 11:30:25 by goofee
goofee, did you read the Remarks (last paragraph) for SendInput?
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/sendinput.asp
Actually, the real problem might be having to press the key twice: DOWN/UP, DOWN/UP.
Posted on 2002-08-03 11:43:52 by bitRAKE
Well, that was the problem at first but that didn't help it.

Current code IS sending two keys (also tried with keybd_event):



invoke SendInput, 1, esi, sizeof inputevtcode
or [esi].ki.dwFlags, KEYEVENTF_KEYUP
;simulate a key release
invoke SendInput, 1, esi, sizeof inputevtcode
Posted on 2002-08-03 11:56:49 by goofee
goofee, it works for me. The code you posted sends one key down,
and one key up - not two keys. :)
	push 100

@@: invoke Set_vKey,VK_NUMLOCK,TRUE
invoke Sleep,100
invoke Set_vKey,VK_NUMLOCK,FALSE
invoke Sleep,100
dec DWORD PTR [esp]
jne @B
pop eax
Posted on 2002-08-03 11:59:00 by bitRAKE
OK !!!!!

Now, again.

This time with keybd_event (same difference).

Send two keys (twice up AND down):



start:

invoke SetKeyboarLED,VK_NUMLOCK,TRUE ; key down AND up #1
invoke Sleep,500
invoke SetKeyboarLED,VK_NUMLOCK,FALSE ; key down AND up #2
invoke ExitProcess,NULL

END start





SetKeyboarLED PROC LEDNumber :DWORD,
bOnOff :DWORD

LOCAL keyState[256] :BYTE

invoke GetKeyboardState, addr keyState
lea eax,keyState
add eax,LEDNumber
mov al,byte ptr [eax]
and eax,0FFh
xor eax,1
cmp eax,bOnOff
jnz Done
invoke MapVirtualKey,LEDNumber,0
invoke keybd_event,LEDNumber,eax,KEYEVENTF_EXTENDEDKEY or 0,0 ;3A,46 ;DOWN HERE
invoke keybd_event,LEDNumber,eax,KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP,0 ;UP HERE
Done:
ret
SetKeyboarLED ENDP


Now this should turn num lock on and off, shouldn't it ??????
Well, it DOES NOT !!!!
Posted on 2002-08-03 12:06:01 by goofee
This is what is really happening:
	invoke SetKeyboarLED,VK_NUMLOCK,TRUE   ;    key [b]UP[/b] AND up #1

invoke Sleep,500
i.e. Does nothing ;)
Posted on 2002-08-03 12:07:59 by bitRAKE
Don't see why:



invoke keybd_event,LEDNumber,eax,KEYEVENTF_EXTENDEDKEY or 0,0 ;3A,46 ;DOWN HERE
invoke keybd_event,LEDNumber,eax,KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP,0 ;UP HERE


:rolleyes:
Posted on 2002-08-03 12:16:46 by goofee
Why don't you trace through the logic and you'll see why.
Here is a little graph for you - just fill it in:
  | U | D |

--|---|---|
U | | |
--|-------|
D | | |
--|---|---|
Posted on 2002-08-03 12:27:41 by bitRAKE
Well, I'd rather say there is nothing wrong with my logic
but with the value GetKeyBoardState returns for numlock:

1. numlock is initially off
2. GetKeyboardState returns zero for numlock
3. keybd_event,LEDNumber,eax,KEYEVENTF_EXTENDEDKEY or 0,0 presses key
4. keybd_event,LEDNumber,eax,KEYEVENTF_EXTENDEDKEY or KEYEVENTF_UP,0 releases the key
5. numlock is now on
6. GetKeyboardState returns zero again
7. The keybd_event functions are skipped.
7. Running the program again with numlock still on GetKeyboardState returns 1 for numlock which is correct.

If it weren't like that there would be the same error in the code Andycar posted.
Posted on 2002-08-03 13:00:55 by goofee
The key to understanding: :grin:

(try this):

invoke Set_vKey,VK_NUMLOCK,TRUE ;sumulates first 'key-down' + 'key-up' pair, i.e. just as it was pressed by you
invoke Sleep,2500
invoke Set_vKey,VK_NUMLOCK,TRUE ; does the same !!!

;Now the key was pressed TWO TIMES...

(or this)
invoke keybd_event,VK_NUMLOCK,45h,KEYEVENTF_EXTENDEDKEY or 0,0 ;3A,46 ;DOWN HERE
invoke keybd_event,VK_NUMLOCK,45h,KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP,0 ;UP HERE
invoke Sleep,2500
invoke keybd_event,VK_NUMLOCK,45h,KEYEVENTF_EXTENDEDKEY or 0,0 ;3A,46 ;DOWN HERE
invoke keybd_event,VK_NUMLOCK,45h,KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP,0 ;UP HERE

;This will also make it flash one time baby
Posted on 2002-08-03 19:26:07 by Andycar
Thanks,

you're right and it looks like I totally screwed up on this. :rolleyes:
Sorry, bitRake, for making such a mess out off it.

One more thing, though.
What got me a little distracted was the bOnOff parameter.
Why use it at all if you always have to pass in TRUE ?

Thanks for y'all's patience :alright: ,

goofee
Posted on 2002-08-03 19:48:29 by goofee