I've uset GetRawInputData and it should be catched in the WM_INPUT message.
But now i'm implementing GetRawInputBuffer to reduce amount of WM_INPUT messages retrieved. Mice equipment today is very high resolution and can easily flood my program with WM_INPUT messages, so I figure using a buffered version of RawInput is the best solution.
My question is, where should I process it, microsoft sample use GetRawInputBuffer using a private windows message. Can I catch it in the peekmessage loop and just dump the WM_INPUT message from the windows procedure handler?
(Btw, there was not a single hit on "RawInput" or "GetRawInputBuffer" on this site, about time someone started such a thread :8))
Well, there is no need for buffered input, because you can handle the WM_INPUT message. The buffered method needs a timer or some other event, that let you read the input.
Quote from: zemtex on January 30, 2011, 12:00:35 AMMice equipment today is very high resolution and can easily flood my program with WM_INPUT messages, so I figure using a buffered version of RawInput is the best solution.
why? - for both methods you must process the same number of event at a time.
qWord
If you move your mouse 500 pixels across with a 5700 dpi mouse and press 3-4 keys at the same time, it will generate events at the same pace, thats true, but the WM_INPUT version will rerun and fill in a message structure for each event over and over, while the buffered variant will only need to process it once without having the message resent.
If you use the buffered variant you will have code that runs and loops undisturbed, if you use the other variant you will run code, parse a long msg structure again and this adds overhead.
maybe your underrated the speed of today's computers :bg
There is no doubt that a modern computer can handle both ways, I even doubt you would notice any difference. Thats not the case, the case is when you combine the methods with demanding game-code, what will be the result then.
To tell the truth, I was tempted to use the easiest variant. But I don't go for cheap solutions just because the other is harder to implement. Thats a bad habit.
Btw, do you know of a good way to implement the buffered variant, are you absolutely sure you have to use a timer, can you not parse the structures in the message loop?
You checked this (http://msdn.microsoft.com/en-us/library/ms645595%28v=vs.85%29.aspx), I suppose?
QuoteGetRawInputBuffer Function
Performs a buffered read of the raw input data.
Syntax
Copy
UINT WINAPI GetRawInputBuffer(
__out_opt PRAWINPUT pData,
__inout PUINT pcbSize,
__in UINT cbSizeHeader
);
Parameters
pData [out, optional]
Type: PRAWINPUT
A pointer to a buffer of RAWINPUT structures that contain the raw input data. If NULL, the minimum required buffer, in bytes, is returned in *pcbSize.
Been readin all the ms docs yesterday, almost any sublink from that page is purple as i've clicked almost all of them and gone deeper into the topic. I spent about 6 hours reading on the subject.
I've already implemented the non-buffered variant and to tell the truth, its not that bad, the amount of messages it generates is really not as bad as I thought and it shouldnt produce a problem on performance.
hi,
I've also played a bit with it and end up in an bug in WOW64. However, after some fix it works: look for the line
Quote.if [edi].RAWINPUT.data.keyboard.VKey+8 == VK_J
the displacement of 8 is normally not needed - but win7-x64 seems to use wrong struct definition (WIN64) for the RAWINPUTHEADER-struct.(?)
include masm32rt.inc
.686p
.mmx
.xmm
RAWINPUTDEVICE struct
usUsagePage USHORT ?
usUsage USHORT ?
dwFlags DWORD ?
hwndTarget HWND ?
RAWINPUTDEVICE ends
RAWINPUTHEADER struct
dwType DWORD ?
dwSize DWORD ?
hDevice HANDLE ?
wParam WPARAM ?
RAWINPUTHEADER ends
PRAWINPUTHEADER typedef ptr RAWINPUTHEADER
RAWMOUSE struct
usFlags WORD ?
union
ulButtons DWORD ?
struct
usButtonFlags WORD ?
usButtonData WORD ?
ends
ends
ulRawButtons DWORD ?
lLastX SDWORD ?
lLastY SDWORD ?
ulExtraInformation DWORD ?
RAWMOUSE ends
PRAWMOUSE typedef ptr RAWMOUSE
RAWKEYBOARD struct
MakeCode WORD ?
Flags WORD ?
Reserved WORD ?
VKey WORD ?
Message DWORD ?
ExtraInformation DWORD ?
RAWKEYBOARD ends
PRAWKEYBOARD typedef ptr RAWKEYBOARD
RAWHID struct
dwSizeHid DWORD ?
dwCount DWORD ?
bRawData BYTE 1 dup (?)
RAWHID ends
PRAWHID typedef ptr RAWHID
RAWINPUT struct
header RAWINPUTHEADER <>
union data
mouse RAWMOUSE <>
keyboard RAWKEYBOARD <>
hid RAWHID <>
ends
RAWINPUT ends
PRAWINPUT typedef ptr RAWINPUT
RawInputThread proto hWnd:HWND
.data?
hInstance HINSTANCE ?
dwThreadID DWORD ?
hCloseevent HANDLE ?
hwnd HWND ?
.code
WndProc proto hWnd:HWND,uMgs:UINT,wParam:WPARAM,lParam:LPARAM
main proc
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
mov hInstance,rv(GetModuleHandle,0)
mov wc.hInstance,eax
mov wc.cbSize,SIZEOF wc
mov wc.style,CS_HREDRAW or CS_VREDRAW or CS_SAVEBITS
mov wc.lpfnWndProc,OFFSET WndProc
mov wc.cbClsExtra,0
mov wc.cbWndExtra,0
mov wc.hIcon,rv(LoadIcon,0,IDI_APPLICATION)
mov wc.hIconSm,eax
mov wc.hCursor,rv(LoadCursor,0,IDC_ARROW)
mov wc.lpszMenuName,0
mov wc.hbrBackground,rv(GetStockObject,WHITE_BRUSH);
mov wc.lpszClassName,chr$("Win32Wnd")
invoke RegisterClassEx,ADDR wc
mov ebx,ASM(mov edi,rv(GetSystemMetrics,SM_CXSCREEN))
mov esi,rv(GetSystemMetrics,SM_CYSCREEN)
shr ebx,1
shr eax,1
shr edi,2
shr esi,2
mov esi,rv(CreateWindowEx,0,wc.lpszClassName,"Win32Wnd",WS_VISIBLE or WS_SYSMENU or WS_MAXIMIZEBOX or WS_MINIMIZEBOX or WS_SIZEBOX,edi,esi,ebx,eax,0,0,hInstance,0)
mov hwnd,eax
invoke UpdateWindow,esi
.while 1
invoke GetMessage,ADDR msg,0,0,0
.break .if !eax || eax == -1
invoke TranslateMessage,ADDR msg
invoke DispatchMessage,ADDR msg
.endw
xor eax,eax
ret
main endp
WndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.if uMsg == WM_CLOSE
invoke SetEvent,hCloseevent
invoke PostQuitMessage,0
.elseif uMsg == WM_CREATE
mov hCloseevent,rv(CreateEvent,0,1,0,0)
invoke CreateThread,0,0,OFFSET RawInputThread,hCloseevent,0,ADDR dwThreadID
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
WndProc endp
RawInputThread proc hCloseEvent:HANDLE
LOCAL rid:RAWINPUTDEVICE
LOCAL hWndDummy:HWND
LOCAL cbSize:DWORD
LOCAL msg:MSG
mov hWndDummy,rv(CreateWindowEx,0,"button",0,0,0,0,1,1,0,0,hInstance,0)
mov rid.usUsagePage,1
mov rid.usUsage,6
mov rid.dwFlags,0
m2m rid.hwndTarget,hWndDummy
invoke RegisterRawInputDevices,ADDR rid,1,SIZEOF RAWINPUTDEVICE
.while 1
invoke MsgWaitForMultipleObjects,1,ADDR hCloseEvent,0,INFINITE,QS_RAWINPUT
.if eax == WAIT_OBJECT_0+1
.break .if rv(GetRawInputBuffer,0,ADDR cbSize,SIZEOF RAWINPUTHEADER)
mov eax,cbSize
imul eax,eax,16
mov cbSize,eax
.break .if !ASM(mov edi,alloc(cbSize))
.while 1
.if ASM( mov esi,rv(GetRawInputBuffer,edi,ADDR cbSize,SIZEOF RAWINPUTHEADER)) != -1 && eax
mov ebx,edi
push esi
.while esi
.if [edi].RAWINPUT.header.dwType == RIM_TYPEKEYBOARD
.if [edi].RAWINPUT.data.keyboard.VKey+8 == VK_J ; !!! fix for wow64
fn MessageBox,hwnd,"sdfsdf",0,0
.endif
.endif
; align 4 needed !
add edi,SIZEOF RAWINPUT + 3
and edi,-4
dec esi
.endw
pop esi
.else
.break
.endif
.endw
.while 1
.break .if !rv(PeekMessage,ADDR msg,0,WM_INPUT,WM_INPUT,PM_REMOVE)
.endw
free edi
.else
.break
.endif
.endw
invoke DestroyWindow,hWndDummy
ret
RawInputThread endp
end main
The RAWMOUSE structure is bad unless you add 2 bytes at the beginning. It is off by 2 bytes using win32.
The windows documentation says that RawMouse usFlags is a word sized, but I need to add 2 bytes for the adressing to be correct.
well, the struct RAWINPUT must be/is aligned to 4 - have you checked this?
I was about to say so, windows aligns the structure.
I had my structures defined individually, because of that I had to align the RawMouse structure individually for it to work, so I simply just merged all structures and nested them.
RawInput struct 4
header RawInputHeader {}
UNION data
STRUCT mouse
usFlags word ?
UNION
ulButtons dword ?
STRUCT
usButtonFlags word ?
usButtonData word ?
ENDS
ENDS
ulRawButtons dword ?
lLastX dword ?
lLastY dword ?
ulExtraInformation dword ?
ENDS
STRUCT keyboard
MakeCode word ?
Flags word ?
Reserved word ?
VKey word ?
Message dword ?
ExtraInformation dword ?
ENDS
STRUCT hid
dwSizeHid dword ?
dwCount dword ?
bRawData byte ?
ENDS
ENDS
RawInput ends
have you tested my program on your machine? (after removing the +8)
No I dont have win64 here.
it is an 32Bit application - after removing the displacement of 8 it should work (theoretically :-))
see the attachment: a msgbox should appear, when pressing 'j'
Ok I will look into it, I thought it was the single raw read variant, Didnt pay too much attention. :bdg
Why not use the main window as the target and fetch it in peekmessage? I read somewhere that using a dummy window is quite common. But why is it?
To be able to run the main loop undisturbed?
window-related message are only post to the thread that create the window - that the whole reason.
now, did the programm work?
Yes works wonderfully
The only thing I would add is RIDEV_NOLEGACY to the flags when creating rawinput to get rid of mouse and key legacy messages.
I would also avvoid allocating memory, the buffer doesnt go above 40 bytes for keyboard and mouse raw inputs, you can declare that
buffer. Even worse is to use globalalloc.
Other than that it looks good to me. I will copy your philosophy, but code my own code. I have my own codestyle so i'm sure you understand
that I need to code it myself. But like I said, I have studied the philosophy behind the code and will copy some of that.
:U
Quote from: zemtex on January 30, 2011, 11:21:35 PMI would also avoid allocating memory, the buffer doesnt go above 40 bytes for keyboard and mouse raw inputs, you can declare that
buffer.
That's dangerous - what is if windows collect two or more events and send them to you in a bunch? (for this case the function is designed)
If you use GetRawInputBuffer you should allocate using heap allocation (not globalalloc) but if you use GetRawInputData you should use a local declared buffer of 40 bytes.
Allocating memory takes time, you could also measure the peak usage of memory during runtime to find a good sized buffer and then preallocate it.
Memory allocation is not such a big deal (usually), but we're dealing with directinput coding here so it is relevant, allocating memory should be avvoided if possible, especially in a RawInput handler, we want things to happen FAST and get the hell out of there.
If your buffer is too small, catch an error if the returned required size is above your buffer size, you can avvoid the danger that way.
Also beware when you declare RIDEV_NOLEGACY your window will not be taking mouse clicks or keyboard clicks, it works best for fullscreen programs. But then again, games that use RawInput is usually a full program :dazzled:
If you dont declare it you will recieve multiple unneccesary WM_KEYUP WM_KEYDOWN and such useless messages that you wont process anyway.
According to windows api documentation if you create a secondary dummy window and it gets focus, the main window will be in the background moving from priority 9 down to 7 and the rawinput handler window gets priority 9. Perhaps we ought to setfocus to the main window after creating the dummy window?
I've peeked into "Message-Only-Windows", I was hoping this could be used in replacement of creating a dummy "button" window. But I have my doubts it can be used for that. Anyone check it out: http://msdn.microsoft.com/en-us/library/ms632599%28v=vs.85%29.aspx#message_only
It looks like it is specially designed for this purpose.
Do you think this special message processing window can be used as a rawinputbuffer handler? The docs says such a window cannot be enumerated. :snooty:
You can set the main window back to top priority by using SetForegroundWindow function
Btw, i've been thinking. Instead of using an event in your handler, you could kill the event and just use PostThreadMessage. That will eliminate some complexity and reduce overhead.
I measured amount of messages retrieved by using a 5700 dpi mouse at full resolution and moving it as fast as possible, I measured the event count per second.
It peaked at 507 events per second (When moving mouse as fast as possible) I didnt output anything while measuring, I set a tickcounter every 1000 ms and output the result to the window caption text.
I couldnt get any higher number on any other dpi settings either. Thats nothing a computer cant handle. Thats not even a single event per millisecond. I have underestimated computers :bdg
zemtex,
the question is why to use raw input. - the normal message processing (WM_MOUSEMOVE,...) is really enough for mouse and keyboard input. Also, as I notice, there are bugs in the implementation at least on Win7-x64.
qWord
The good part of using legacy messages is that you dont have to deal with low level coding and you get pointer ballistics integrated in a single package.