Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
8.7 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: newmouse.c
  3. *
  4. * Copyright (c) 1985 - 2000, Microsoft Corporation
  5. *
  6. * Implements new mouse acceleration algorithm.
  7. *
  8. * History:
  9. * 10-12-2000 JasonSch Adapted code from StevieB
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #ifdef SUBPIXEL_MOUSE
  14. /*
  15. * Globals.
  16. */
  17. BOOL gbNewMouseInit;
  18. #define MIN_REFRESH 60
  19. #define MIN_RESOLUTION 96
  20. /*
  21. * Constants for FixedPoint Math.
  22. */
  23. #define FP_SHIFT 16 // number of binary decimal digits
  24. #define FP_SCALE 65536 // (2^(32-FP_SHIFT)), used during conversion of
  25. // floats
  26. #define FP_MASK 0x0000ffff // mask to retrieve the remainder
  27. #define FIXP2INT(n) ((INT)((n) >> FP_SHIFT))
  28. #define FIXP_REM(n) ((n) & FP_MASK)
  29. #define INT2FIXP(n) ((((FIXPOINT)n) << FP_SHIFT))
  30. /*
  31. * This function divides two fixed point numbers and returns the result.
  32. * Notice how the final result is shifted back.
  33. */
  34. __inline FIXPOINT Div_Fixed(FIXPOINT f1, FIXPOINT f2)
  35. {
  36. return ((f1 << FP_SHIFT) / f2);
  37. }
  38. /*
  39. * This function mulitplies two fixed point numbers and returns the result.
  40. * Notice how the final result is shifted back.
  41. */
  42. __inline FIXPOINT Mul_Fixed(FIXPOINT f1, FIXPOINT f2)
  43. {
  44. return (f1 * f2) >> FP_SHIFT;
  45. }
  46. /*
  47. * This function adds two fixed point numbers and returns the result.
  48. * Notice how no shifting is necessary.
  49. */
  50. __inline FIXPOINT Add_Fixed(FIXPOINT f1, FIXPOINT f2)
  51. {
  52. return f1 + f2;
  53. }
  54. /*
  55. * Build the curves at boot and when the user changes the setting in the UI.
  56. * The algorithm uses the speedscale, the screenscale, and mousescale to
  57. * interpolate the new curves.
  58. */
  59. VOID
  60. BuildMouseAccelerationCurve(
  61. PMONITOR pMonitor)
  62. {
  63. int i, res, vrefresh;
  64. HDC hdc;
  65. FIXPOINT ScreenScale, SpeedScale;
  66. /*
  67. * 229376 is 3.5 in FP. This is strong magic, so don't sweat it too much!
  68. * Ideally we'd calculate this number, but USB mice don't report their
  69. * refresh rate, which we'd need:
  70. *
  71. * MouseScale = Div_Fixed(INT2FIXP(MouseRefresh), INT2FIXP(MouseDPI));
  72. */
  73. FIXPOINT MouseScale = 229376;
  74. if (!gbNewMouseInit) {
  75. return;
  76. }
  77. /*
  78. * Dividing by 10 is somewhat ad hoc -- this divisor controls the
  79. * overall "height" of the curves, but does not affect the shape.
  80. */
  81. SpeedScale = INT2FIXP(gMouseSensitivity) / 10;
  82. hdc = GreCreateDisplayDC(pMonitor->hDev, DCTYPE_DIRECT, FALSE);
  83. res = GreGetDeviceCaps(hdc, LOGPIXELSX);
  84. if (res < MIN_RESOLUTION) {
  85. /*
  86. * While there is no evidence that display drivers can return bogus
  87. * values for the resolution, we have no reason to think they won't
  88. * (see below). So we clamp the value to a reasonable minimum.
  89. */
  90. RIPMSG2(RIP_WARNING,
  91. "GreGetDeviceCaps(0x%p, LOGPIXELSX) returned 0n%d", hdc, res);
  92. res = MIN_RESOLUTION;
  93. }
  94. /*
  95. * Some video cards lie to us and tell us the refresh rate is 1. There are
  96. * probably others that lie in different ways, so let's make sure there's
  97. * some sane mimimum value, or the mouse will be entirely too slow.
  98. * ALL YOUR REFRESH ARE BELONG TO US!
  99. */
  100. vrefresh = GreGetDeviceCaps(hdc, VREFRESH);
  101. if (vrefresh < MIN_REFRESH) {
  102. vrefresh = MIN_REFRESH;
  103. }
  104. ScreenScale = INT2FIXP(vrefresh) / res;
  105. GreDeleteDC(hdc);
  106. for (i = 0; i < ARRAY_SIZE(pMonitor->xTxf); i++) {
  107. pMonitor->yTxf[i] = Mul_Fixed(Mul_Fixed(gDefyTxf[i], ScreenScale), SpeedScale);
  108. pMonitor->xTxf[i] = Mul_Fixed(gDefxTxf[i], MouseScale);
  109. }
  110. /*
  111. * Build the new curves in a slope-intercept format.
  112. */
  113. for (i = 1; i < ARRAY_SIZE(pMonitor->xTxf); i++) {
  114. /*
  115. * Make sure we don't divide by zero (this could happen if bogus values
  116. * are in the registry).
  117. */
  118. if ((pMonitor->xTxf[i] - pMonitor->xTxf[i-1]) == 0) {
  119. RIPMSG1(RIP_ERROR, "Bad data in registry for new mouse (i = %d)", i);
  120. pMonitor->slope[i-1] = pMonitor->yint[i-1] = 0;
  121. continue;
  122. }
  123. pMonitor->slope[i-1] = Div_Fixed(pMonitor->yTxf[i] - pMonitor->yTxf[i-1], pMonitor->xTxf[i] - pMonitor->xTxf[i-1]);
  124. pMonitor->yint[i-1] = pMonitor->yTxf[i-1] - Mul_Fixed(pMonitor->slope[i-1], pMonitor->xTxf[i-1]);
  125. }
  126. }
  127. VOID
  128. DoNewMouseAccel(
  129. INT *dx,
  130. INT *dy)
  131. {
  132. static FIXPOINT fpDxAcc = 0, fpDyAcc = 0;
  133. static int i_last = 0;
  134. int i = 0;
  135. PMONITOR pMonitor = _MonitorFromPoint(gptCursorAsync, MONITOR_DEFAULTTOPRIMARY);
  136. FIXPOINT accel, fpDxyMag;
  137. /*
  138. * Convert Mouse X and Y to FixedPoint.
  139. */
  140. FIXPOINT fpDx = INT2FIXP(*dx);
  141. FIXPOINT fpDy = INT2FIXP(*dy);
  142. /*
  143. * During TS operations it's possible for a mouse move to be queued up but
  144. * for gpDispInfo->pMonitorFirst/Primary to be NULL. Let's try not to fault
  145. * in that case. Windows Bug #413159.
  146. */
  147. if (pMonitor == NULL) {
  148. RIPMSG0(RIP_WARNING, "Ignoring mouse movement w/ no monitor set.");
  149. return;
  150. }
  151. // Get the magnitude
  152. fpDxyMag = max(abs(fpDx), abs(fpDy)) + (min(abs(fpDx), abs(fpDy)) / 2);
  153. /*
  154. * Ensure we don't divide by 0.
  155. */
  156. if (fpDxyMag != 0) {
  157. /*
  158. * Find the position MagXY from the interpolate acceleration curves.
  159. * It's possible we won't find one so we'll just use the biggest (i.e.,
  160. * the last entry in the array).
  161. */
  162. while (i < (ARRAY_SIZE(pMonitor->xTxf) - 1) && fpDxyMag > pMonitor->xTxf[i]) {
  163. ++i;
  164. }
  165. --i;
  166. accel = Div_Fixed(Add_Fixed(Mul_Fixed(pMonitor->slope[i], fpDxyMag), pMonitor->yint[i]), fpDxyMag);
  167. /*
  168. * If change of slope from last time then average the accel value using
  169. * i_last and the current i.
  170. */
  171. if (i_last != i) {
  172. accel = (accel + Div_Fixed((Mul_Fixed(pMonitor->slope[i_last], fpDxyMag) + pMonitor->yint[i_last]), fpDxyMag)) / 2;
  173. i_last = i;
  174. }
  175. /*
  176. * Calculate the multiplier for the mouse data.
  177. */
  178. fpDx = Mul_Fixed(accel, fpDx) + fpDxAcc;
  179. fpDy = Mul_Fixed(accel, fpDy) + fpDyAcc;
  180. /*
  181. * Store the remainder of the calculated X and Y. This gets added in
  182. * next time.
  183. */
  184. fpDxAcc = FIXP_REM(fpDx);
  185. fpDyAcc = FIXP_REM(fpDy);
  186. /*
  187. * Convert back to integer.
  188. */
  189. *dx = FIXP2INT(fpDx);
  190. *dy = FIXP2INT(fpDy);
  191. }
  192. }
  193. VOID
  194. ReadDefaultAccelerationCurves(
  195. PUNICODE_STRING pProfileUserName)
  196. {
  197. FIXPOINT xTxf[SM_POINT_CNT], yTxf[SM_POINT_CNT];
  198. DWORD cbSizeX, cbSizeY;
  199. /*
  200. * The default curves will reside in the .DEFAULT user profile but can be
  201. * overridden on a per-user basis.
  202. */
  203. cbSizeX = FastGetProfileValue(pProfileUserName,
  204. PMAP_MOUSE,
  205. (LPWSTR)STR_SMOOTHMOUSEXCURVE,
  206. NULL,
  207. (LPBYTE)xTxf,
  208. sizeof(xTxf),
  209. 0);
  210. cbSizeY = FastGetProfileValue(pProfileUserName,
  211. PMAP_MOUSE,
  212. (LPWSTR)STR_SMOOTHMOUSEYCURVE,
  213. NULL,
  214. (LPBYTE)yTxf,
  215. sizeof(yTxf),
  216. 0);
  217. /*
  218. * Check if we successfully read the correct amount of data from both keys.
  219. * If not, and we're reading the .DEFAULT profile, copy in the default
  220. * values.
  221. */
  222. if (cbSizeX == sizeof(xTxf) && cbSizeY == sizeof(yTxf)) {
  223. RtlCopyMemory(gDefxTxf, xTxf, sizeof(xTxf));
  224. RtlCopyMemory(gDefyTxf, yTxf, sizeof(yTxf));
  225. } else if (!gbNewMouseInit) {
  226. /*
  227. * Default values.
  228. */
  229. static FIXPOINT _xTxf[SM_POINT_CNT] = {0x0, 0x6E15, 0x14000, 0x3DC29, 0x280000};
  230. static FIXPOINT _yTxf[SM_POINT_CNT] = {0x0, 0x15EB8, 0x54CCD, 0x184CCD, 0x2380000};
  231. RtlCopyMemory(gDefxTxf, _xTxf, sizeof(_xTxf));
  232. RtlCopyMemory(gDefyTxf, _yTxf, sizeof(_yTxf));
  233. }
  234. gbNewMouseInit = TRUE;
  235. }
  236. VOID
  237. ResetMouseAccelerationCurves(
  238. VOID)
  239. {
  240. PMONITOR pMonitor = gpDispInfo->pMonitorFirst;
  241. CheckCritIn();
  242. for (; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext) {
  243. BuildMouseAccelerationCurve(pMonitor);
  244. }
  245. }
  246. #endif // SUBPIXEL_MOUSE