@@ -45,6 +45,11 @@ static bool xinput2_multitouch_supported;
45
45
* this extension */
46
46
static int xinput2_opcode ;
47
47
48
+ static Atom xinput2_rel_x_atom ;
49
+ static Atom xinput2_rel_y_atom ;
50
+ static Atom xinput2_abs_x_atom ;
51
+ static Atom xinput2_abs_y_atom ;
52
+
48
53
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO
49
54
typedef struct
50
55
{
@@ -67,23 +72,40 @@ static int scrollable_device_count;
67
72
static bool xinput2_scrolling_supported ;
68
73
#endif
69
74
70
- static void parse_valuators (const double * input_values , const unsigned char * mask , int mask_len ,
71
- double * output_values , int output_values_len )
75
+ static void parse_relative_valuators (SDL_XInput2DeviceInfo * devinfo , const XIRawEvent * rawev )
72
76
{
73
- int i = 0 , z = 0 ;
74
- int top = mask_len * 8 ;
75
- if (top > MAX_AXIS ) {
76
- top = MAX_AXIS ;
77
- }
77
+ double processed_coords [2 ] = { 0.0 , 0.0 };
78
+ int values_i = 0 , found = 0 ;
79
+
80
+ for (int i = 0 ; i < rawev -> valuators .mask_len * 8 && found < 2 ; ++ i ) {
81
+ if (!XIMaskIsSet (rawev -> valuators .mask , i )) {
82
+ continue ;
83
+ }
84
+
85
+ for (int j = 0 ; j < 2 ; ++ j ) {
86
+ if (devinfo -> number [j ] == i ) {
87
+ const double current_val = rawev -> valuators .values [values_i ];
88
+
89
+ if (devinfo -> relative [j ]) {
90
+ processed_coords [j ] = current_val ;
91
+ } else {
92
+ processed_coords [j ] = devinfo -> prev_coords [j ] - current_val ; // convert absolute to relative
93
+ }
78
94
79
- SDL_memset (output_values , 0 , output_values_len * sizeof (double ));
80
- for (; i < top && z < output_values_len ; i ++ ) {
81
- if (XIMaskIsSet (mask , i )) {
82
- const int value = (int )* input_values ;
83
- output_values [z ] = value ;
84
- input_values ++ ;
95
+ devinfo -> prev_coords [j ] = current_val ;
96
+ ++ found ;
97
+
98
+ break ;
99
+ }
85
100
}
86
- z ++ ;
101
+
102
+ ++ values_i ;
103
+ }
104
+
105
+ // Relative mouse motion is delivered to the window with keyboard focus
106
+ SDL_Mouse * mouse = SDL_GetMouse ();
107
+ if (mouse -> relative_mode && SDL_GetKeyboardFocus ()) {
108
+ SDL_SendMouseMotion (rawev -> time , mouse -> focus , (SDL_MouseID )rawev -> sourceid , true, (float )processed_coords [0 ], (float )processed_coords [1 ]);
87
109
}
88
110
}
89
111
@@ -260,6 +282,12 @@ bool X11_InitXinput2(SDL_VideoDevice *_this)
260
282
xinput2_multitouch_supported = xinput2_version_atleast (version , 2 , 2 );
261
283
#endif
262
284
285
+ // Populate the atoms for finding relative axes
286
+ xinput2_rel_x_atom = X11_XInternAtom (data -> display , "Rel X" , False );
287
+ xinput2_rel_y_atom = X11_XInternAtom (data -> display , "Rel Y" , False );
288
+ xinput2_abs_x_atom = X11_XInternAtom (data -> display , "Abs X" , False );
289
+ xinput2_abs_y_atom = X11_XInternAtom (data -> display , "Abs Y" , False );
290
+
263
291
// Enable raw motion events for this display
264
292
SDL_zero (eventmask );
265
293
SDL_zeroa (mask );
@@ -345,7 +373,6 @@ static SDL_XInput2DeviceInfo *xinput2_get_device_info(SDL_VideoData *videodata,
345
373
SDL_XInput2DeviceInfo * prev = NULL ;
346
374
SDL_XInput2DeviceInfo * devinfo ;
347
375
XIDeviceInfo * xidevinfo ;
348
- int axis = 0 ;
349
376
int i ;
350
377
351
378
for (devinfo = videodata -> mouse_device_info ; devinfo ; devinfo = devinfo -> next ) {
@@ -375,18 +402,49 @@ static SDL_XInput2DeviceInfo *xinput2_get_device_info(SDL_VideoData *videodata,
375
402
376
403
devinfo -> device_id = device_id ;
377
404
378
- /* !!! FIXME: this is sort of hacky because we only care about the first two axes we see, but any given
379
- !!! FIXME: axis could be relative or absolute, and they might not even be the X and Y axes!
380
- !!! FIXME: But we go on, for now. Maybe we need a more robust mouse API in SDL3... */
405
+ /* Search for relative axes with the following priority:
406
+ * - Labelled 'Rel X'/'Rel Y'
407
+ * - Labelled 'Abs X'/'Abs Y'
408
+ * - The first two axes found
409
+ */
410
+ bool have_rel_x = false, have_rel_y = false;
411
+ bool have_abs_x = false, have_abs_y = false;
412
+ int axis_index = 0 ;
381
413
for (i = 0 ; i < xidevinfo -> num_classes ; i ++ ) {
382
414
const XIValuatorClassInfo * v = (const XIValuatorClassInfo * )xidevinfo -> classes [i ];
383
415
if (v -> type == XIValuatorClass ) {
384
- devinfo -> relative [axis ] = (v -> mode == XIModeRelative );
385
- devinfo -> minval [axis ] = v -> min ;
386
- devinfo -> maxval [axis ] = v -> max ;
387
- if (++ axis >= 2 ) {
416
+ if (v -> label == xinput2_rel_x_atom || (v -> label == xinput2_abs_x_atom && !have_rel_x ) ||
417
+ (axis_index == 0 && !have_rel_x && !have_abs_x )) {
418
+ devinfo -> number [0 ] = v -> number ;
419
+ devinfo -> relative [0 ] = (v -> mode == XIModeRelative );
420
+ devinfo -> minval [0 ] = v -> min ;
421
+ devinfo -> maxval [0 ] = v -> max ;
422
+
423
+ if (v -> label == xinput2_rel_x_atom ) {
424
+ have_rel_x = true;
425
+ } else if (v -> label == xinput2_abs_x_atom ) {
426
+ have_abs_x = true;
427
+ }
428
+ } else if (v -> label == xinput2_rel_y_atom || (v -> label == xinput2_abs_y_atom && !have_rel_y ) ||
429
+ (axis_index == 1 && !have_rel_y && !have_abs_y )) {
430
+ devinfo -> number [1 ] = v -> number ;
431
+ devinfo -> relative [1 ] = (v -> mode == XIModeRelative );
432
+ devinfo -> minval [1 ] = v -> min ;
433
+ devinfo -> maxval [1 ] = v -> max ;
434
+
435
+ if (v -> label == xinput2_rel_y_atom ) {
436
+ have_rel_y = true;
437
+ } else if (v -> label == xinput2_abs_y_atom ) {
438
+ have_abs_y = true;
439
+ }
440
+ }
441
+
442
+ // If two relative axes were found, nothing more to do.
443
+ if (have_rel_x && have_rel_y ) {
388
444
break ;
389
445
}
446
+
447
+ ++ axis_index ;
390
448
}
391
449
}
392
450
@@ -437,41 +495,18 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
437
495
{
438
496
const XIRawEvent * rawev = (const XIRawEvent * )cookie -> data ;
439
497
const bool is_pen = X11_FindPenByDeviceID (rawev -> sourceid ) != NULL ;
440
- SDL_Mouse * mouse = SDL_GetMouse ();
441
- SDL_XInput2DeviceInfo * devinfo ;
442
- double coords [2 ];
443
- double processed_coords [2 ];
444
- int i ;
445
- Uint64 timestamp = X11_GetEventTimestamp (rawev -> time );
446
498
447
499
videodata -> global_mouse_changed = true;
448
500
if (is_pen ) {
449
501
break ; // Pens check for XI_Motion instead
450
502
}
451
503
452
- devinfo = xinput2_get_device_info (videodata , rawev -> deviceid );
504
+ SDL_XInput2DeviceInfo * devinfo = xinput2_get_device_info (videodata , rawev -> deviceid );
453
505
if (!devinfo ) {
454
506
break ; // oh well.
455
507
}
456
508
457
- parse_valuators (rawev -> raw_values , rawev -> valuators .mask ,
458
- rawev -> valuators .mask_len , coords , 2 );
459
-
460
- for (i = 0 ; i < 2 ; i ++ ) {
461
- if (devinfo -> relative [i ]) {
462
- processed_coords [i ] = coords [i ];
463
- } else {
464
- processed_coords [i ] = devinfo -> prev_coords [i ] - coords [i ]; // convert absolute to relative
465
- }
466
- }
467
-
468
- // Relative mouse motion is delivered to the window with keyboard focus
469
- if (mouse -> relative_mode && SDL_GetKeyboardFocus ()) {
470
- SDL_SendMouseMotion (timestamp , mouse -> focus , (SDL_MouseID )rawev -> sourceid , true, (float )processed_coords [0 ], (float )processed_coords [1 ]);
471
- }
472
-
473
- devinfo -> prev_coords [0 ] = coords [0 ];
474
- devinfo -> prev_coords [1 ] = coords [1 ];
509
+ parse_relative_valuators (devinfo , rawev );
475
510
} break ;
476
511
477
512
case XI_KeyPress :
0 commit comments