XI2 DirectInput mouse implementation RFC (Tarballed)

Paul TBBle Hampson Paul.Hampson at Pobox.com
Tue Apr 21 10:03:07 CDT 2009

On Tue, Apr 21, 2009 at 08:16:14AM -0600, Vitaliy Margolen wrote:
> Paul TBBle Hampson wrote:
>> On Sun, Apr 19, 2009 at 02:39:43PM -0600, Vitaliy Margolen wrote:
>>> Paul TBBle Hampson wrote:
>> 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.
> That's the goal. But it won't be an easy thing to do. For now (testing XI2)
> we might make a special interface between dinput and x11drv.

>> I'm probably wrong about Ventrilo. I had this vague recollection that it
>> only worked with other Wine programs in non-DI mode...
> From what I recall it can use HotKeys or DirectInput for push-to-talk. Of
> course neither one of them work on Wine ATM.

I'm sure one of them used to work, because I used to use it with WoW.

>>>> 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?
> Both. They call SetCooperativeLevel(did, NULL, DISCL_EXCLUSIVE |
> DISCL_FOREGROUND) which is wrong - they have to specify the window, it can't
> be null. And they don't check for return, assuming call was successful. And
> ending up with default (non-exclusive, background).

>> 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.
> Well, Wine have to do what native does - at least make these games work in
> full screen.

>> 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.
> Eventually we might have to - native has all sorts of "shims" to fix broken
> programs. But this is a topic for another big and long discussion.

Oh, indeed. If we can spot the mistakes (as described above) we can fix
them. I meant that we cannot for example turn a foreground non-exclusive
acquire into a foreground exclusive acquire, as that will break things
that really do want it non-exclusive.

>>>> 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.
> Most likely - yes. Or at least for the time being to test new XI2 to make
> things easier.

>> Whether this involves warping the mouse every 10ms, using XI2 to perform
> Now this is something we can not do. Wine can not warp mouse - some games
> break because of that.

So how do we handle systems that don't support XI2? If we remove the
mouse warping entirely, do we just reject attempts to acquire the mouse
exclusively on those systems?

I assume those same games will break if we cannot acquire the mouse
exclusively, although I'd be thrilled to be wrong.

I haven't looked at the other alternatives, but maybe once we get
relative motion using XI2, we can simulate exclusive mode by simply
discarding all mouse events in the x11drv event loop, and use a normal
X cursor grab to tie the mouse inside our window?

(My knowledge on grabs is shakey at best, which is the other reason I
addresses the background DI case before the exclusive DI case)

>> a grab on the pointer, or some mysterious quartz driver voodoo,
>> shouldn't be visible to dinput, or rawinput, or 
> This might be necessary in virtual-desktop mode. Full screen is kind of easy
> way to solve this problem for most game developers. So they don't envision
> their games running in a windowed mode (I'm looking at you Ubi).

We still need to hold the mouse for full-screen games, or we get the
problem that a full-screen game is generally only full-screen on one
monitor, and the mouse isn't otherwise constrained to that monitor, and
hence the mouse can stray out of the game's window. Happens on Windows
too, to some non-DI games, although click-to-focus means that if you
don't click, it doesn't break.

>>>> 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.
> That's not what I meant. Some games create more then one keyboard/mouse
> devices (IDirectInput_CreateDevice). And expect them all to work.

That'd work now, though, right? Each device object you create using
CreateDevice gets its own event queue which the queue_event call
populates, so draining the buffer on one doesn't affect the others.

Or do they expect to work by sharing a buffer (ie being actually
multiple references to one instance)?

>> 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.
> Not move warping, remove it (it shouldn't be done at all).

This is the incremental changes approach... It seems to me the first
step is to move around the existing functionality, before we start
ripping it out wholesale. If the first step can be ripping out warping,
I'm all in favour of it.

>> 	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!)
> Correct. DI does something like that currently - it has a dedicated thread
> that receives all the events. Then it dispatches them to each acquired
> device. X11drv will have to do something similar - it needs a dedicated
> thread with a dedicated X11 connection - we can't relay on the owner of the
> foreground window to pump events, as some don't.

>> 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.
> Correct. It might be a complete replacement for the current raw event
> generator (regular X events).

So every process that uses DI or similar causes x11drv to spawn a thread
that talks to the XServer, doing only XI2 raw event processing and
presumably grabs? It would feed the hooks, and/or call the callback into
DI or RawInput or whatever. And the current hook feeding functions in
mouse.c and keyboard.c go away.

>> 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).
> We can always change DInput to talk to X11 directly. Or use ... RawInput
> events. It sure would be cool to make it in a native compatible way (using
> driver interface) but it would be too much work. No something we'd like to
> spend our time on ATM.

I was actually thinking it might be interesting to consider RawInput
implemented on DI, but hadn't thought the semantics through.

I actually went looking, but didn't find any documentation in WDK online
or MSDN about how DI would talk directly to mouse or keyboard hardware
under Windows.

>> 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.
> In theory LL hook events should contain raw mouse events regardless of the
> pointer. In practice - I don't remember what native does. I think if the
> cursor "stuck" on the border it just (dec|inc)rements it's position by the
> relative move amount and send these "fake" coords to the hook. Of course the
> cursor position doesn't change, so (hook_coords - GetCursorPos() = relative
> coords) still works.

I'll expand my test program to use native hooks (and maybe RawInput if
necessary) before I do any more work on implementing these behaviours.

That comparison doesn't work if the mouse is not against the edge of the
screen, I assume. (ie the hook is not processed before cursor position
is updated)

>> 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.
> Looks good. Might even add a callback instead of piping messages through the
> whole Wine.

This is actually roughly what my patch currently prototypes, a direct
callback from x11drv to DirectInput. It relies on the existing message pump
though, and assumes only one callback at a time will be in existence,
for speed of prototyping.

Along with the notes in my other message, I think letting code that
wants relative data register a callback with x11drv is the right thing
to do.

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/20090422/18c0b386/attachment.pgp>

More information about the wine-devel mailing list