diff options
Diffstat (limited to 'mousetsr.c')
| -rw-r--r-- | mousetsr.c | 114 |
1 files changed, 77 insertions, 37 deletions
@@ -60,6 +60,24 @@ static void bound_position_to_window(void) if (data.pos.y > data.max.y) data.pos.y = data.max.y; } +/** Apply sensitivity to a raw mouse delta. + * @param sens value [5..100] given to set_mouse_sensitivity. + * @param x mouse delta in mickeys + * @return mouse delta scaled by sensitivity + * + * Note this is not acceleration, we are still multiplying the delta by a + * linear factor supposedly derived from the sensivitity [5..100] value. + * Every mouse driver seems to use their own formula for computing this factor. + * I am going with f(x) = x(x+32)/4096 since it looks round and fits decently, + * even with integer math (we don't divide by 4096 until after multiplying by delta). + * @see INT33_SET_MOUSE_SENSITIVITY for what the factor should look like. */ +int16_t apply_sensitivity(int16_t x, uint8_t sens, int16_t *rem) +{ + uint16_t factor = (sens * (sens + 32)); + // TODO Actually use a shift instead of division + return scalei_rem(x, 4096, factor, rem); +} + /** Constraints coordinate value to the desired granularity, * which must be a power of two. */ static inline int16_t snap_to_grid(int16_t val, int16_t granularity) @@ -72,7 +90,8 @@ static void hide_text_cursor(void) { // Restore the character under the old position of the cursor uint16_t __far *ch = get_video_char(&data.video_mode, - data.cursor_pos.x / 8, data.cursor_pos.y / 8); + data.cursor_pos.x / (data.screen_scale.x * 8), + data.cursor_pos.y / (data.screen_scale.y * 8)); *ch = data.cursor_prev_char; data.cursor_visible = false; } @@ -80,7 +99,8 @@ static void hide_text_cursor(void) static void show_text_cursor(void) { uint16_t __far *ch = get_video_char(&data.video_mode, - data.pos.x / 8, data.pos.y / 8); + data.pos.x / (data.screen_scale.x * 8), + data.pos.y / (data.screen_scale.y * 8)); data.cursor_prev_char = *ch; data.cursor_pos = data.pos; *ch = (*ch & data.cursor_text_and_mask) ^ data.cursor_text_xor_mask; @@ -624,40 +644,54 @@ static void handle_mouse_event(uint16_t buttons, bool absolute, int x, int y, ch // Set the new absolute position data.pos.x = x; data.pos.y = y; - data.pos_frac.x = 0; - data.pos_frac.y = 0; + data.pos_pixel_frac.x = 0; + data.pos_pixel_frac.y = 0; + data.pos_sens_frac.x = 0; + data.pos_sens_frac.y = 0; } } else if (x || y) { // Relative movement: x,y are in mickeys - uint16_t ticks = bda_get_tick_count_lo(); + uint16_t cur_ticks = bda_get_tick_count_lo(); unsigned ax = abs(x), ay = abs(y); events |= INT33_EVENT_MASK_MOVEMENT; - // Check if around one second has passed - if ((ticks - data.last_motion_ticks) >= 18) { + // Check if a tick has passed, if so update speed + if (data.last_motion_ticks != cur_ticks) { + uint16_t elapsed_ticks = cur_ticks - data.last_motion_ticks; + data.cur_speed = (data.total_motion / elapsed_ticks) * 18; // Extrapolate speed from movement in this tick +#if TRACE_EVENTS + dprintf("mouse speed = %u / threshold = %u total_motion in last %u ticks = %u\n", data.cur_speed, data.doubleSpeedThreshold * data.doubleSpeedThreshold, elapsed_ticks, data.total_motion); +#endif data.total_motion = 0; - data.last_motion_ticks = ticks; + data.last_motion_ticks = cur_ticks; } - - // If more than the double speed threshold has been moved in the last second, - // double the speed data.total_motion += ax * ax + ay * ay; - if (data.total_motion > data.doubleSpeedThreshold * data.doubleSpeedThreshold) { - x *= 2; - y *= 2; - } + // Apply sensitivity now, since unlike acceleration/speed, it affects the raw mickey counters + x = apply_sensitivity(x, data.sensitivity_x, &data.pos_sens_frac.x); + y = apply_sensitivity(y, data.sensitivity_y, &data.pos_sens_frac.y); + + // Update the raw mickey counters data.delta.x += x; data.delta.y += y; - data.delta_frac.x = 0; - data.delta_frac.y = 0; + + // Invalidate last abs position data.abs_pos.x = -1; data.abs_pos.y = -1; - // Convert mickeys into pixels - data.pos.x += scalei_rem(x, data.mickeysPerLine.x, 8, &data.pos_frac.x); - data.pos.y += scalei_rem(y, data.mickeysPerLine.y, 8, &data.pos_frac.y); + // Convert mickeys into pixels, applying speed and acceleration + + // If more than the double speed threshold has been moved in the last second, + // double the speed + if (data.cur_speed > data.double_speed_threshold * data.double_speed_threshold) { + x *= 2; + y *= 2; + } + + // Apply mickeysPerLine. Keep the fractional part for the next movement! + data.pos.x += scalei_rem(x, data.mickeysPerLine.x, 8, &data.pos_pixel_frac.x); + data.pos.y += scalei_rem(y, data.mickeysPerLine.y, 8, &data.pos_pixel_frac.y); } bound_position_to_window(); @@ -1164,7 +1198,7 @@ static void reset_mouse_settings() data.mickeysPerLine.x = 8; data.mickeysPerLine.y = 16; - data.doubleSpeedThreshold = 64; + data.double_speed_threshold = 64; data.min.x = 0; data.max.x = data.screen_max.x; data.min.y = 0; @@ -1177,6 +1211,10 @@ static void reset_mouse_settings() data.cursor_hotspot.y = 0; memcpy(data.cursor_graphic, default_cursor_graphic, sizeof(data.cursor_graphic)); + // Sensitivity is persisted through resets, but ensure we init it with 50 if 0. + if (data.sensitivity_x == 0) data.sensitivity_x = 50; + if (data.sensitivity_y == 0) data.sensitivity_y = 50; + refresh_cursor(); // This will hide the cursor and update data.cursor_visible } @@ -1186,15 +1224,18 @@ static void reset_mouse_state() int i; data.pos.x = data.min.x + (data.max.x - data.min.x) / 2; data.pos.y = data.min.y + (data.max.y - data.min.y) / 2; - data.pos_frac.x = 0; - data.pos_frac.y = 0; + data.pos_pixel_frac.x = 0; + data.pos_pixel_frac.y = 0; + data.pos_sens_frac.x = 0; + data.pos_sens_frac.y = 0; data.delta.x = 0; data.delta.y = 0; - data.delta_frac.x = 0; - data.delta_frac.y = 0; data.abs_pos.x = -1; data.abs_pos.y = -1; data.buttons = 0; + data.cur_speed = 0; + data.total_motion = 0; + data.last_motion_ticks = bda_get_tick_count_lo(); for (i = 0; i < MAX_BUTTONS; i++) { data.button[i].pressed.count = 0; data.button[i].pressed.last.x = 0; @@ -1307,12 +1348,12 @@ static void int33_handler(union INTPACK r) #endif data.pos.x = r.w.cx; data.pos.y = r.w.dx; - data.pos_frac.x = 0; - data.pos_frac.y = 0; + data.pos_pixel_frac.x = 0; + data.pos_pixel_frac.y = 0; + data.pos_sens_frac.x = 0; + data.pos_sens_frac.y = 0; data.delta.x = 0; data.delta.y = 0; - data.delta_frac.x = 0; - data.delta_frac.y = 0; bound_position_to_window(); break; case INT33_GET_BUTTON_PRESSED_COUNTER: @@ -1407,7 +1448,7 @@ static void int33_handler(union INTPACK r) break; case INT33_SET_SPEED_DOUBLE_THRESHOLD: dprintf("Mouse set speed double threshold=%d\n", r.w.dx); - data.doubleSpeedThreshold = r.w.dx; + data.double_speed_threshold = r.w.dx; break; case INT33_EXCHANGE_EVENT_HANDLER: dputs("Mouse exchange event handler"); @@ -1439,15 +1480,14 @@ static void int33_handler(union INTPACK r) case INT33_SET_MOUSE_SENSITIVITY: dprintf("Mouse set sensitivity x=%d y=%d threshold=%d\n", r.w.bx, r.w.cx, r.w.dx); - // TODO According to cutemouse, sensitivity != mickeysPerLine - data.mickeysPerLine.x = r.w.bx; - data.mickeysPerLine.y = r.w.cx; - data.doubleSpeedThreshold = r.w.dx; + data.sensitivity_x = BOUND(r.w.bx, 1, 100); + data.sensitivity_y = BOUND(r.w.cx, 1, 100); + data.double_speed_threshold = r.w.dx; break; case INT33_GET_MOUSE_SENSITIVITY: - r.w.bx = data.mickeysPerLine.x; - r.w.cx = data.mickeysPerLine.y; - r.w.dx = data.doubleSpeedThreshold; + r.w.bx = data.sensitivity_x; + r.w.cx = data.sensitivity_y; + r.w.dx = data.double_speed_threshold; break; case INT33_RESET_SETTINGS: dputs("Mouse reset settings"); |
