[RFC 5/11] Linux FF: Linux effect parameters: time parameters
Elias Vanderstuyft
elias.vds at gmail.com
Tue Mar 4 13:20:09 CST 2014
a) Because of the higher time resolution of DInput parameters (in
microseconds instead of milliseconds), e.g. dwPeriod,
and because truncating may result in "periodic.period == 0", while
"1 <= dwPeriod (non-zero) < 1000",
and because "periodic.period == 0" is an invalid argument,
we might set periodic.period to the smallest non-zero value (that
is 1) when dwPeriod is non-zero, to avoid unnecessary exceptions.
So change in dinput/effect_linuxinput.c:488 :
This->effect.u.periodic.period = tsp->dwPeriod / 1000;
to :
if (0 < tsp->dwPeriod && tsp->dwPeriod <= 1000)
This->effect.u.periodic.period = 1;
else
This->effect.u.periodic.period = tsp->dwPeriod / 1000;
b) Anticipate if dwPeriod < 0, otherwise periodic.period will
incorrectly wrap around because it's unsigned.
We can choose to let periodic.period be proportional to:
- 0 (driver will generate EINVAL)
- abs(dwPeriod) (no error, and is mathematically more correct)
Choosing the latter, so change in dinput/effect_linuxinput.c:488 :
if (0 < tsp->dwPeriod && tsp->dwPeriod <= 1000)
This->effect.u.periodic.period = 1;
else
This->effect.u.periodic.period = tsp->dwPeriod / 1000;
to :
if (tsp->dwPeriod && abs(tsp->dwPeriod) <= 1000)
This->effect.u.periodic.period = 1;
else
This->effect.u.periodic.period = abs(tsp->dwPeriod) / 1000;
c) Something similar is needed for 'dwDuration':
Set infinite replay-length in linux by "replay.length == 0":
discussion: http://www.mail-archive.com/[email protected]/msg08459.html
Knowing that DInput "INFINITE == -1", we convert -1 to 0.
If "peff->dwDuration == 0", we can:
- not start the effect
- set the effect duration to the absolute minimum
I would choose the latter, because otherwise more behaviour of the
code would change.
And lastly, we don't throw exceptions when "dwDuration < 0": MSDN
does not require us to throw DIERR_INVALIDPARAM.
So, change in dinput/effect_linuxinput.c:191 :
if (dwFlags & DIEP_DURATION) {
peff->dwDuration = (DWORD)This->effect.replay.length * 1000;
}
to :
if (dwFlags & DIEP_DURATION) {
peff->dwDuration = (This->effect.replay.length ?
(DWORD)This->effect.replay.length * 1000 : -1);
}
And change in dinput/effect_linuxinput.c:424 :
if (dwFlags & DIEP_DURATION)
This->effect.replay.length = peff->dwDuration / 1000;
to :
if (dwFlags & DIEP_DURATION) {
if (peff->dwDuration == -1)
This->effect.replay.length = 0; // Infinity
else if (peff->dwDuration > 1000)
This->effect.replay.length = peff->dwDuration / 1000;
else
This->effect.replay.length = 1; // Smallest non-zero value
}
Elias
-------------- next part --------------
///////////////////////////// Linux effect parameters: time parameters /////////////////////////////
a) Because of the higher time resolution of DInput parameters (in microseconds instead of milliseconds), e.g. dwPeriod,
and because truncating may result in "periodic.period == 0", while "1 <= dwPeriod (non-zero) < 1000",
and because "periodic.period == 0" is an invalid argument,
we might set periodic.period to the smallest non-zero value (that is 1) when dwPeriod is non-zero, to avoid unnecessary exceptions.
So change in dinput/effect_linuxinput.c:488 :
This->effect.u.periodic.period = tsp->dwPeriod / 1000;
to :
if (0 < tsp->dwPeriod && tsp->dwPeriod <= 1000)
This->effect.u.periodic.period = 1;
else
This->effect.u.periodic.period = tsp->dwPeriod / 1000;
b) Anticipate if dwPeriod < 0, otherwise periodic.period will incorrectly wrap around because it's unsigned.
We can choose to let periodic.period be proportional to:
- 0 (driver will generate EINVAL)
- abs(dwPeriod) (no error, and is mathematically more correct)
Choosing the latter, so change in dinput/effect_linuxinput.c:488 :
if (0 < tsp->dwPeriod && tsp->dwPeriod <= 1000)
This->effect.u.periodic.period = 1;
else
This->effect.u.periodic.period = tsp->dwPeriod / 1000;
to :
if (tsp->dwPeriod && abs(tsp->dwPeriod) <= 1000)
This->effect.u.periodic.period = 1;
else
This->effect.u.periodic.period = abs(tsp->dwPeriod) / 1000;
c) Something similar is needed for 'dwDuration':
Set infinite replay-length in linux by "replay.length == 0": discussion: http://www.mail-archive.com/[email protected]/msg08459.html
Knowing that DInput "INFINITE == -1", we convert -1 to 0.
If "peff->dwDuration == 0", we can:
- not start the effect
- set the effect duration to the absolute minimum
I would choose the latter, because otherwise more behaviour of the code would change.
And lastly, we don't throw exceptions when "dwDuration < 0": MSDN does not require us to throw DIERR_INVALIDPARAM.
So, change in dinput/effect_linuxinput.c:191 :
if (dwFlags & DIEP_DURATION) {
peff->dwDuration = (DWORD)This->effect.replay.length * 1000;
}
to :
if (dwFlags & DIEP_DURATION) {
peff->dwDuration = (This->effect.replay.length ? (DWORD)This->effect.replay.length * 1000 : -1);
}
And change in dinput/effect_linuxinput.c:424 :
if (dwFlags & DIEP_DURATION)
This->effect.replay.length = peff->dwDuration / 1000;
to :
if (dwFlags & DIEP_DURATION) {
if (peff->dwDuration == -1)
This->effect.replay.length = 0; // Infinity
else if (peff->dwDuration > 1000)
This->effect.replay.length = peff->dwDuration / 1000;
else
This->effect.replay.length = 1; // Smallest non-zero value
}
More information about the wine-devel
mailing list