ghosthand scroll down 5 scrolls like a real mouse wheel. It does not drag.scroll down 5 │ ├─ move pointer to --at (default: screen center), wait 100 ms ├─ 2 lead-in reports ──▶ iOS drops them (start of the scroll gesture) ├─ 5 reports, wheel=+3, one every 16 ms ──▶ ~100 pt each └─ wait 200 ms
swipe taps the row where it starts. In the Clock city picker a swipe added a city. The wheel scrolls these lists.report 7: [buttons, dx lo, dx hi, dy lo, dy hi, wheel] wheel: [0, 0, 0, 0, 0, +3] positive = content further down
HIDDevice.sendWheel clamps to -127...127 (-128 is outside the logical range). The absolute report 1 has no wheel; iOS still scrolls from report 7 while it uses the absolute pointer.screentext y positions of the same lines.| settings | ticks: movement |
| value 1, 16 ms, no lead | 1-3: 0 pt; 4: 55; 5: 116; 6: 186 |
| value 1, 50 ms, no lead | 1-3: 0; 4: 31; 5: 80 |
| value 3, 16 ms, no lead | 1-2: 0; 3: 91; 4: 195; 5: 305 |
| value 3, 32 ms, no lead | 2: 0; 3: 88; 4: 181 |
| value 6, 16 ms, no lead | 2: 0; 3: 118; 4: 259 |
| value 3, 16 ms, lead 2 (shipped), Safari | 1: 90-97; 2: 193-199; 3: 301-304; 4: 421; 5: 520-546 |
| same, Clock city list (UITableView) | 1: 127; 2: 248; 3: 339; 5: 580-585 |
scroll sends 2 lead-in reports so every tick counts.up moves the same distance back.scroll down 2 once moved 99 pt instead of ~195.kHIDUsage_GD_Wheel, kDefaultScrollFixedResolution)IOHIDScrollAccelerator. IOHIDPointerScrollFilter.cpp (filter, setupScrollAcceleration)SCROLL_CLEAR_THRESHOLD_MS 500 gap > 500 ms or direction change: history is cleared SCROLL_EVENT_THRESHOLD_MS 150 a gap longer than this counts as 150 ms (slow) SCROLL_EVENT_AVARAGE_LENGHT 9 velocity = average of the last 9 reports eventCount > 2 velocity *= sqrt(16 * count) / 4 (boost from report 3)
scroll calls about 300 ms pass (200 ms end wait + 100 ms pointer settle), so back-to-back calls mostly start fresh; this is why the same command usually moves about the same distance (not guaranteed: one scroll down 2 moved 99 pt instead of ~195).scroll sends 2 lead-in reports.scroll() sends the wheel on the relative report. It forwards live Mac scroll events (scrollingDeltaY / 8 notches, InputController.swift), so the continuous stream hides the dropped first reports.