XI2 DirectInput mouse implementation RFC (Tarballed)

Paul TBBle Hampson Paul.Hampson at Pobox.com
Mon Apr 20 10:09:47 CDT 2009


On Sun, Apr 19, 2009 at 02:39:43PM -0600, Vitaliy Margolen wrote:
> Paul TBBle Hampson wrote:
>> On Sun, Apr 19, 2009 at 10:48:11AM -0600, Vitaliy Margolen wrote:
>>> Paul TBBle Hampson wrote:
>>>> On Sun, Apr 19, 2009 at 12:46:20PM +0200, Stefan Dösinger wrote:
>>>>> Am Sonntag, 19. April 2009 10:41:34 schrieb Paul TBBle Hampson:
>>>>>> I've thrown together a rather-rough-but-working-in-a-limited-sense
>>>>>> implementation of XInput2-based DirectInput.
>>>>>> * Doesn't check for XInput2.h, so it won't build without it. (Laziness)
>>>>>>   It will _run_ without XInput2, falling back to the current dinput
>>>>>>   WndProc hooks even if compiled with XInput2 support.
>>>>> I'm not that much into all the input code, but I always understood it the way 
>>>>> that dinput should always use WndProc hooks, and winex11.drv implements the 
>>>>> relative movement part either with XI2 or warping if XI2 is not available. 
>>>>> Ie, there should be no difference between XI2 and legacy operation in 
>>>>> dinput.dll. That would, I think, make native dinput work as well as the 
>>>>> builtin one, and help apps that rely on hooks the same way native dinput 
>>>>> does(if there are any).
>> 
>>>>> The problem is that this means the warping has to be moved to winex11, which 
>>>>> is something Vitaliy tried before and failed
>> 
>>>>> I could be entirely wrong with that though. And I have no idea how that would 
>>>>> affect mouse grabbing, or window focus issues etc.
>> 
>>>> A WndProc hook can only work for Foreground-mode DI. In background mode,
>>>> you still expect to get movement messages without being in a position to
>>>> receive WM_MOUSEMOVE or WM_KEYPRESS.
>>> Not necessarily. Hook is for raw mouse & keyboard events, and they are being
>>> generated by the devices themselves. On native this works regardless of
>>> where the pointer is.
>> 
>> OK, I'm a little confused. What message is sent on native to all windows
>> (or at least all windows with a DI Background Acquire on the mouse?) for
>> a WndProc hook on the Acquiring process to handle?
> WndProc hook is strictly to detect focus losses. The actual input comes from
> LL_HOOKs: WH_KEYBOARD_LL & WH_MOUSE_LL.

I think I understand now.

So we really don't want to touch dinput at all, but instead just use XI2
to feed the WH_*_LL hooks and let the existing DI code turn those hook
inputs into event queue entries as it does now.

>> My understanding of Wine's current method is that a background process
>> only gets events when they happen over its window, not when they happen
>> over other Wine windows.
> Not exactly correct. ATM Wine gets only those mouse & keyboard events that
> happen over _any_ Wine window (for mouse) and when Wine has focus (for
> keyboard).

>> Which explains why Ventrilo in DI mode can't get keyboard
>> input even when different Wine applications are in the foreground.
> This is not true. You probably running then from different prefixes.

Nope, they were the same prefix. The exact same command with my Wine
build produced the correct behaviour.

Actually, I just checked, and it's only movement that's being lost.
Scroll wheels and button presses appear on both, and every once in a
while, I'll see a movement entry on the client that is not the
foreground.

It could very well be a bug in my test program, although I can't see
what it would be, I basically assembled it out of MSDN and some other
quick samples.

I'm probably wrong about Ventrilo. I had this vague recollection that it
only worked with other Wine programs in non-DI mode...

>> Either way, that doesn't work for Wine because not every window on
>> screen has a WndProc for us to hook. Unless I've missed something,
>> that's the basis of my position that you cannot do correct background DI
>> using only a WndProc hook, because you miss all the events that do not
>> get fed to _any_ WndProc hook.
> You missing something (see above). This doesn't work because lots of games
> buggy and think they acquire mouse in exclusive mode, while in fact they
> end-up using non-exclusive foreground mode.

Buggy in that they pass in the wrong flags, or buggy in that they don't
check the result? I know there's some discussion regarding Quake and
Quake 2 in the bug report, but it doesn't specify if it's a game bug or
not. It _seems_ to indicate it's a program bug that is hidden because
the game is running full-screen so is always the window under the
cursor, but I think that problem needs to be addressed separately. We
can't exactly misimplement the API to benefit games that are using it
wrong, if it involves breaking things that are using it right.

>> I'll review your earlier patches for this change as well at that time,
>> and make sure I understand how to go about this correctly.
> That might be waste of time. I was trying to make x11org do all the magic
> (warping & grabbing pointer). This won't be aplicable as much with XI2.

Actually, I still think it has to do that. To my mind, we only want
dinput telling the graphics driver when it has acquired a device (so the
graphics driver can start pumping the WH_*_LL hooks) and when it has
acquired a device exclusively so the graphics driver can prevent events
propagating to the normal windows event loop.

Whether this involves warping the mouse every 10ms, using XI2 to perform
a grab on the pointer, or some mysterious quartz driver voodoo,
shouldn't be visible to dinput, or rawinput, or 

>> So from my reading, my suggestion above probably makes sense, to keep
>> the current pair of methods I added for DI (wine_directinput_AcquireMouse
>> and wine_dinput_MouseUnacquire), make it non-optional for a graphics
>> driver to provide such methods and a system mouse, rename them without
>> directinput, and then add RawInput to user32 such that it also takes an
>> acquire on mouse and keyboard if those're what's asked for by the client
>> software.
> That's what I was thinking too. Only they would need to be more
> sophisticated to handle multiple "users". Some games using multiple keyboard
> & mouse DInput devices. Also don't forget additional software, like
> ventrilo, running in parallel with the game.

Can games use multiple mouse and keyboard devices? MSDN states that
Windows XP's DI only enumerates one mouse and one keyboard, so I assumed
people program with that assumption. Not that this is a hard assumption
to manage.

>> Then again, I haven't looked hard at exclusive-mode grabbing, so there
>> may be some need. I'd hoped we could just tell winex11 to ignore
>> MotionNotify, ButtonPress and ButtonRelease when the mouse is taken in
>> exclusive mode, and grab it so it effectively stays exactly where it is,
>> modulo the window moving around beneath it shouldn't lose the grab.
> That would have to be done somewhere - either x11drv or wineserver. With
> current code path for LL hooks it's in x11drv.

[trim]
>> I don't understand that in context of this paragraph.
> Read what I said about type of hooks current DInput using. Then it will be
> more clear. Hooks are not going away, some programs would still use them.
> Which means we can't just use XI2 for dinput. It would need to be used for
> anything requiring raw input events (RawInput, LL hooks, DInput, HotKeys, etc).

OK, I'm clearer on all that now, thankyou.

So I guess the way to implement the XI2 support from the above is to
restart this patch series again, as follows:

Move mouse warping into winex11.drv, and add a MouseAcquire/MouseDeacquire
interface pair to winex11.drv.

	That pair of functions will enable mouse warping if exclusive
	acquisition occurs. They probably need to keep a reference count, and
	ensure that we only stop doing what we've been asked if everything
	that acquired us has deacquired us. Only one thing at a time can
	have an exclusive acquisition (the foreground window) but this
	interface needs to be able to be used by RawInput too, so it might
	need to protect against multiple exclusive efforts by the foreground
	window. (Pathological case of program using both DI and RawInput!)

Add an XI2 variation of the MouseAcquire/MouseDeacquire functions that
use a grab instead of mouse warping, and feed raw events into
queue_raw_mouse_message if no Wine window has X focus.

However, there's at least one issue here:

Feeding LL_HOOKS from XI2 which then feeds DirectInput means we're going
from relative to absolute values and back to relative (and then back to
absolute if DI has the mouse axes in absolute mode).

The middle part of this will see co-ordinates that aren't sensible (ie
the hook will see absolute co-ordinates that are outside its virtual
desktop if running in a virtual desktop smaller than the screen)

The larger problem is that certain mouse movements can't work with an
absolute value in the middle, namely those that happen when the cursor
is already on the edge of the screen. If we support those by using the
absolute position in the WH_MOUSE_LL data structure as accumulated
relative position (as DirectInput does when providing absolute mouse
axis data) then when we get a real cursor position later, the mouse is
going to appear to jump quite sharply by however much movement was
applied relatively without affecting the absolute pointer position on
screen.

This also means we replicate part of the mouse-warping problem, because
for foreground exclusive apps, the cursor isn't moving when we receive
relative motion, so either we send the real cursor position in the
WH_MOUSE_LL data, in which case no movement is visible, or we send real
cursor position + relative movement, and therefore accumulate error over
the life of the exclusive acquisition. I'm pretty sure this is what
causes the Warhammer Online cusor-controlled camera to go completely
wild when used with targeted seige weapons.

I think my solution to that while keeping the same structure is to add a
WH_WINEMOUSE_REL hook message that carries relative mouse movement data,
and let DirectInput and RawInput hook that. This also means that
applications that wish to hook WH_MOUSE_LL while using DirectInput and
RawInput are free to do so. (This last point may not be interesting, I
don't know if they are currently interfered with by DirectInput taking a
WH_MOUSE_LL hook on their behalf, and again it's probably pathological)

This would make the prototype for MouseAcquire be something like
MouseAcquire( BOOL foreground, BOOL exclusive, BOOL relative )
* foreground true disables use of XI2, since by definition data will
  come through the normal X channel
* exclusive enables pointer grab or warping and killing of normal Mouse
  handling.
* relative enables sending of WH_WINEMOUSE_REL hook messages.

Again, it'd have to be a reference counted system, so any outstanding
acquisitions would ensure messages of the type they acquire are being
resent.

It's late, and although I've been stewing this over for the last few
hours, it still may not make a lot of sense or contain large oversights
on my part.

-- 
-----------------------------------------------------------
Paul "TBBle" Hampson, B.Sc, LPI, MCSE
Very-later-year Asian Studies student, ANU
The Boss, Bubblesworth Pty Ltd (ABN: 51 095 284 361)
Paul.Hampson at Pobox.com

Of course Pacman didn't influence us as kids. If it did,
we'd be running around in darkened rooms, popping pills and
listening to repetitive music.
 -- Kristian Wilson, Nintendo, Inc, 1989

License: http://creativecommons.org/licenses/by/2.5/au/
-----------------------------------------------------------
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20090421/d9ed86e5/attachment-0001.pgp>


More information about the wine-devel mailing list