Patch for dinput keyboard
arjen at blehq.org
arjen at blehq.org
Sat May 18 22:01:19 CDT 2002
On Sun, 19 May 2002, Ove Kaaven wrote:
>
> On Sat, 18 May 2002 arjen at blehq.org wrote:
>
> > This 'beautiful' patch I wrote for fixing dinput was silently ignored.
> > Can someone comment about it?
>
> The x11drv parts are unnecessary. It's done differently (more
> Alexandre-style) in WineX. Since there's no particular need to hold this
> piece back whether or not the code trade Gav wants to do is successful
> (especially since you're working on it in any case), I may as well use it
> to help you get this functionality into Wine. Here's the code merged
> against ReWind, licensed under the X11 license. You may have to merge it
> again against the current Wine code yourself, since some other DirectInput
> patches may not have been applied to ReWind. (Of course, change this in
> other ways as well if you feel like it.)
>
Thank you, I guess. I don't want to get involved in any politics. I don't
really know anything about other trees.
I think the hook is agood idea.
I think the best thing to do now is to get best out of the two different
implementations. I have some comments about your code, and I can improve
mine with yours. I'll make a new patch from these two, and send it later.
If anybody has any other comments, I would like to hear them.
> + /* SysKeyboardAImpl */
> + BYTE keystate[256];
There is not a real reason to get a keystate per keyboard, as there is
only one keyboard. I made this global. Is that OK?
> static HRESULT WINAPI SysKeyboardAImpl_SetProperty(
> LPDIRECTINPUTDEVICE2A iface,REFGUID rguid,LPCDIPROPHEADER ph
> )
> @@ -115,13 +169,19 @@
>
> TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
> TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n",
> - ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow);
> + ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow);
> if (!HIWORD(rguid)) {
> switch ((DWORD)rguid) {
> case (DWORD) DIPROP_BUFFERSIZE: {
> - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
> -
> - TRACE("(buffersize=%ld)\n",pd->dwData);
> + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
> +
> + TRACE("buffersize = %ld\n",pd->dwData);
> +
> + This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
> + pd->dwData * sizeof(DIDEVICEOBJECTDATA));
How do you know the data_queue is free (NULL)? My patch made sure that:
!Acquired => (data_queue == NULL)
And setproperty can only be invoked when !Acquired.
> static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState(
> LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
> )
> {
> - DWORD i;
> + ICOM_THIS(SysKeyboardAImpl,iface);
> +
> + if (!This->acquired)
> + return DIERR_NOTACQUIRED;
I have this game that does not acquire the device. Guess what? It works
with windows.
>
> - memset( ptr, 0, len );
> - if (len != 256)
> - {
> - WARN("whoops, got len %ld?\n", len);
> - return DI_OK;
> - }
> - for (i = 0; i < 0x80; i++)
> - {
> - WORD vkey = MapVirtualKeyA( i, 1 );
> - if (vkey && (GetAsyncKeyState( vkey ) & 0x8000))
> - {
> - ((LPBYTE)ptr)[i] = 0x80;
> - ((LPBYTE)ptr)[i | 0x80] = 0x80;
> - }
> - }
> - return DI_OK;
> + memset( ptr, 0, len );
> + if (len != 256)
> + {
> + WARN("whoops, got len %ld?\n", len);
> + return DI_OK;
DI_OK?
> + }
> + memcpy(ptr, This->keystate, len);
> + return DI_OK;
> }
>
> static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData(
> @@ -162,34 +258,53 @@
> )
> {
> ICOM_THIS(SysKeyboardAImpl,iface);
> - int i, n;
> + DWORD len, nqtail;
> +
> + EnterCriticalSection(&(This->crit));
> + TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
>
> - TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
> - This,dodsize,dod,entries,entries?*entries:0,flags);
> + len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
> + + (This->queue_head - This->queue_tail);
> + if (len > *entries) len = *entries;
> +
> + if (dod == NULL) {
> + if (len)
> + TRACE("Application discarding %ld event(s).\n", len);
> +
> + *entries = len;
> + nqtail = This->queue_tail + len;
> + while (nqtail >= This->queue_len) nqtail -= This->queue_len;
> + } else {
> + if (dodsize < sizeof(DIDEVICEOBJECTDATA)) {
> + ERR("Wrong structure size !\n");
> + LeaveCriticalSection(&(This->crit));
> + return DIERR_INVALIDPARAM;
> + }
> +
> + if (len)
> + TRACE("Application retrieving %ld event(s).\n", len);
> +
> + *entries = 0;
> + nqtail = This->queue_tail;
> + while (len) {
> + DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
If dodsize > 16 then span = 1, but I don't really get the algorithm. Do
you know, that most of the time there is not more than one entry in the
buffer. I once read a peace about UNIX and algorithms and N being small...
Well, never mind.
> + - nqtail;
> + if (span > len) span = len;
> + /* Copy the buffered data into the application queue */
> + memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize);
> + /* Advance position */
> + nqtail += span;
> + if (nqtail >= This->queue_len) nqtail -= This->queue_len;
> + *entries += span;
> + len -= span;
> + }
> + }
> + if (!(flags & DIGDD_PEEK))
> + This->queue_tail = nqtail;
>
> + LeaveCriticalSection(&(This->crit));
> + return DI_OK;
> }
I think my implementation is cleaner.
>
> static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
> @@ -199,10 +314,27 @@
> TRACE("(this=%p)\n",This);
>
> if (This->acquired == 0) {
> - This->acquired = 1;
> + DWORD i;
> +
> + /* Store (in a global variable) the current lock */
> + current_lock = (IDirectInputDevice2A*)This;
> +
> + /* Install our keyboard hook */
> + This->hook = SetWindowsHookExW( WH_KEYBOARD_LL, dinput_keyboard_hook, 0, 0 );
> +
> + /* Read current keyboard state */
> + memset(&This->keystate, 0, 256);
> + for (i = 0; i < 0x100; i++)
> + {
> + WORD vkey = MapVirtualKeyA( i, 1 ); /* FIXME: use map mode 3 when implemented */
> + if (vkey && (GetAsyncKeyState( vkey ) & 0x8000))
This does not work (see earlier mails). but it isn't needed when keystate
is global.
> + This->keystate[i] = 0x80;
> + }
> +
> + This->acquired = 1;
> + return DI_OK;
> }
> -
> - return DI_OK;
> + return S_FALSE;
> }
>
Could you send me the file instead of the patch, as I don't really know
what to do with this patch.
To get involved in politics anyway: you can have the changes I make to
this patch.
More information about the wine-devel
mailing list