| /* |
| Simple DirectMedia Layer |
| Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org> |
| |
| This software is provided 'as-is', without any express or implied |
| warranty. In no event will the authors be held liable for any damages |
| arising from the use of this software. |
| |
| Permission is granted to anyone to use this software for any purpose, |
| including commercial applications, and to alter it and redistribute it |
| freely, subject to the following restrictions: |
| |
| 1. The origin of this software must not be misrepresented; you must not |
| claim that you wrote the original software. If you use this software |
| in a product, an acknowledgment in the product documentation would be |
| appreciated but is not required. |
| 2. Altered source versions must be plainly marked as such, and must not be |
| misrepresented as being the original software. |
| 3. This notice may not be removed or altered from any source distribution. |
| */ |
| |
| #ifndef NO_BUILD_CONFIG |
| #include <stddef.h> |
| |
| /** |
| * Pen test suite |
| */ |
| |
| #define SDL_internal_h_ /* Inhibit dynamic symbol redefinitions that clash with ours */ |
| |
| /* ================= System Under Test (SUT) ================== */ |
| /* Renaming SUT operations to avoid link-time symbol clashes */ |
| #define SDL_GetPens SDL_SUT_GetPens |
| #define SDL_GetPenStatus SDL_SUT_GetPenStatus |
| #define SDL_GetPenFromGUID SDL_SUT_GetPenFromGUID |
| #define SDL_GetPenGUID SDL_SUT_GetPenGUID |
| #define SDL_PenConnected SDL_SUT_PenConnected |
| #define SDL_GetPenName SDL_SUT_GetPenName |
| #define SDL_GetPenCapabilities SDL_SUT_GetPenCapabilities |
| #define SDL_GetPenType SDL_SUT_GetPenType |
| |
| #define SDL_GetPenPtr SDL_SUT_GetPenPtr |
| #define SDL_PenModifyBegin SDL_SUT_PenModifyBegin |
| #define SDL_PenModifyAddCapabilities SDL_SUT_PenModifyAddCapabilities |
| #define SDL_PenModifyForWacomID SDL_SUT_PenModifyForWacomID |
| #define SDL_PenUpdateGUIDForWacom SDL_SUT_PenUpdateGUIDForWacom |
| #define SDL_PenUpdateGUIDForType SDL_SUT_PenUpdateGUIDForType |
| #define SDL_PenUpdateGUIDForGeneric SDL_SUT_PenUpdateGUIDForGeneric |
| #define SDL_PenModifyEnd SDL_SUT_PenModifyEnd |
| #define SDL_PenGCMark SDL_SUT_PenGCMark |
| #define SDL_PenGCSweep SDL_SUT_PenGCSweep |
| #define SDL_SendPenMotion SDL_SUT_SendPenMotion |
| #define SDL_SendPenButton SDL_SUT_SendPenButton |
| #define SDL_SendPenTipEvent SDL_SUT_SendPenTipEvent |
| #define SDL_SendPenWindowEvent SDL_SUT_SendPenWindowEvent |
| #define SDL_PenPerformHitTest SDL_SUT_PenPerformHitTest |
| #define SDL_PenInit SDL_SUT_PenInit |
| #define SDL_PenQuit SDL_SUT_PenQuit |
| |
| /* ================= Mock API ================== */ |
| |
| #include <stdlib.h> |
| #include <SDL3/SDL.h> |
| #include <SDL3/SDL_test.h> |
| /* For SDL_Window, SDL_Mouse, SDL_MouseID: */ |
| #include "../src/events/SDL_mouse_c.h" |
| /* Divert calls to mock mouse API: */ |
| #define SDL_SendMouseMotion SDL_Mock_SendMouseMotion |
| #define SDL_SendMouseButton SDL_Mock_SendMouseButton |
| #define SDL_GetMouse SDL_Mock_GetMouse |
| #define SDL_MousePositionInWindow SDL_Mock_MousePositionInWindow |
| #define SDL_SetMouseFocus SDL_Mock_SetMouseFocus |
| |
| /* Mock mouse API */ |
| static int SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, SDL_bool relative, float x, float y); |
| static int SDL_SendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button); |
| static SDL_Mouse *SDL_GetMouse(void); |
| static SDL_bool SDL_MousePositionInWindow(SDL_Window *window, float x, float y); |
| static void SDL_SetMouseFocus(SDL_Window *window); |
| |
| /* Import SUT code with macro-renamed function names */ |
| #define SDL_waylanddyn_h_ /* hack: suppress spurious build problem with libdecor.h on Wayland */ |
| #include "../src/events/SDL_pen.c" |
| #include "../src/events/SDL_pen_c.h" |
| |
| |
| /* ================= Internal SDL API Compatibility ================== */ |
| /* Mock implementations of Pen -> Mouse calls */ |
| /* Not thread-safe! */ |
| |
| static SDL_bool SDL_MousePositionInWindow(SDL_Window *window, float x, float y) |
| { |
| return SDL_TRUE; |
| } |
| |
| static int _mouseemu_last_event = 0; |
| static float _mouseemu_last_x = 0.0f; |
| static float _mouseemu_last_y = 0.0f; |
| static int _mouseemu_last_mouseid = 0; |
| static int _mouseemu_last_button = 0; |
| static SDL_bool _mouseemu_last_relative = SDL_FALSE; |
| static int _mouseemu_last_focus = -1; |
| |
| static int SDL_SendMouseButton(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button) |
| { |
| if (mouseID == SDL_PEN_MOUSEID) { |
| _mouseemu_last_event = (state == SDL_PRESSED) ? SDL_EVENT_MOUSE_BUTTON_DOWN : SDL_EVENT_MOUSE_BUTTON_UP; |
| _mouseemu_last_button = button; |
| _mouseemu_last_mouseid = mouseID; |
| } |
| return 1; |
| } |
| |
| static int SDL_SendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, SDL_bool relative, float x, float y) |
| { |
| if (mouseID == SDL_PEN_MOUSEID) { |
| _mouseemu_last_event = SDL_EVENT_MOUSE_MOTION; |
| _mouseemu_last_x = x; |
| _mouseemu_last_y = y; |
| _mouseemu_last_mouseid = mouseID; |
| _mouseemu_last_relative = relative; |
| } |
| return 1; |
| } |
| |
| static SDL_Mouse *SDL_GetMouse(void) |
| { |
| static SDL_Mouse dummy_mouse; |
| |
| return &dummy_mouse; |
| } |
| |
| static void SDL_SetMouseFocus(SDL_Window *window) |
| { |
| _mouseemu_last_focus = window ? 1 : 0; |
| } |
| |
| /* ================= Test Case Support ================== */ |
| |
| #define PEN_NUM_TEST_IDS 8 |
| |
| /* Helper functions */ |
| |
| /* Iterate over all pens to find index for pen ID, otherwise -1 */ |
| static int _pen_iterationFindsPenIDAt(SDL_PenID needle) |
| { |
| int i; |
| int num_pens = -1; |
| |
| SDL_PenID *pens = SDL_GetPens(&num_pens); |
| /* Check for (a) consistency and (b) ability to handle NULL parameter */ |
| SDL_PenID *pens2 = SDL_GetPens(NULL); |
| |
| SDLTest_AssertCheck(num_pens >= 0, |
| "SDL_GetPens() yielded %d pens", num_pens); |
| SDLTest_AssertCheck(pens[num_pens] == 0, |
| "SDL_GetPens() not 0 terminated (num_pens = %d)", num_pens); |
| SDLTest_AssertCheck(pens2[num_pens] == 0, |
| "SDL_GetPens(NULL) not 0 terminated (num_pens = %d)", num_pens); |
| |
| for (i = 0; i < num_pens; ++i) { |
| SDLTest_AssertCheck(pens[i] == pens2[i], |
| "SDL_GetPens(&i) and SDL_GetPens(NULL) disagree at index %d/%d", i, num_pens); |
| SDLTest_AssertCheck(pens[i] != SDL_PEN_INVALID, |
| "Invalid pen ID %08lx at index %d/%d after SDL_GetPens()", (unsigned long) pens[i], i, num_pens); |
| } |
| SDL_free(pens2); |
| |
| for (i = 0; pens[i]; ++i) { |
| SDL_PenID pen_id = pens[i]; |
| |
| SDLTest_AssertCheck(pen_id != SDL_PEN_INVALID, |
| "Invalid pen ID %08lx at index %d/%d after SDL_GetPens()", (unsigned long) pen_id, i, num_pens); |
| if (pen_id == needle) { |
| SDL_free(pens); |
| return i; |
| } |
| } |
| SDL_free(pens); |
| return -1; |
| } |
| |
| /* Retrieve number of pens and sanity-check SDL_GetPens() */ |
| static int |
| _num_pens(void) |
| { |
| int num_pens = -1; |
| SDL_PenID *pens = SDL_GetPens(&num_pens); |
| SDLTest_AssertCheck(pens != NULL, |
| "SDL_GetPens() => NULL"); |
| SDLTest_AssertCheck(num_pens >= 0, |
| "SDL_GetPens() reports %d pens", num_pens); |
| SDLTest_AssertCheck(pens[num_pens] == 0, |
| "SDL_GetPens()[%d] != 0", num_pens); |
| SDL_free(pens); |
| return num_pens; |
| } |
| |
| /* Assert number of pens is as expected */ |
| static void _AssertCheck_num_pens(int expected, char *location) |
| { |
| int num_pens = _num_pens(); |
| SDLTest_AssertCheck(expected == num_pens, |
| "Expected SDL_GetPens() =>count = %d, actual = %d: %s", expected, num_pens, location); |
| } |
| |
| /* ---------------------------------------- */ |
| /* Test device deallocation */ |
| |
| typedef struct /* Collection of pen (de)allocation information */ |
| { |
| unsigned int deallocated_id_flags; /* ith bits set to 1 if the ith test_id is deallocated */ |
| unsigned int deallocated_deviceinfo_flags; /* ith bits set to 1 if deviceinfo as *int with value i was deallocated */ |
| SDL_PenID ids[PEN_NUM_TEST_IDS]; |
| SDL_GUID guids[PEN_NUM_TEST_IDS]; |
| SDL_Window *window; |
| int num_ids; |
| int initial_pen_count; |
| } pen_testdata; |
| |
| /* SDL_PenGCSweep(): callback for tracking pen deallocation */ |
| static void _pen_testdata_callback(Uint32 deviceid, void *deviceinfo, void *tracker_ref) |
| { |
| pen_testdata *tracker = (pen_testdata *)tracker_ref; |
| int offset = -1; |
| int i; |
| |
| for (i = 0; i < tracker->num_ids; ++i) { |
| if (deviceid == tracker->ids[i]) { |
| tracker->deallocated_id_flags |= (1 << i); |
| } |
| } |
| |
| SDLTest_AssertCheck(deviceinfo != NULL, |
| "Device %lu has deviceinfo", |
| (unsigned long) deviceid); |
| offset = *((int *)deviceinfo); |
| SDLTest_AssertCheck(offset >= 0 && offset <= 31, |
| "Device %lu has well-formed deviceinfo %d", |
| (unsigned long) deviceid, offset); |
| tracker->deallocated_deviceinfo_flags |= 1 << offset; |
| SDL_free(deviceinfo); |
| } |
| |
| /* GC Sweep tracking: update "tracker->deallocated_id_flags" and "tracker->deallocated_deviceinfo_flags" to record deallocations */ |
| static void _pen_trackGCSweep(pen_testdata *tracker) |
| { |
| tracker->deallocated_id_flags = 0; |
| tracker->deallocated_deviceinfo_flags = 0; |
| SDL_PenGCSweep(tracker, _pen_testdata_callback); |
| } |
| |
| /* Finds a number of unused pen IDs (does not allocate them). Also initialises GUIDs. */ |
| static void _pen_unusedIDs(pen_testdata *tracker, int count) |
| { |
| static Uint8 guidmod = 0; /* Ensure uniqueness as long as we use no more than 256 test pens */ |
| Uint32 synthetic_penid = 1000u; |
| int index = 0; |
| |
| tracker->num_ids = count; |
| SDLTest_AssertCheck(count < PEN_NUM_TEST_IDS, "Test setup: Valid number of test IDs requested: %d", (int)count); |
| |
| while (count--) { |
| int k; |
| |
| while (SDL_GetPenPtr(synthetic_penid)) { |
| ++synthetic_penid; |
| } |
| tracker->ids[index] = synthetic_penid; |
| for (k = 0; k < 15; ++k) { |
| tracker->guids[index].data[k] = (Uint8)((16 * k) + index); |
| } |
| tracker->guids[index].data[15] = ++guidmod; |
| |
| ++synthetic_penid; |
| ++index; |
| } |
| } |
| |
| #define DEVICEINFO_UNCHANGED -17 |
| |
| /* Allocate deviceinfo for pen */ |
| static void _pen_setDeviceinfo(SDL_Pen *pen, int deviceinfo) |
| { |
| if (deviceinfo == DEVICEINFO_UNCHANGED) { |
| SDLTest_AssertCheck(pen->deviceinfo != NULL, |
| "pen->deviceinfo was already set for %p (%lu), as expected", |
| pen, (unsigned long) pen->header.id); |
| } else { |
| int *data = (int *)SDL_malloc(sizeof(int)); |
| *data = deviceinfo; |
| |
| SDLTest_AssertCheck(pen->deviceinfo == NULL, |
| "pen->deviceinfo was NULL for %p (%lu) when requesting deviceinfo %d", |
| pen, (unsigned long) pen->header.id, deviceinfo); |
| |
| pen->deviceinfo = data; |
| } |
| SDL_PenModifyEnd(pen, SDL_TRUE); |
| } |
| |
| /* ---------------------------------------- */ |
| /* Back up and restore device information */ |
| |
| typedef struct deviceinfo_backup |
| { |
| Uint32 deviceid; |
| void *deviceinfo; |
| struct deviceinfo_backup *next; |
| } deviceinfo_backup; |
| |
| /* SDL_PenGCSweep(): Helper callback for collecting all deviceinfo records */ |
| static void _pen_accumulate_gc_sweep(Uint32 deviceid, void *deviceinfo, void *backup_ref) |
| { |
| deviceinfo_backup **db_ref = (deviceinfo_backup **)backup_ref; |
| deviceinfo_backup *next = *db_ref; |
| |
| *db_ref = SDL_calloc(sizeof(deviceinfo_backup), 1); |
| (*db_ref)->deviceid = deviceid; |
| (*db_ref)->deviceinfo = deviceinfo; |
| (*db_ref)->next = next; |
| } |
| |
| /* SDL_PenGCSweep(): Helper callback that must never be called */ |
| static void _pen_assert_impossible(Uint32 deviceid, void *deviceinfo, void *backup_ref) |
| { |
| SDLTest_AssertCheck(0, "Deallocation for deviceid %lu during enableAndRestore: not expected", |
| (unsigned long) deviceid); |
| } |
| |
| /* Disable all pens and store their status */ |
| static deviceinfo_backup *_pen_disableAndBackup(void) |
| { |
| deviceinfo_backup *backup = NULL; |
| |
| SDL_PenGCMark(); |
| SDL_PenGCSweep(&backup, _pen_accumulate_gc_sweep); |
| return backup; |
| } |
| |
| /* Restore all pens to their previous status */ |
| static void _pen_enableAndRestore(deviceinfo_backup *backup, int test_marksweep) |
| { |
| if (test_marksweep) { |
| SDL_PenGCMark(); |
| } |
| while (backup) { |
| SDL_Pen *disabledpen = SDL_GetPenPtr(backup->deviceid); |
| deviceinfo_backup *next = backup->next; |
| |
| SDL_PenModifyEnd(SDL_PenModifyBegin(disabledpen->header.id), |
| SDL_TRUE); |
| disabledpen->deviceinfo = backup->deviceinfo; |
| |
| SDL_free(backup); |
| backup = next; |
| } |
| if (test_marksweep) { |
| SDL_PenGCSweep(NULL, _pen_assert_impossible); |
| } |
| } |
| |
| static struct SDL_Window _test_window = { 0 }; |
| |
| /* ---------------------------------------- */ |
| /* Default set-up and tear down routines */ |
| |
| /* Back up existing pens, allocate fresh ones but don't assign them yet */ |
| static deviceinfo_backup *_setup_test(pen_testdata *ptest, int pens_for_testing) |
| { |
| int i; |
| deviceinfo_backup *backup; |
| |
| /* Get number of pens */ |
| SDL_free(SDL_GetPens(&ptest->initial_pen_count)); |
| |
| /* Provide fake window for window enter/exit simulation */ |
| _test_window.id = 0x7e57da7a; |
| _test_window.w = 1600; |
| _test_window.h = 1200; |
| ptest->window = &_test_window; |
| |
| /* Grab unused pen IDs for testing */ |
| _pen_unusedIDs(ptest, pens_for_testing); |
| for (i = 0; i < pens_for_testing; ++i) { |
| int index = _pen_iterationFindsPenIDAt(ptest->ids[i]); |
| SDLTest_AssertCheck(-1 == index, |
| "Registered PenID(%lu) since index %d == -1", |
| (unsigned long) ptest->ids[i], index); |
| } |
| |
| /* Remove existing pens, but back up */ |
| backup = _pen_disableAndBackup(); |
| |
| _AssertCheck_num_pens(0, "after disabling and backing up all current pens"); |
| SDLTest_AssertPass("Removed existing pens"); |
| |
| return backup; |
| } |
| |
| static void _teardown_test_general(pen_testdata *ptest, deviceinfo_backup *backup, int with_gc_test) |
| { |
| /* Restore previously existing pens */ |
| _pen_enableAndRestore(backup, with_gc_test); |
| |
| /* validate */ |
| SDLTest_AssertPass("Restored pens to pre-test state"); |
| _AssertCheck_num_pens(ptest->initial_pen_count, "after restoring all initial pens"); |
| } |
| |
| static void _teardown_test(pen_testdata *ptest, deviceinfo_backup *backup) |
| { |
| _teardown_test_general(ptest, backup, 0); |
| } |
| |
| static void _teardown_test_with_gc(pen_testdata *ptest, deviceinfo_backup *backup) |
| { |
| _teardown_test_general(ptest, backup, 1); |
| } |
| |
| /* ---------------------------------------- */ |
| /* Pen simulation */ |
| |
| #define SIMPEN_ACTION_DONE 0 |
| #define SIMPEN_ACTION_MOVE_X 1 |
| #define SIMPEN_ACTION_MOVE_Y 2 |
| #define SIMPEN_ACTION_AXIS 3 |
| #define SIMPEN_ACTION_MOTION_EVENT 4 /* epxlicit motion event */ |
| #define SIMPEN_ACTION_MOTION_EVENT_S 5 /* send motion event but expect it to be suppressed */ |
| #define SIMPEN_ACTION_PRESS 6 /* implicit update event */ |
| #define SIMPEN_ACTION_RELEASE 7 /* implicit update event */ |
| #define SIMPEN_ACTION_DOWN 8 /* implicit update event */ |
| #define SIMPEN_ACTION_UP 9 /* implicit update event */ |
| #define SIMPEN_ACTION_ERASER_MODE 10 |
| |
| /* Individual action in pen simulation script */ |
| typedef struct simulated_pen_action |
| { |
| int type; |
| int pen_index; /* index into the list of simulated pens */ |
| int index; /* button or axis number, if needed */ |
| float update; /* x,y; for AXIS, update[0] is the updated axis */ |
| } simulated_pen_action; |
| |
| static simulated_pen_action _simpen_event(int type, int pen_index, int index, float v, int line_nr) |
| { |
| simulated_pen_action action; |
| action.type = type; |
| action.pen_index = pen_index; |
| action.index = index; |
| action.update = v; |
| |
| /* Sanity check-- turned out to be necessary */ |
| if ((type == SIMPEN_ACTION_PRESS || type == SIMPEN_ACTION_RELEASE) && index == 0) { |
| SDL_Log("Error: SIMPEN_EVENT_BUTTON must have button > 0 (first button has number 1!), in line %d!", line_nr); |
| exit(1); |
| } |
| return action; |
| } |
| |
| /* STEP is passed in later (C macros use dynamic scoping) */ |
| |
| #define SIMPEN_DONE() \ |
| STEP _simpen_event(SIMPEN_ACTION_DONE, 0, 0, 0.0f, __LINE__) |
| #define SIMPEN_MOVE(pen_index, x, y) \ |
| STEP _simpen_event(SIMPEN_ACTION_MOVE_X, (pen_index), 0, (x), __LINE__); \ |
| STEP _simpen_event(SIMPEN_ACTION_MOVE_Y, (pen_index), 0, (y), __LINE__) |
| |
| #define SIMPEN_AXIS(pen_index, axis, y) \ |
| STEP _simpen_event(SIMPEN_ACTION_AXIS, (pen_index), (axis), (y), __LINE__) |
| |
| #define SIMPEN_EVENT_MOTION(pen_index) \ |
| STEP _simpen_event(SIMPEN_ACTION_MOTION_EVENT, (pen_index), 0, 0.0f, __LINE__) |
| |
| #define SIMPEN_EVENT_MOTION_SUPPRESSED(pen_index) \ |
| STEP _simpen_event(SIMPEN_ACTION_MOTION_EVENT_S, (pen_index), 0, 0.0f, __LINE__) |
| |
| #define SIMPEN_EVENT_BUTTON(pen_index, push, button) \ |
| STEP _simpen_event((push) ? SIMPEN_ACTION_PRESS : SIMPEN_ACTION_RELEASE, (pen_index), (button), 0.0f, __LINE__) |
| |
| #define SIMPEN_EVENT_TIP(pen_index, touch, tip) \ |
| STEP _simpen_event((touch) ? SIMPEN_ACTION_DOWN : SIMPEN_ACTION_UP, (pen_index), tip, 0.0f, __LINE__) |
| |
| #define SIMPEN_SET_ERASER(pen_index, eraser_mode) \ |
| STEP _simpen_event(SIMPEN_ACTION_ERASER_MODE, (pen_index), eraser_mode, 0.0f, __LINE__) |
| |
| static void |
| _pen_dump(const char *prefix, SDL_Pen *pen) |
| { |
| int i; |
| char *axes_str; |
| |
| if (!pen) { |
| SDL_Log("(NULL pen)"); |
| return; |
| } |
| |
| axes_str = SDL_strdup(""); |
| for (i = 0; i < SDL_PEN_NUM_AXES; ++i) { |
| char *old_axes_str = axes_str; |
| SDL_asprintf(&axes_str, "%s\t%f", old_axes_str, pen->last.axes[i]); |
| SDL_free(old_axes_str); |
| } |
| SDL_Log("%s: pen %lu (%s): status=%04lx, flags=%lx, x,y=(%f, %f) axes = %s", |
| prefix, |
| (unsigned long) pen->header.id, |
| pen->name, |
| (unsigned long) pen->last.buttons, |
| (unsigned long) pen->header.flags, |
| pen->last.x, pen->last.y, |
| axes_str); |
| SDL_free(axes_str); |
| } |
| |
| /* Runs until the next event has been issued or we are done and returns pointer to it. |
| Returns NULL once we hit SIMPEN_ACTION_DONE. |
| Updates simulated_pens accordingly. There must be as many simulated_pens as the highest pen_index used in |
| any of the "steps". |
| Also validates the internal state with expectations (via SDL_GetPenStatus()) and updates the, but does not poll SDL events. */ |
| static simulated_pen_action * |
| _pen_simulate(simulated_pen_action *steps, int *step_counter, SDL_Pen *simulated_pens, int num_pens) |
| { |
| SDL_bool done = SDL_FALSE; |
| SDL_bool dump_pens = SDL_FALSE; |
| unsigned int mask; |
| int pen_nr; |
| |
| do { |
| simulated_pen_action step = steps[*step_counter]; |
| SDL_Pen *simpen = &simulated_pens[step.pen_index]; |
| |
| if (step.pen_index >= num_pens) { |
| SDLTest_AssertCheck(0, |
| "Unexpected pen index %d at step %d, action %d", step.pen_index, *step_counter, step.type); |
| return NULL; |
| } |
| |
| switch (step.type) { |
| case SIMPEN_ACTION_DONE: |
| SDLTest_AssertPass("SIMPEN_ACTION_DONE"); |
| return NULL; |
| |
| case SIMPEN_ACTION_MOVE_X: |
| SDLTest_AssertPass("SIMPEN_ACTION_MOVE_X [pen %d] : y <- %f", step.pen_index, step.update); |
| simpen->last.x = step.update; |
| break; |
| |
| case SIMPEN_ACTION_MOVE_Y: |
| SDLTest_AssertPass("SIMPEN_ACTION_MOVE_Y [pen %d] : x <- %f", step.pen_index, step.update); |
| simpen->last.y = step.update; |
| break; |
| |
| case SIMPEN_ACTION_AXIS: |
| SDLTest_AssertPass("SIMPEN_ACTION_AXIS [pen %d] : axis[%d] <- %f", step.pen_index, step.index, step.update); |
| simpen->last.axes[step.index] = step.update; |
| break; |
| |
| case SIMPEN_ACTION_MOTION_EVENT: |
| done = SDL_TRUE; |
| SDLTest_AssertCheck(SDL_SendPenMotion(0, simpen->header.id, SDL_TRUE, |
| &simpen->last), |
| "SIMPEN_ACTION_MOTION_EVENT [pen %d]", step.pen_index); |
| break; |
| |
| case SIMPEN_ACTION_MOTION_EVENT_S: |
| SDLTest_AssertCheck(!SDL_SendPenMotion(0, simpen->header.id, SDL_TRUE, |
| &simpen->last), |
| "SIMPEN_ACTION_MOTION_EVENT_SUPPRESSED [pen %d]", step.pen_index); |
| break; |
| |
| case SIMPEN_ACTION_PRESS: |
| mask = (1 << (step.index - 1)); |
| simpen->last.buttons |= mask; |
| SDLTest_AssertCheck(SDL_SendPenButton(0, simpen->header.id, SDL_PRESSED, (Uint8)step.index), |
| "SIMPEN_ACTION_PRESS [pen %d]: button %d (mask %x)", step.pen_index, step.index, mask); |
| done = SDL_TRUE; |
| break; |
| |
| case SIMPEN_ACTION_RELEASE: |
| mask = ~(1 << (step.index - 1)); |
| simpen->last.buttons &= mask; |
| SDLTest_AssertCheck(SDL_SendPenButton(0, simpen->header.id, SDL_RELEASED, (Uint8)step.index), |
| "SIMPEN_ACTION_RELEASE [pen %d]: button %d (mask %x)", step.pen_index, step.index, mask); |
| done = SDL_TRUE; |
| break; |
| |
| case SIMPEN_ACTION_DOWN: |
| simpen->last.buttons |= SDL_PEN_DOWN_MASK; |
| SDLTest_AssertCheck(SDL_SendPenTipEvent(0, simpen->header.id, SDL_PRESSED), |
| "SIMPEN_ACTION_DOWN [pen %d]: (mask %lx)", step.pen_index, SDL_PEN_DOWN_MASK); |
| done = SDL_TRUE; |
| break; |
| |
| case SIMPEN_ACTION_UP: |
| simpen->last.buttons &= ~SDL_PEN_DOWN_MASK; |
| SDLTest_AssertCheck(SDL_SendPenTipEvent(0, simpen->header.id, SDL_RELEASED), |
| "SIMPEN_ACTION_UP [pen %d]: (mask %lx)", step.pen_index, ~SDL_PEN_DOWN_MASK); |
| done = SDL_TRUE; |
| break; |
| |
| case SIMPEN_ACTION_ERASER_MODE: { |
| Uint32 pmask; |
| SDL_Pen *pen = SDL_PenModifyBegin(simpen->header.id); |
| |
| if (step.index) { |
| pmask = SDL_PEN_ERASER_MASK; |
| } else { |
| pmask = SDL_PEN_INK_MASK; |
| } |
| |
| SDL_PenModifyAddCapabilities(pen, pmask); |
| SDL_PenModifyEnd(pen, SDL_TRUE); |
| |
| simpen->header.flags &= ~(SDL_PEN_INK_MASK | SDL_PEN_ERASER_MASK); |
| simpen->header.flags |= pmask; |
| break; |
| } |
| |
| default: |
| SDLTest_AssertCheck(0, |
| "Unexpected pen simulation action %d", step.type); |
| return NULL; |
| } |
| ++(*step_counter); |
| } while (!done); |
| |
| for (pen_nr = 0; pen_nr < num_pens; ++pen_nr) { |
| SDL_Pen *simpen = &simulated_pens[pen_nr]; |
| float x = -1.0f, y = -1.0f; |
| float axes[SDL_PEN_NUM_AXES]; |
| Uint32 actual_flags = SDL_GetPenStatus(simpen->header.id, &x, &y, axes, SDL_PEN_NUM_AXES); |
| int i; |
| |
| if (simpen->last.x != x || simpen->last.y != y) { |
| SDLTest_AssertCheck(0, "Coordinate mismatch in pen %d", pen_nr); |
| dump_pens = SDL_TRUE; |
| } |
| if ((actual_flags & ~(SDL_PEN_INK_MASK | SDL_PEN_ERASER_MASK)) != (simpen->last.buttons & ~(SDL_PEN_INK_MASK | SDL_PEN_ERASER_MASK))) { |
| SDLTest_AssertCheck(0, "Status mismatch in pen %d (reported: %08x)", pen_nr, (unsigned int)actual_flags); |
| dump_pens = SDL_TRUE; |
| } |
| if ((actual_flags & (SDL_PEN_INK_MASK | SDL_PEN_ERASER_MASK)) != (simpen->header.flags & (SDL_PEN_INK_MASK | SDL_PEN_ERASER_MASK))) { |
| SDLTest_AssertCheck(0, "Flags mismatch in pen %d (reported: %08x)", pen_nr, (unsigned int)actual_flags); |
| dump_pens = SDL_TRUE; |
| } |
| for (i = 0; i < SDL_PEN_NUM_AXES; ++i) { |
| if (axes[i] != simpen->last.axes[i]) { |
| SDLTest_AssertCheck(0, "Axis %d mismatch in pen %d", pen_nr, i); |
| dump_pens = SDL_TRUE; |
| } |
| } |
| } |
| |
| if (dump_pens) { |
| int i; |
| for (i = 0; i < num_pens; ++i) { |
| SDL_Log("==== pen #%d", i); |
| _pen_dump("expect", simulated_pens + i); |
| _pen_dump("actual", SDL_GetPenPtr(simulated_pens[i].header.id)); |
| } |
| } |
| |
| return &steps[(*step_counter) - 1]; |
| } |
| |
| /* Init simulated_pens with suitable initial state */ |
| static void |
| _pen_simulate_init(pen_testdata *ptest, SDL_Pen *simulated_pens, int num_pens) |
| { |
| int i; |
| for (i = 0; i < num_pens; ++i) { |
| simulated_pens[i] = *SDL_GetPenPtr(ptest->ids[i]); |
| } |
| } |
| |
| /* ---------------------------------------- */ |
| /* Other helper functions */ |
| |
| /* "standard" pen registration process */ |
| static SDL_Pen * |
| _pen_register(SDL_PenID penid, SDL_GUID guid, char *name, Uint32 flags) |
| { |
| SDL_Pen *pen = SDL_PenModifyBegin(penid); |
| pen->guid = guid; |
| SDL_strlcpy(pen->name, name, SDL_PEN_MAX_NAME); |
| SDL_PenModifyAddCapabilities(pen, flags); |
| return pen; |
| } |
| |
| /* Test whether EXPECTED and ACTUAL of type TY agree. Their C format string must be FMT. |
| MESSAGE is a string with one format string, passed as ARG0. */ |
| #define SDLTest_AssertEq1(TY, FMT, EXPECTED, ACTUAL, MESSAGE, ARG0) \ |
| { \ |
| TY _t_expect = (EXPECTED); \ |
| TY _t_actual = (ACTUAL); \ |
| SDLTest_AssertCheck(_t_expect == _t_actual, "L%d: " MESSAGE ": expected " #EXPECTED " = " FMT ", actual = " FMT, __LINE__, (ARG0), _t_expect, _t_actual); \ |
| } |
| |
| /* ================= Test Case Implementation ================== */ |
| |
| /** |
| * @brief Check basic pen device introduction and iteration, as well as basic queries |
| * |
| * @sa SDL_GetPens, SDL_GetPenName, SDL_GetPenCapabilities |
| */ |
| static int |
| pen_iteration(void *arg) |
| { |
| pen_testdata ptest; |
| int i; |
| char long_pen_name[SDL_PEN_MAX_NAME + 10]; |
| const char *name; |
| deviceinfo_backup *backup; |
| |
| /* Check initial pens */ |
| SDL_PumpEvents(); |
| SDLTest_AssertPass("SDL_GetPens() => count = %d", _num_pens()); |
| |
| /* Grab unused pen IDs for testing */ |
| backup = _setup_test(&ptest, 3); /* validates that we have zero pens */ |
| |
| /* Re-run GC, track deallocations */ |
| SDL_PenGCMark(); |
| _pen_trackGCSweep(&ptest); |
| _AssertCheck_num_pens(0, "after second GC pass"); |
| SDLTest_AssertCheck(ptest.deallocated_id_flags == 0, "No unexpected device deallocations"); |
| SDLTest_AssertCheck(ptest.deallocated_deviceinfo_flags == 0, "No unexpected deviceinfo deallocations"); |
| SDLTest_AssertPass("Validated that GC on empty pen set is idempotent"); |
| |
| /* Add three pens, validate */ |
| SDL_PenGCMark(); |
| |
| SDL_memset(long_pen_name, 'x', sizeof(long_pen_name)); /* Include pen name that is too long */ |
| long_pen_name[sizeof(long_pen_name) - 1] = 0; |
| |
| _pen_setDeviceinfo(_pen_register(ptest.ids[0], ptest.guids[0], "pen 0", |
| SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK), |
| 16); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[2], ptest.guids[2], long_pen_name, |
| SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_XTILT_MASK), |
| 20); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[1], ptest.guids[1], "pen 1", |
| SDL_PEN_ERASER_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_YTILT_MASK), |
| 24); |
| _pen_trackGCSweep(&ptest); |
| |
| _AssertCheck_num_pens(3, "after allocating three pens"); |
| |
| SDLTest_AssertCheck(ptest.deallocated_id_flags == 0, "No unexpected device deallocations"); |
| SDLTest_AssertCheck(ptest.deallocated_deviceinfo_flags == 0, "No unexpected deviceinfo deallocations"); |
| |
| for (i = 0; i < 3; ++i) { |
| /* Check that all pens are accounted for */ |
| int index = _pen_iterationFindsPenIDAt(ptest.ids[i]); |
| SDLTest_AssertCheck(-1 != index, "Found PenID(%lu)", (unsigned long) ptest.ids[i]); |
| } |
| SDLTest_AssertPass("Validated that all three pens are indexable"); |
| |
| /* Check pen properties */ |
| SDLTest_AssertCheck(0 == SDL_strcmp("pen 0", SDL_GetPenName(ptest.ids[0])), |
| "Pen #0 name"); |
| SDLTest_AssertCheck((SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK) == SDL_GetPenCapabilities(ptest.ids[0], NULL), |
| "Pen #0 capabilities"); |
| |
| SDLTest_AssertCheck(0 == SDL_strcmp("pen 1", SDL_GetPenName(ptest.ids[1])), |
| "Pen #1 name"); |
| SDLTest_AssertCheck((SDL_PEN_ERASER_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_YTILT_MASK) == SDL_GetPenCapabilities(ptest.ids[1], NULL), |
| "Pen #1 capabilities"); |
| |
| name = SDL_GetPenName(ptest.ids[2]); |
| SDLTest_AssertCheck(SDL_PEN_MAX_NAME - 1 == SDL_strlen(name), |
| "Pen #2 name length"); |
| SDLTest_AssertCheck(0 == SDL_memcmp(name, long_pen_name, SDL_PEN_MAX_NAME - 1), |
| "Pen #2 name contents"); |
| SDLTest_AssertCheck((SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_XTILT_MASK) == SDL_GetPenCapabilities(ptest.ids[2], NULL), |
| "Pen #2 capabilities"); |
| SDLTest_AssertPass("Pen registration and basic queries"); |
| |
| /* Re-run GC, track deallocations */ |
| SDL_PenGCMark(); |
| _pen_trackGCSweep(&ptest); |
| _AssertCheck_num_pens(0, "after third GC pass"); |
| SDLTest_AssertCheck(ptest.deallocated_id_flags == 0x07, |
| "No unexpected device deallocation : %08x", ptest.deallocated_id_flags); |
| SDLTest_AssertCheck(ptest.deallocated_deviceinfo_flags == 0x01110000, |
| "No unexpected deviceinfo deallocation : %08x ", ptest.deallocated_deviceinfo_flags); |
| SDLTest_AssertPass("Validated that GC on empty pen set is idempotent"); |
| |
| /* tear down and finish */ |
| _teardown_test(&ptest, backup); |
| return TEST_COMPLETED; |
| } |
| |
| static void |
| _expect_pen_attached(SDL_PenID penid) |
| { |
| SDLTest_AssertCheck(-1 != _pen_iterationFindsPenIDAt(penid), |
| "Found PenID(%lu)", (unsigned long) penid); |
| SDLTest_AssertCheck(SDL_PenConnected(penid), |
| "Pen %lu was attached, as expected", (unsigned long) penid); |
| } |
| |
| static void |
| _expect_pen_detached(SDL_PenID penid) |
| { |
| SDLTest_AssertCheck(-1 == _pen_iterationFindsPenIDAt(penid), |
| "Did not find PenID(%lu), as expected", (unsigned long) penid); |
| SDLTest_AssertCheck(!SDL_PenConnected(penid), |
| "Pen %lu was detached, as expected", (unsigned long) penid); |
| } |
| |
| #define ATTACHED(i) (1 << (i)) |
| |
| static void |
| _expect_pens_attached_or_detached(SDL_PenID *pen_ids, int ids, Uint32 mask) |
| { |
| int i; |
| int attached_count = 0; |
| for (i = 0; i < ids; ++i) { |
| if (mask & (1 << i)) { |
| ++attached_count; |
| _expect_pen_attached(pen_ids[i]); |
| } else { |
| _expect_pen_detached(pen_ids[i]); |
| } |
| } |
| _AssertCheck_num_pens(attached_count, "While checking attached/detached status"); |
| } |
| |
| /** |
| * @brief Check pen device hotplugging |
| * |
| * @sa SDL_GetPens, SDL_GetPenName, SDL_GetPenCapabilities, SDL_PenConnected |
| */ |
| static int |
| pen_hotplugging(void *arg) |
| { |
| pen_testdata ptest; |
| deviceinfo_backup *backup = _setup_test(&ptest, 3); |
| SDL_GUID checkguid; |
| |
| /* Add two pens */ |
| SDL_PenGCMark(); |
| |
| _pen_setDeviceinfo(_pen_register(ptest.ids[0], ptest.guids[0], "pen 0", SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK), |
| 16); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[2], ptest.guids[2], "pen 2", SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK), |
| 24); |
| _pen_trackGCSweep(&ptest); |
| |
| _AssertCheck_num_pens(2, "after allocating two pens (pass 1)"); |
| SDLTest_AssertCheck(ptest.deallocated_id_flags == 0, "No unexpected device deallocation (pass 1)"); |
| SDLTest_AssertCheck(ptest.deallocated_deviceinfo_flags == 0, "No unexpected deviceinfo deallocation (pass 1)"); |
| |
| _expect_pens_attached_or_detached(ptest.ids, 3, ATTACHED(0) | ATTACHED(2)); |
| SDLTest_AssertPass("Validated hotplugging (pass 1): attachmend of two pens"); |
| |
| /* Introduce pen #1, remove pen #2 */ |
| SDL_PenGCMark(); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[0], ptest.guids[0], "pen 0", SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK), |
| DEVICEINFO_UNCHANGED); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[1], ptest.guids[1], "pen 1", SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK), |
| 20); |
| _pen_trackGCSweep(&ptest); |
| |
| _AssertCheck_num_pens(2, "after allocating two pens (pass 2)"); |
| SDLTest_AssertCheck(ptest.deallocated_id_flags == 0x04, "No unexpected device deallocation (pass 2): %x", ptest.deallocated_id_flags); |
| SDLTest_AssertCheck(ptest.deallocated_deviceinfo_flags == 0x01000000, "No unexpected deviceinfo deallocation (pass 2): %x", ptest.deallocated_deviceinfo_flags); |
| |
| _expect_pens_attached_or_detached(ptest.ids, 3, ATTACHED(0) | ATTACHED(1)); |
| SDLTest_AssertPass("Validated hotplugging (pass 2): unplug one, attach another"); |
| |
| /* Return to previous state (#0 and #2 attached) */ |
| SDL_PenGCMark(); |
| |
| _pen_setDeviceinfo(_pen_register(ptest.ids[0], ptest.guids[0], "pen 0", SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_YTILT), |
| DEVICEINFO_UNCHANGED); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[2], ptest.guids[2], "pen 2", SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK), |
| 24); |
| _pen_trackGCSweep(&ptest); |
| |
| _AssertCheck_num_pens(2, "after allocating two pens (pass 3)"); |
| SDLTest_AssertCheck(ptest.deallocated_id_flags == 0x02, "No unexpected device deallocation (pass 3)"); |
| SDLTest_AssertCheck(ptest.deallocated_deviceinfo_flags == 0x00100000, "No unexpected deviceinfo deallocation (pass 3)"); |
| |
| _expect_pens_attached_or_detached(ptest.ids, 3, ATTACHED(0) | ATTACHED(2)); |
| SDLTest_AssertPass("Validated hotplugging (pass 3): return to state of pass 1"); |
| |
| /* Introduce pen #1, remove pen #0 */ |
| SDL_PenGCMark(); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[1], ptest.guids[1], "pen 1", SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK), |
| 20); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[2], ptest.guids[2], "pen 2", SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK), |
| DEVICEINFO_UNCHANGED); |
| _pen_trackGCSweep(&ptest); |
| |
| _AssertCheck_num_pens(2, "after allocating two pens (pass 4)"); |
| SDLTest_AssertCheck(ptest.deallocated_id_flags == 0x01, "No unexpected device deallocation (pass 4): %x", ptest.deallocated_id_flags); |
| SDLTest_AssertCheck(ptest.deallocated_deviceinfo_flags == 0x00010000, "No unexpected deviceinfo deallocation (pass 4): %x", ptest.deallocated_deviceinfo_flags); |
| |
| _expect_pens_attached_or_detached(ptest.ids, 3, ATTACHED(1) | ATTACHED(2)); |
| SDLTest_AssertPass("Validated hotplugging (pass 5)"); |
| |
| /* Check detached pen */ |
| SDLTest_AssertCheck(0 == SDL_strcmp("pen 0", SDL_GetPenName(ptest.ids[0])), |
| "Pen #0 name"); |
| checkguid = SDL_GetPenGUID(ptest.ids[0]); |
| SDLTest_AssertCheck(0 == SDL_memcmp(ptest.guids[0].data, checkguid.data, sizeof(ptest.guids[0].data)), |
| "Pen #0 guid"); |
| SDLTest_AssertCheck((SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_YTILT) == SDL_GetPenCapabilities(ptest.ids[0], NULL), |
| "Pen #0 capabilities"); |
| SDLTest_AssertPass("Validated that detached pens retained name, GUID, axis info after pass 5"); |
| |
| /* Individually detach #1 dn #2 */ |
| _expect_pens_attached_or_detached(ptest.ids, 3, ATTACHED(1) | ATTACHED(2)); |
| SDL_PenModifyEnd(SDL_PenModifyBegin(ptest.ids[1]), SDL_FALSE); |
| _expect_pens_attached_or_detached(ptest.ids, 3, ATTACHED(2)); |
| |
| SDL_PenModifyEnd(SDL_PenModifyBegin(ptest.ids[2]), SDL_FALSE); |
| _expect_pens_attached_or_detached(ptest.ids, 3, 0); |
| |
| SDLTest_AssertPass("Validated individual hotplugging (pass 6)"); |
| |
| /* Individually attach all */ |
| SDL_PenModifyEnd(SDL_PenModifyBegin(ptest.ids[2]), SDL_TRUE); |
| _expect_pens_attached_or_detached(ptest.ids, 3, ATTACHED(2)); |
| |
| SDL_PenModifyEnd(SDL_PenModifyBegin(ptest.ids[0]), SDL_TRUE); |
| _expect_pens_attached_or_detached(ptest.ids, 3, ATTACHED(0) | ATTACHED(2)); |
| |
| SDL_PenModifyEnd(SDL_PenModifyBegin(ptest.ids[1]), SDL_TRUE); |
| _expect_pens_attached_or_detached(ptest.ids, 3, ATTACHED(0) | ATTACHED(1) | ATTACHED(2)); |
| SDLTest_AssertPass("Validated individual hotplugging (pass 7)"); |
| |
| SDL_PenGCMark(); |
| _pen_trackGCSweep(&ptest); |
| _AssertCheck_num_pens(0, "after hotplugging test (cleanup)"); |
| SDLTest_AssertCheck(ptest.deallocated_id_flags == 0x06, "No unexpected device deallocation (cleanup): %x", ptest.deallocated_id_flags); |
| SDLTest_AssertCheck(ptest.deallocated_deviceinfo_flags == 0x01100000, "No unexpected deviceinfo deallocation (pass 4): %x", ptest.deallocated_deviceinfo_flags); |
| |
| _teardown_test_with_gc(&ptest, backup); |
| |
| return TEST_COMPLETED; |
| } |
| |
| /** |
| * @brief Check pen device GUID handling |
| * |
| * @sa SDL_GetPenGUID |
| */ |
| static int |
| pen_GUIDs(void *arg) |
| { |
| int i; |
| char *names[4] = { "pen 0", "pen 1", "pen 2", "pen 3" }; |
| pen_testdata ptest; |
| deviceinfo_backup *backup; |
| |
| backup = _setup_test(&ptest, 4); |
| |
| /* Define four pens */ |
| SDL_PenGCMark(); |
| for (i = 0; i < 4; ++i) { |
| _pen_setDeviceinfo(_pen_register(ptest.ids[i], ptest.guids[i], names[i], SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK), |
| 20); |
| } |
| _pen_trackGCSweep(&ptest); |
| |
| /* Detach pens 0 and 2 */ |
| SDL_PenGCMark(); |
| for (i = 1; i < 4; i += 2) { |
| _pen_setDeviceinfo(_pen_register(ptest.ids[i], ptest.guids[i], names[i], SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK), |
| DEVICEINFO_UNCHANGED); |
| } |
| _pen_trackGCSweep(&ptest); |
| |
| for (i = 0; i < 4; ++i) { |
| SDLTest_AssertCheck(ptest.ids[i] == SDL_GetPenFromGUID(ptest.guids[i]), |
| "GUID search succeeded for %d", i); |
| } |
| |
| /* detach all */ |
| SDL_PenGCMark(); |
| _pen_trackGCSweep(&ptest); |
| |
| _teardown_test(&ptest, backup); |
| SDLTest_AssertPass("Pen ID lookup by GUID"); |
| |
| return TEST_COMPLETED; |
| } |
| |
| /** |
| * @brief Check pen device button reporting |
| * |
| */ |
| static int |
| pen_buttonReporting(void *arg) |
| { |
| int i; |
| int button_nr, pen_nr; |
| pen_testdata ptest; |
| SDL_Event event; |
| SDL_PenStatusInfo update; |
| float axes[SDL_PEN_NUM_AXES + 1]; |
| const float expected_x[2] = { 10.0f, 20.0f }; |
| const float expected_y[2] = { 11.0f, 21.0f }; |
| const Uint32 all_axes = SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_XTILT_MASK | SDL_PEN_AXIS_YTILT_MASK | SDL_PEN_AXIS_DISTANCE_MASK | SDL_PEN_AXIS_ROTATION_MASK | SDL_PEN_AXIS_SLIDER_MASK; |
| |
| /* Register pen */ |
| deviceinfo_backup *backup = _setup_test(&ptest, 2); |
| SDL_PenGCMark(); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[0], ptest.guids[0], "test pen", |
| SDL_PEN_INK_MASK | all_axes), |
| 20); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[1], ptest.guids[1], "test eraser", |
| SDL_PEN_ERASER_MASK | all_axes), |
| 24); |
| _pen_trackGCSweep(&ptest); |
| |
| /* Position mouse suitably before we start */ |
| for (i = 0; i <= SDL_PEN_NUM_AXES; ++i) { |
| axes[i] = 0.0625f * i; /* initialise with numbers that can be represented precisely in IEEE 754 and |
| are > 0.0f and <= 1.0f */ |
| } |
| |
| /* Let pens enter the test window */ |
| SDL_SendPenWindowEvent(0, ptest.ids[0], ptest.window); |
| SDL_SendPenWindowEvent(0, ptest.ids[1], ptest.window); |
| |
| update.x = expected_x[0]; |
| update.y = expected_y[0]; |
| SDL_memcpy(update.axes, axes, sizeof(float) * SDL_PEN_NUM_AXES); |
| SDL_SendPenMotion(0, ptest.ids[0], SDL_TRUE, &update); |
| update.x = expected_x[1]; |
| update.y = expected_y[1]; |
| SDL_memcpy(update.axes, axes + 1, sizeof(float) * SDL_PEN_NUM_AXES); |
| SDL_SendPenMotion(0, ptest.ids[1], SDL_TRUE, &update); |
| |
| while (SDL_PollEvent(&event)) |
| ; /* Flush event queue */ |
| |
| /* Trigger pen tip events for PEN_DOWN */ |
| SDLTest_AssertPass("Touch pens to surface"); |
| |
| for (pen_nr = 0; pen_nr < 2; ++pen_nr) { |
| float *expected_axes = axes + pen_nr; |
| SDL_bool found_event = SDL_FALSE; |
| Uint16 pen_state = 0x0000 | SDL_PEN_DOWN_MASK; |
| Uint8 tip = SDL_PEN_TIP_INK; |
| |
| if (pen_nr == 1) { |
| pen_state |= SDL_PEN_ERASER_MASK; |
| tip = SDL_PEN_TIP_ERASER; |
| } |
| |
| SDL_SendPenTipEvent(0, ptest.ids[pen_nr], SDL_PRESSED); |
| |
| while (SDL_PollEvent(&event)) { |
| if (event.type == SDL_EVENT_PEN_DOWN) { |
| SDLTest_AssertCheck(event.ptip.which == ptest.ids[pen_nr], |
| "Received SDL_EVENT_PEN_DOWN from correct pen"); |
| SDLTest_AssertCheck(event.ptip.tip == (pen_nr == 0)? SDL_PEN_TIP_INK : SDL_PEN_TIP_ERASER, |
| "Received SDL_EVENT_PEN_DOWN for correct tip"); |
| SDLTest_AssertCheck(event.ptip.state == SDL_PRESSED, |
| "Received SDL_EVENT_PEN_DOWN but and marked SDL_PRESSED"); |
| SDLTest_AssertCheck(event.ptip.tip == tip, |
| "Received tip %x but expected %x", event.ptip.tip, tip); |
| SDLTest_AssertCheck(event.ptip.pen_state == pen_state, |
| "Received SDL_EVENT_PEN_DOWN, and state %04x == %04x (expected)", |
| event.pbutton.pen_state, pen_state); |
| SDLTest_AssertCheck((event.ptip.x == expected_x[pen_nr]) && (event.ptip.y == expected_y[pen_nr]), |
| "Received SDL_EVENT_PEN_DOWN event at correct coordinates: (%f, %f) vs (%f, %f) (expected)", |
| event.pbutton.x, event.pbutton.y, expected_x[pen_nr], expected_y[pen_nr]); |
| SDLTest_AssertCheck(0 == SDL_memcmp(expected_axes, event.pbutton.axes, sizeof(float) * SDL_PEN_NUM_AXES), |
| "Received SDL_EVENT_PEN_DOWN event with correct axis values"); |
| found_event = SDL_TRUE; |
| } |
| SDLTest_AssertCheck(found_event, |
| "Received the expected SDL_EVENT_PEN_DOWN event"); |
| } |
| } |
| |
| SDLTest_AssertPass("Pen and eraser set up for button testing"); |
| |
| /* Actual tests start: pen, then eraser */ |
| for (pen_nr = 0; pen_nr < 2; ++pen_nr) { |
| Uint16 pen_state = 0x0000 | SDL_PEN_DOWN_MASK; |
| float *expected_axes = axes + pen_nr; |
| |
| if (pen_nr == 1) { |
| pen_state |= SDL_PEN_ERASER_MASK; |
| } |
| for (button_nr = 1; button_nr <= 8; ++button_nr) { |
| SDL_bool found_event = SDL_FALSE; |
| pen_state |= (1 << (button_nr - 1)); |
| |
| SDL_SendPenButton(0, ptest.ids[pen_nr], SDL_PRESSED, (Uint8)button_nr); |
| while (SDL_PollEvent(&event)) { |
| if (event.type == SDL_EVENT_PEN_BUTTON_DOWN) { |
| SDLTest_AssertCheck(event.pbutton.which == ptest.ids[pen_nr], |
| "Received SDL_EVENT_PEN_BUTTON_DOWN from correct pen"); |
| SDLTest_AssertCheck(event.pbutton.button == button_nr, |
| "Received SDL_EVENT_PEN_BUTTON_DOWN from correct button"); |
| SDLTest_AssertCheck(event.pbutton.state == SDL_PRESSED, |
| "Received SDL_EVENT_PEN_BUTTON_DOWN but and marked SDL_PRESSED"); |
| SDLTest_AssertCheck(event.pbutton.pen_state == pen_state, |
| "Received SDL_EVENT_PEN_BUTTON_DOWN, and state %04x == %04x (expected)", |
| event.pbutton.pen_state, pen_state); |
| SDLTest_AssertCheck((event.pbutton.x == expected_x[pen_nr]) && (event.pbutton.y == expected_y[pen_nr]), |
| "Received SDL_EVENT_PEN_BUTTON_DOWN event at correct coordinates: (%f, %f) vs (%f, %f) (expected)", |
| event.pbutton.x, event.pbutton.y, expected_x[pen_nr], expected_y[pen_nr]); |
| SDLTest_AssertCheck(0 == SDL_memcmp(expected_axes, event.pbutton.axes, sizeof(float) * SDL_PEN_NUM_AXES), |
| "Received SDL_EVENT_PEN_BUTTON_DOWN event with correct axis values"); |
| if (0 != SDL_memcmp(expected_axes, event.pbutton.axes, sizeof(float) * SDL_PEN_NUM_AXES)) { |
| int ax; |
| for (ax = 0; ax < SDL_PEN_NUM_AXES; ++ax) { |
| SDL_Log("\tax %d\t%.5f\t%.5f expected (equal=%d)", |
| ax, |
| event.pbutton.axes[ax], expected_axes[ax], |
| event.pbutton.axes[ax] == expected_axes[ax]); |
| } |
| } |
| found_event = SDL_TRUE; |
| } |
| } |
| SDLTest_AssertCheck(found_event, |
| "Received the expected SDL_EVENT_PEN_BUTTON_DOWN event"); |
| } |
| } |
| SDLTest_AssertPass("Pressed all buttons"); |
| |
| /* Release every other button */ |
| for (pen_nr = 0; pen_nr < 2; ++pen_nr) { |
| Uint16 pen_state = 0x00ff | SDL_PEN_DOWN_MASK; /* 8 buttons pressed */ |
| float *expected_axes = axes + pen_nr; |
| |
| if (pen_nr == 1) { |
| pen_state |= SDL_PEN_ERASER_MASK; |
| } |
| for (button_nr = pen_nr + 1; button_nr <= 8; button_nr += 2) { |
| SDL_bool found_event = SDL_FALSE; |
| pen_state &= ~(1 << (button_nr - 1)); |
| |
| SDL_SendPenButton(0, ptest.ids[pen_nr], SDL_RELEASED, (Uint8)button_nr); |
| while (SDL_PollEvent(&event)) { |
| if (event.type == SDL_EVENT_PEN_BUTTON_UP) { |
| SDLTest_AssertCheck(event.pbutton.which == ptest.ids[pen_nr], |
| "Received SDL_EVENT_PEN_BUTTON_UP from correct pen"); |
| SDLTest_AssertCheck(event.pbutton.button == button_nr, |
| "Received SDL_EVENT_PEN_BUTTON_UP from correct button"); |
| SDLTest_AssertCheck(event.pbutton.state == SDL_RELEASED, |
| "Received SDL_EVENT_PEN_BUTTON_UP and is marked SDL_RELEASED"); |
| SDLTest_AssertCheck(event.pbutton.pen_state == pen_state, |
| "Received SDL_EVENT_PEN_BUTTON_UP, and state %04x == %04x (expected)", |
| event.pbutton.pen_state, pen_state); |
| SDLTest_AssertCheck((event.pbutton.x == expected_x[pen_nr]) && (event.pbutton.y == expected_y[pen_nr]), |
| "Received SDL_EVENT_PEN_BUTTON_UP event at correct coordinates"); |
| SDLTest_AssertCheck(0 == SDL_memcmp(expected_axes, event.pbutton.axes, sizeof(float) * SDL_PEN_NUM_AXES), |
| "Received SDL_EVENT_PEN_BUTTON_UP event with correct axis values"); |
| found_event = SDL_TRUE; |
| } |
| } |
| SDLTest_AssertCheck(found_event, |
| "Received the expected SDL_EVENT_PEN_BUTTON_UP event"); |
| } |
| } |
| SDLTest_AssertPass("Released every other button"); |
| |
| /* Trigger pen tip events for PEN_UP */ |
| SDLTest_AssertPass("Remove pens from surface"); |
| |
| for (pen_nr = 0; pen_nr < 2; ++pen_nr) { |
| float *expected_axes = axes + pen_nr; |
| SDL_bool found_event = SDL_FALSE; |
| Uint16 pen_state = 0x0000; |
| Uint8 tip = SDL_PEN_TIP_INK; |
| |
| if (pen_nr == 1) { |
| pen_state |= SDL_PEN_ERASER_MASK; |
| tip = SDL_PEN_TIP_ERASER; |
| } |
| |
| SDL_SendPenTipEvent(0, ptest.ids[pen_nr], SDL_RELEASED); |
| |
| while (SDL_PollEvent(&event)) { |
| if (event.type == SDL_EVENT_PEN_UP) { |
| SDLTest_AssertCheck(event.ptip.which == ptest.ids[pen_nr], |
| "Received SDL_EVENT_PEN_UP from correct pen"); |
| SDLTest_AssertCheck(event.ptip.tip == (pen_nr == 0)? SDL_PEN_TIP_INK : SDL_PEN_TIP_ERASER, |
| "Received SDL_EVENT_PEN_UP for correct tip"); |
| SDLTest_AssertCheck(event.ptip.state == SDL_RELEASED, |
| "Received SDL_EVENT_PEN_UP but and marked SDL_RELEASED"); |
| SDLTest_AssertCheck(event.ptip.tip == tip, |
| "Received tip %x but expected %x", event.ptip.tip, tip); |
| SDLTest_AssertCheck((event.ptip.pen_state & 0xff00) == (pen_state & 0xff00), |
| "Received SDL_EVENT_PEN_UP, and state %04x == %04x (expected)", |
| event.pbutton.pen_state, pen_state); |
| SDLTest_AssertCheck((event.ptip.x == expected_x[pen_nr]) && (event.ptip.y == expected_y[pen_nr]), |
| "Received SDL_EVENT_PEN_UP event at correct coordinates: (%f, %f) vs (%f, %f) (expected)", |
| event.pbutton.x, event.pbutton.y, expected_x[pen_nr], expected_y[pen_nr]); |
| SDLTest_AssertCheck(0 == SDL_memcmp(expected_axes, event.pbutton.axes, sizeof(float) * SDL_PEN_NUM_AXES), |
| "Received SDL_EVENT_PEN_UP event with correct axis values"); |
| found_event = SDL_TRUE; |
| } |
| SDLTest_AssertCheck(found_event, |
| "Received the expected SDL_EVENT_PEN_UP event"); |
| } |
| } |
| |
| /* Cleanup */ |
| SDL_PenGCMark(); |
| _pen_trackGCSweep(&ptest); |
| _teardown_test(&ptest, backup); |
| |
| return TEST_COMPLETED; |
| } |
| |
| /** |
| * @brief Check pen device movement and axis update reporting |
| * |
| * Also tests SDL_GetPenStatus for agreement with the most recently reported events |
| * |
| * @sa SDL_GetPenStatus |
| */ |
| static int |
| pen_movementAndAxes(void *arg) |
| { |
| pen_testdata ptest; |
| SDL_Event event; |
| #define MAX_STEPS 80 |
| /* Pen simulation */ |
| simulated_pen_action steps[MAX_STEPS]; |
| size_t num_steps = 0; |
| |
| SDL_Pen simulated_pens[2]; |
| int sim_pc = 0; |
| simulated_pen_action *last_action; |
| |
| /* Register pen */ |
| deviceinfo_backup *backup = _setup_test(&ptest, 2); |
| |
| /* Pen simulation program */ |
| #define STEP steps[num_steps++] = |
| |
| /* #1: Check basic reporting */ |
| /* Hover eraser, tilt axes */ |
| SIMPEN_MOVE(0, 30.0f, 31.0f); |
| SIMPEN_AXIS(0, SDL_PEN_AXIS_PRESSURE, 0.0f); |
| SIMPEN_AXIS(0, SDL_PEN_AXIS_XTILT, 22.5f); |
| SIMPEN_AXIS(0, SDL_PEN_AXIS_YTILT, 45.0f); |
| SIMPEN_EVENT_MOTION(0); |
| |
| /* #2: Check that motion events without motion aren't reported */ |
| SIMPEN_EVENT_MOTION_SUPPRESSED(0); |
| SIMPEN_EVENT_MOTION_SUPPRESSED(0); |
| |
| /* #3: Check multiple pens being reported */ |
| /* Move pen and touch surface, don't tilt */ |
| SIMPEN_MOVE(1, 40.0f, 41.0f); |
| SIMPEN_AXIS(1, SDL_PEN_AXIS_PRESSURE, 0.25f); |
| SIMPEN_EVENT_MOTION(1); |
| |
| /* $4: Multi-buttons */ |
| /* Press eraser buttons */ |
| SIMPEN_EVENT_TIP(0, "down", SDL_PEN_TIP_ERASER); |
| SIMPEN_EVENT_BUTTON(0, "push", 2); |
| SIMPEN_EVENT_BUTTON(0, "push", 1); |
| SIMPEN_EVENT_BUTTON(0, 0, 2); /* release again */ |
| SIMPEN_EVENT_BUTTON(0, "push", 3); |
| |
| /* #5: Check move + button actions connecting */ |
| /* Move and tilt pen, press some pen buttons */ |
| SIMPEN_MOVE(1, 3.0f, 8.0f); |
| SIMPEN_AXIS(1, SDL_PEN_AXIS_PRESSURE, 0.5f); |
| SIMPEN_AXIS(1, SDL_PEN_AXIS_XTILT, -21.0f); |
| SIMPEN_AXIS(1, SDL_PEN_AXIS_YTILT, -25.0f); |
| SIMPEN_EVENT_MOTION(1); |
| SIMPEN_EVENT_BUTTON(1, "push", 2); |
| SIMPEN_EVENT_TIP(1, "down", SDL_PEN_TIP_INK); |
| |
| /* #6: Check nonterference between pens */ |
| /* Eraser releases buttons */ |
| SIMPEN_EVENT_BUTTON(0, 0, 1); |
| SIMPEN_EVENT_TIP(0, 0, SDL_PEN_TIP_ERASER); |
| |
| /* #7: Press-move-release action */ |
| /* Eraser press-move-release */ |
| SIMPEN_EVENT_BUTTON(0, "push", 1); |
| SIMPEN_MOVE(0, 99.0f, 88.0f); |
| SIMPEN_AXIS(0, SDL_PEN_AXIS_PRESSURE, 0.625f); |
| SIMPEN_EVENT_MOTION(0); |
| SIMPEN_MOVE(0, 44.5f, 42.25f); |
| SIMPEN_EVENT_MOTION(0); |
| SIMPEN_EVENT_BUTTON(0, 0, 1); |
| |
| /* #8: Intertwining button release actions some more */ |
| /* Pen releases button */ |
| SIMPEN_EVENT_BUTTON(1, 0, 2); |
| SIMPEN_EVENT_TIP(1, 0, SDL_PEN_TIP_INK); |
| |
| /* Push one more pen button, then release all ereaser buttons */ |
| SIMPEN_EVENT_TIP(1, "down", SDL_PEN_TIP_INK); |
| SIMPEN_EVENT_BUTTON(0, 0, 2); |
| SIMPEN_EVENT_BUTTON(0, 0, 3); |
| |
| /* Lift up pen, flip it so it becomes an eraser, and touch it again */ |
| SIMPEN_EVENT_TIP(1, 0, SDL_PEN_TIP_INK); |
| SIMPEN_SET_ERASER(1, 1); |
| SIMPEN_EVENT_TIP(1, "push", SDL_PEN_TIP_ERASER); |
| |
| /* And back again */ |
| SIMPEN_EVENT_TIP(1, 0, SDL_PEN_TIP_ERASER); |
| SIMPEN_SET_ERASER(1, 0); |
| SIMPEN_EVENT_TIP(1, "push", SDL_PEN_TIP_INK); |
| |
| /* #9: Suppress move on unsupported axis */ |
| SIMPEN_AXIS(1, SDL_PEN_AXIS_DISTANCE, 0.25f); |
| SIMPEN_EVENT_MOTION_SUPPRESSED(0); |
| |
| SIMPEN_DONE(); |
| #undef STEP |
| /* End of pen simulation program */ |
| |
| SDLTest_AssertCheck(num_steps < MAX_STEPS, "Pen simulation program does not exceed buffer size"); |
| #undef MAX_STEPS |
| |
| SDL_PenGCMark(); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[0], ptest.guids[0], "test eraser", |
| SDL_PEN_ERASER_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_XTILT_MASK | SDL_PEN_AXIS_YTILT_MASK), |
| 20); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[1], ptest.guids[1], "test pen", |
| SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_XTILT_MASK | SDL_PEN_AXIS_YTILT_MASK), |
| 24); |
| _pen_trackGCSweep(&ptest); |
| SDL_SendPenWindowEvent(0, ptest.ids[0], ptest.window); |
| SDL_SendPenWindowEvent(0, ptest.ids[1], ptest.window); |
| while (SDL_PollEvent(&event)) |
| ; /* Flush event queue */ |
| SDLTest_AssertPass("Pen and eraser set up for testing"); |
| |
| _pen_simulate_init(&ptest, simulated_pens, 2); |
| /* Simulate pen movements */ |
| while ((last_action = _pen_simulate(steps, &sim_pc, &simulated_pens[0], 2)) != 0) { |
| int attempts = 0; |
| SDL_Pen *simpen = &simulated_pens[last_action->pen_index]; |
| SDL_PenID reported_which = 0; |
| float reported_x = -1.0f, reported_y = -1.0f; |
| float *reported_axes = NULL; |
| Uint32 reported_pen_state = 0; |
| Uint32 expected_pen_state = simpen->header.flags & SDL_PEN_ERASER_MASK; |
| SDL_bool dump_pens = SDL_FALSE; |
| |
| do { |
| SDL_PumpEvents(); |
| SDL_PollEvent(&event); |
| if (++attempts > 10000) { |
| SDLTest_AssertCheck(0, "Never got the anticipated event"); |
| return TEST_ABORTED; |
| } |
| } while (event.type != SDL_EVENT_PEN_DOWN |
| && event.type != SDL_EVENT_PEN_UP |
| && event.type != SDL_EVENT_PEN_MOTION |
| && event.type != SDL_EVENT_PEN_BUTTON_UP |
| && event.type != SDL_EVENT_PEN_BUTTON_DOWN); /* skip boring events */ |
| |
| expected_pen_state |= simpen->last.buttons; |
| |
| SDLTest_AssertCheck(0 != event.type, |
| "Received the anticipated event"); |
| |
| switch (last_action->type) { |
| case SIMPEN_ACTION_MOTION_EVENT: |
| SDLTest_AssertCheck(event.type == SDL_EVENT_PEN_MOTION, "Expected pen motion event (but got 0x%lx)", (unsigned long) event.type); |
| reported_which = event.pmotion.which; |
| reported_x = event.pmotion.x; |
| reported_y = event.pmotion.y; |
| reported_pen_state = event.pmotion.pen_state; |
| reported_axes = &event.pmotion.axes[0]; |
| break; |
| |
| case SIMPEN_ACTION_PRESS: |
| SDLTest_AssertCheck(event.type == SDL_EVENT_PEN_BUTTON_DOWN, "Expected PENBUTTONDOWN event (but got 0x%lx)", (unsigned long) event.type); |
| SDLTest_AssertCheck(event.pbutton.state == SDL_PRESSED, "Expected PRESSED button"); |
| SDL_FALLTHROUGH; |
| case SIMPEN_ACTION_RELEASE: |
| if (last_action->type == SIMPEN_ACTION_RELEASE) { |
| SDLTest_AssertCheck(event.type == SDL_EVENT_PEN_BUTTON_UP, "Expected PENBUTTONUP event (but got 0x%lx)", (unsigned long) event.type); |
| SDLTest_AssertCheck(event.pbutton.state == SDL_RELEASED, "Expected RELEASED button"); |
| } |
| SDLTest_AssertCheck(event.pbutton.button == last_action->index, "Expected button %d, but got %d", |
| last_action->index, event.pbutton.button); |
| reported_which = event.pbutton.which; |
| reported_x = event.pbutton.x; |
| reported_y = event.pbutton.y; |
| reported_pen_state = event.pbutton.pen_state; |
| reported_axes = &event.pbutton.axes[0]; |
| break; |
| |
| case SIMPEN_ACTION_DOWN: |
| SDLTest_AssertCheck(event.type == SDL_EVENT_PEN_DOWN, "Expected PENBUTTONDOWN event (but got 0x%lx)", (unsigned long) event.type); |
| SDLTest_AssertCheck(event.ptip.state == SDL_PRESSED, "Expected PRESSED button"); |
| SDL_FALLTHROUGH; |
| case SIMPEN_ACTION_UP: |
| if (last_action->type == SIMPEN_ACTION_UP) { |
| SDLTest_AssertCheck(event.type == SDL_EVENT_PEN_UP, "Expected PENBUTTONUP event (but got 0x%lx)", (unsigned long) event.type); |
| SDLTest_AssertCheck(event.ptip.state == SDL_RELEASED, "Expected RELEASED button"); |
| } |
| SDLTest_AssertCheck(event.ptip.tip == last_action->index, "Expected tip %d, but got %d", |
| last_action->index, event.ptip.tip); |
| reported_which = event.ptip.which; |
| reported_x = event.ptip.x; |
| reported_y = event.ptip.y; |
| reported_pen_state = event.ptip.pen_state; |
| reported_axes = &event.ptip.axes[0]; |
| break; |
| |
| case SIMPEN_ACTION_ERASER_MODE: |
| break; |
| |
| default: |
| SDLTest_AssertCheck(0, "Error in pen simulator: unexpected action %d", last_action->type); |
| return TEST_ABORTED; |
| } |
| |
| if (reported_which != simpen->header.id) { |
| dump_pens = SDL_TRUE; |
| SDLTest_AssertCheck(0, "Expected report for pen %lu but got report for pen %lu", |
| (unsigned long) simpen->header.id, |
| (unsigned long) reported_which); |
| } |
| if (reported_x != simpen->last.x || reported_y != simpen->last.y) { |
| dump_pens = SDL_TRUE; |
| SDLTest_AssertCheck(0, "Mismatch in pen coordinates"); |
| } |
| if (reported_x != simpen->last.x || reported_y != simpen->last.y) { |
| dump_pens = SDL_TRUE; |
| SDLTest_AssertCheck(0, "Mismatch in pen coordinates"); |
| } |
| if (reported_pen_state != expected_pen_state) { |
| dump_pens = SDL_TRUE; |
| SDLTest_AssertCheck(0, "Mismatch in pen state: %lx vs %lx (expected)", |
| (unsigned long) reported_pen_state, |
| (unsigned long) expected_pen_state); |
| } |
| if (0 != SDL_memcmp(reported_axes, simpen->last.axes, sizeof(float) * SDL_PEN_NUM_AXES)) { |
| dump_pens = SDL_TRUE; |
| SDLTest_AssertCheck(0, "Mismatch in axes"); |
| } |
| |
| if (dump_pens) { |
| SDL_Log("----- Pen #%d:", last_action->pen_index); |
| _pen_dump("expect", simpen); |
| _pen_dump("actual", SDL_GetPenPtr(simpen->header.id)); |
| } |
| } |
| SDLTest_AssertPass("Pen and eraser move and report events correctly and independently"); |
| |
| /* Cleanup */ |
| SDL_PenGCMark(); |
| _pen_trackGCSweep(&ptest); |
| _teardown_test(&ptest, backup); |
| return TEST_COMPLETED; |
| } |
| |
| static void |
| _expect_pen_config(SDL_PenID penid, |
| SDL_GUID expected_guid, |
| SDL_bool expected_attached, |
| char *expected_name, |
| int expected_type, |
| int expected_num_buttons, |
| float expected_max_tilt, |
| int expected_axes) |
| { |
| SDL_PenCapabilityInfo actual_info = { 0 }; |
| const char *actual_name = SDL_GetPenName(penid); |
| |
| if (penid == SDL_PEN_INVALID) { |
| SDLTest_Assert(0, "Invalid pen ID"); |
| return; |
| } |
| |
| SDLTest_AssertEq1(int, "%d", 0, SDL_GUIDCompare(expected_guid, SDL_GetPenGUID(penid)), |
| "Pen %lu guid equality", (unsigned long) penid); |
| |
| SDLTest_AssertCheck(0 == SDL_strcmp(expected_name, actual_name), |
| "Expected name='%s' vs actual='%s'", expected_name, actual_name); |
| |
| SDLTest_AssertEq1(int, "%d", expected_attached, SDL_PenConnected(penid), |
| "Pen %lu is attached", (unsigned long) penid); |
| SDLTest_AssertEq1(int, "%d", expected_type, SDL_GetPenType(penid), |
| "Pen %lu type", (unsigned long) penid); |
| SDLTest_AssertEq1(int, "%x", expected_axes, SDL_GetPenCapabilities(penid, &actual_info), |
| "Pen %lu axis flags", (unsigned long) penid); |
| SDLTest_AssertEq1(int, "%d", expected_num_buttons, actual_info.num_buttons, |
| "Pen %lu number of buttons", (unsigned long) penid); |
| SDLTest_AssertEq1(float, "%f", expected_max_tilt, actual_info.max_tilt, |
| "Pen %lu max tilt", (unsigned long) penid); |
| } |
| |
| /** |
| * @brief Check backend pen iniitalisation and pen meta-information |
| * |
| * @sa SDL_GetPenCapabilities, SDL_PenAxisInfo |
| */ |
| static int |
| pen_initAndInfo(void *arg) |
| { |
| pen_testdata ptest; |
| SDL_Pen *pen; |
| Uint32 mask; |
| char strbuf[SDL_PEN_MAX_NAME]; |
| |
| /* Init */ |
| deviceinfo_backup *backup = _setup_test(&ptest, 7); |
| |
| /* Register default pen */ |
| _expect_pens_attached_or_detached(ptest.ids, 7, 0); |
| |
| /* Register completely default pen */ |
| pen = SDL_PenModifyBegin(ptest.ids[0]); |
| SDL_memcpy(pen->guid.data, ptest.guids[0].data, sizeof(ptest.guids[0].data)); |
| SDL_PenModifyEnd(pen, SDL_TRUE); |
| |
| SDL_snprintf(strbuf, sizeof(strbuf), |
| "Pen %lu", (unsigned long) ptest.ids[0]); |
| _expect_pen_config(ptest.ids[0], ptest.guids[0], SDL_TRUE, |
| strbuf, SDL_PEN_TYPE_PEN, SDL_PEN_INFO_UNKNOWN, 0.0f, |
| SDL_PEN_INK_MASK); |
| _expect_pens_attached_or_detached(ptest.ids, 7, ATTACHED(0)); |
| SDLTest_AssertPass("Pass #1: default pen"); |
| |
| /* Register mostly-default pen with buttons and custom name */ |
| pen = SDL_PenModifyBegin(ptest.ids[1]); |
| SDL_PenModifyAddCapabilities(pen, SDL_PEN_AXIS_PRESSURE_MASK); |
| SDL_memcpy(pen->guid.data, ptest.guids[1].data, sizeof(ptest.guids[1].data)); |
| SDL_strlcpy(strbuf, "My special test pen", SDL_PEN_MAX_NAME); |
| SDL_strlcpy(pen->name, strbuf, SDL_PEN_MAX_NAME); |
| pen->info.num_buttons = 7; |
| SDL_PenModifyEnd(pen, SDL_TRUE); |
| |
| _expect_pen_config(ptest.ids[1], ptest.guids[1], SDL_TRUE, |
| strbuf, SDL_PEN_TYPE_PEN, 7, 0.0f, |
| SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK); |
| _expect_pens_attached_or_detached(ptest.ids, 7, ATTACHED(0) | ATTACHED(1)); |
| SDLTest_AssertPass("Pass #2: default pen with button and name info"); |
| |
| /* Register eraser with default name, but keep initially detached */ |
| pen = SDL_PenModifyBegin(ptest.ids[2]); |
| SDL_memcpy(pen->guid.data, ptest.guids[2].data, sizeof(ptest.guids[2].data)); |
| pen->type = SDL_PEN_TYPE_ERASER; |
| SDL_PenModifyAddCapabilities(pen, SDL_PEN_AXIS_XTILT_MASK | SDL_PEN_AXIS_YTILT_MASK); |
| SDL_PenModifyEnd(pen, SDL_FALSE); |
| |
| SDL_snprintf(strbuf, sizeof(strbuf), |
| "Eraser %lu", (unsigned long) ptest.ids[2]); |
| _expect_pen_config(ptest.ids[2], ptest.guids[2], SDL_FALSE, |
| strbuf, SDL_PEN_TYPE_ERASER, SDL_PEN_INFO_UNKNOWN, SDL_PEN_INFO_UNKNOWN, |
| SDL_PEN_ERASER_MASK | SDL_PEN_AXIS_XTILT_MASK | SDL_PEN_AXIS_YTILT_MASK); |
| _expect_pens_attached_or_detached(ptest.ids, 7, ATTACHED(0) | ATTACHED(1)); |
| /* now make available */ |
| SDL_PenModifyEnd(SDL_PenModifyBegin(ptest.ids[2]), SDL_TRUE); |
| _expect_pen_config(ptest.ids[2], ptest.guids[2], SDL_TRUE, |
| strbuf, SDL_PEN_TYPE_ERASER, SDL_PEN_INFO_UNKNOWN, SDL_PEN_INFO_UNKNOWN, |
| SDL_PEN_ERASER_MASK | SDL_PEN_AXIS_XTILT_MASK | SDL_PEN_AXIS_YTILT_MASK); |
| _expect_pens_attached_or_detached(ptest.ids, 7, ATTACHED(0) | ATTACHED(1) | ATTACHED(2)); |
| SDLTest_AssertPass("Pass #3: eraser-type pen initially detached, then attached"); |
| |
| /* Abort pen registration */ |
| pen = SDL_PenModifyBegin(ptest.ids[3]); |
| SDL_memcpy(pen->guid.data, ptest.guids[3].data, sizeof(ptest.guids[3].data)); |
| SDL_PenModifyAddCapabilities(pen, SDL_PEN_AXIS_XTILT_MASK | SDL_PEN_AXIS_YTILT_MASK); |
| pen->type = SDL_PEN_TYPE_NONE; |
| SDL_PenModifyEnd(pen, SDL_TRUE); |
| _expect_pens_attached_or_detached(ptest.ids, 7, ATTACHED(0) | ATTACHED(1) | ATTACHED(2)); |
| SDLTest_AssertCheck(NULL == SDL_GetPenName(ptest.ids[3]), "Pen with aborted registration remains unknown"); |
| SDLTest_AssertPass("Pass #4: aborted pen registration"); |
| |
| /* Brush with custom axes */ |
| pen = SDL_PenModifyBegin(ptest.ids[4]); |
| SDL_memcpy(pen->guid.data, ptest.guids[4].data, sizeof(ptest.guids[4].data)); |
| SDL_strlcpy(pen->name, "Testish Brush", SDL_PEN_MAX_NAME); |
| pen->type = SDL_PEN_TYPE_BRUSH; |
| pen->info.num_buttons = 1; |
| SDL_PenModifyAddCapabilities(pen, SDL_PEN_AXIS_ROTATION_MASK); |
| pen->info.max_tilt = 72.5f; |
| SDL_PenModifyAddCapabilities(pen, SDL_PEN_AXIS_XTILT_MASK); |
| SDL_PenModifyAddCapabilities(pen, SDL_PEN_AXIS_PRESSURE_MASK); |
| SDL_PenModifyEnd(pen, SDL_TRUE); |
| _expect_pen_config(ptest.ids[4], ptest.guids[4], SDL_TRUE, |
| "Testish Brush", SDL_PEN_TYPE_BRUSH, 1, 72.5f, |
| SDL_PEN_INK_MASK | SDL_PEN_AXIS_XTILT_MASK | SDL_PEN_AXIS_ROTATION_MASK | SDL_PEN_AXIS_PRESSURE_MASK); |
| _expect_pens_attached_or_detached(ptest.ids, 7, ATTACHED(0) | ATTACHED(1) | ATTACHED(2) | ATTACHED(4)); |
| SDLTest_AssertPass("Pass #5: brush-type pen with unusual axis layout"); |
| |
| /* Wacom airbrush pen */ |
| { |
| const Uint32 wacom_type_id = 0x0912; |
| const Uint32 wacom_serial_id = 0xa0b1c2d3; |
| SDL_GUID guid = { |
| { 0, 0, 0, 0, |
| 0, 0, 0, 0, |
| 0, 0, 0, 0, |
| 0, 0, 0, 0 } |
| }; |
| guid.data[0] = (wacom_serial_id >> 0) & 0xff; |
| guid.data[1] = (wacom_serial_id >> 8) & 0xff; |
| guid.data[2] = (wacom_serial_id >> 16) & 0xff; |
| guid.data[3] = (wacom_serial_id >> 24) & 0xff; |
| guid.data[4] = (wacom_type_id >> 0) & 0xff; |
| guid.data[5] = (wacom_type_id >> 8) & 0xff; |
| guid.data[6] = (wacom_type_id >> 16) & 0xff; |
| guid.data[7] = (wacom_type_id >> 24) & 0xff; |
| |
| pen = SDL_PenModifyBegin(ptest.ids[5]); |
| SDL_PenModifyForWacomID(pen, wacom_type_id, &mask); |
| SDL_PenUpdateGUIDForWacom(&pen->guid, wacom_type_id, wacom_serial_id); |
| SDL_PenModifyAddCapabilities(pen, mask); |
| SDL_PenModifyEnd(pen, SDL_TRUE); |
| _expect_pen_config(ptest.ids[5], guid, SDL_TRUE, |
| "Wacom Airbrush Pen", SDL_PEN_TYPE_AIRBRUSH, 1, 64.0f, /* Max tilt angle */ |
| SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_XTILT_MASK | SDL_PEN_AXIS_YTILT_MASK | SDL_PEN_AXIS_DISTANCE_MASK | SDL_PEN_AXIS_SLIDER_MASK); |
| _expect_pens_attached_or_detached(ptest.ids, 7, ATTACHED(0) | ATTACHED(1) | ATTACHED(2) | ATTACHED(4) | ATTACHED(5)); |
| } |
| SDLTest_AssertPass("Pass #6: wacom airbrush pen"); |
| |
| /* Cleanup */ |
| SDL_PenGCMark(); |
| _pen_trackGCSweep(&ptest); |
| _teardown_test(&ptest, backup); |
| return TEST_COMPLETED; |
| } |
| |
| #define SET_POS(update, xpos, ypos) \ |
| (update).x = (xpos); \ |
| (update).y = (ypos); |
| |
| static void |
| _penmouse_expect_button(int type, int button) |
| { |
| SDL_bool press = type == SDL_PRESSED; |
| SDLTest_AssertCheck((press ? SDL_EVENT_MOUSE_BUTTON_DOWN : SDL_EVENT_MOUSE_BUTTON_UP) == _mouseemu_last_event, |
| "Mouse button %s: %x", |
| (press ? "press" : "release"), _mouseemu_last_event); |
| SDLTest_AssertCheck(button == _mouseemu_last_button, |
| "Observed the expected simulated button: %d", _mouseemu_last_button); |
| SDLTest_AssertCheck(SDL_PEN_MOUSEID == _mouseemu_last_mouseid, |
| "Observed the expected mouse ID: 0x%x", _mouseemu_last_mouseid); |
| |
| _mouseemu_last_event = 0; |
| } |
| |
| /** |
| * @brief Check pen device mouse emulation and event suppression without SDL_HINT_PEN_DELAY_MOUSE_BUTTON |
| * |
| * Since we include SDL_pen.c, we link it against our own mock implementations of SDL_PSendMouseButton |
| * and SDL_SendMouseMotion; see tehere for details. |
| */ |
| static int |
| pen_mouseEmulation(void *arg) |
| { |
| pen_testdata ptest; |
| SDL_Event event; |
| int i; |
| SDL_PenStatusInfo update; |
| deviceinfo_backup *backup; |
| |
| pen_delay_mouse_button_mode = 0; |
| pen_mouse_emulation_mode = PEN_MOUSE_EMULATE; /* to trigger our own SDL_SendMouseButton */ |
| |
| /* Register pen */ |
| backup = _setup_test(&ptest, 1); |
| SDL_PenGCMark(); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[0], ptest.guids[0], "testpen", |
| SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_XTILT | SDL_PEN_AXIS_YTILT), |
| 20); |
| _pen_trackGCSweep(&ptest); |
| |
| /* Move pen into window */ |
| SDL_SendPenWindowEvent(0, ptest.ids[0], ptest.window); |
| |
| /* Initialise pen location */ |
| SDL_memset(update.axes, 0, sizeof(update.axes)); |
| SET_POS(update, 100.0f, 100.0f); |
| SDL_SendPenMotion(0, ptest.ids[0], SDL_TRUE, &update); |
| while (SDL_PollEvent(&event)) |
| ; /* Flush event queue */ |
| |
| /* Test motion forwarding */ |
| _mouseemu_last_event = 0; |
| SET_POS(update, 121.25f, 110.75f); |
| SDL_SendPenMotion(0, ptest.ids[0], SDL_TRUE, &update); |
| SDLTest_AssertCheck(SDL_EVENT_MOUSE_MOTION == _mouseemu_last_event, |
| "Mouse motion event: %d", _mouseemu_last_event); |
| SDLTest_AssertCheck(121.25f == _mouseemu_last_x && 110.75f == _mouseemu_last_y, |
| "Motion to correct position: %f,%f", _mouseemu_last_x, _mouseemu_last_y); |
| SDLTest_AssertCheck(SDL_PEN_MOUSEID == _mouseemu_last_mouseid, |
| "Observed the expected mouse ID: 0x%x", _mouseemu_last_mouseid); |
| SDLTest_AssertCheck(0 == _mouseemu_last_relative, |
| "Absolute motion event"); |
| SDLTest_AssertPass("Motion emulation"); |
| |
| /* Test redundant motion report suppression */ |
| _mouseemu_last_event = 0; |
| |
| SET_POS(update, 121.25f, 110.75f); |
| SDL_SendPenMotion(0, ptest.ids[0], SDL_TRUE, &update); |
| |
| SET_POS(update, 121.25f, 110.75f); |
| SDL_SendPenMotion(0, ptest.ids[0], SDL_TRUE, &update); |
| |
| update.axes[0] = 1.0f; |
| SDL_SendPenMotion(0, ptest.ids[0], SDL_TRUE, &update); |
| |
| SET_POS(update, 121.25f, 110.75f); |
| update.axes[0] = 0.0f; |
| update.axes[1] = 0.75f; |
| SDL_SendPenMotion(0, ptest.ids[0], SDL_TRUE, &update); |
| |
| SDLTest_AssertCheck(0 == _mouseemu_last_event, |
| "Redundant mouse motion suppressed: %d", _mouseemu_last_event); |
| SDLTest_AssertPass("Redundant motion suppression"); |
| |
| /* Test button press reporting */ |
| SDL_SendPenTipEvent(0, ptest.ids[0], SDL_PRESSED); |
| _penmouse_expect_button(SDL_PRESSED, 1); |
| |
| for (i = 1; i <= 3; ++i) { |
| SDL_SendPenButton(0, ptest.ids[0], SDL_PRESSED, (Uint8)i); |
| _penmouse_expect_button(SDL_PRESSED, i + 1); |
| } |
| SDLTest_AssertPass("Button press mouse emulation"); |
| |
| /* Test button release reporting */ |
| SDL_SendPenTipEvent(0, ptest.ids[0], SDL_RELEASED); |
| _penmouse_expect_button(SDL_RELEASED, 1); |
| |
| for (i = 1; i <= 3; ++i) { |
| SDL_SendPenButton(0, ptest.ids[0], SDL_RELEASED, (Uint8)i); |
| _penmouse_expect_button(SDL_RELEASED, i + 1); |
| } |
| SDLTest_AssertPass("Button release mouse emulation"); |
| |
| /* Cleanup */ |
| SDL_PenGCMark(); |
| _pen_trackGCSweep(&ptest); |
| _teardown_test(&ptest, backup); |
| return TEST_COMPLETED; |
| } |
| |
| /** |
| * @brief Check pen device mouse emulation when SDL_HINT_PEN_DELAY_MOUSE_BUTTON is enabled (default) |
| */ |
| static int |
| pen_mouseEmulationDelayed(void *arg) |
| { |
| pen_testdata ptest; |
| SDL_Event event; |
| int i; |
| SDL_PenStatusInfo update; |
| deviceinfo_backup *backup; |
| |
| pen_delay_mouse_button_mode = 1; |
| pen_mouse_emulation_mode = PEN_MOUSE_EMULATE; /* to trigger our own SDL_SendMouseButton */ |
| |
| /* Register pen */ |
| backup = _setup_test(&ptest, 1); |
| SDL_PenGCMark(); |
| _pen_setDeviceinfo(_pen_register(ptest.ids[0], ptest.guids[0], "testpen", |
| SDL_PEN_INK_MASK | SDL_PEN_AXIS_PRESSURE_MASK | SDL_PEN_AXIS_XTILT | SDL_PEN_AXIS_YTILT), |
| 20); |
| _pen_trackGCSweep(&ptest); |
| |
| /* Move pen into window */ |
| SDL_SendPenWindowEvent(0, ptest.ids[0], ptest.window); |
| |
| /* Initialise pen location */ |
| SDL_memset(update.axes, 0, sizeof(update.axes)); |
| SET_POS(update, 100.0f, 100.0f); |
| SDL_SendPenMotion(0, ptest.ids[0], SDL_TRUE, &update); |
| while (SDL_PollEvent(&event)) |
| ; /* Flush event queue */ |
| |
| /* Test motion forwarding */ |
| _mouseemu_last_event = 0; |
| SET_POS(update, 121.25f, 110.75f); |
| SDL_SendPenMotion(0, ptest.ids[0], SDL_TRUE, &update); |
| SDLTest_AssertCheck(SDL_EVENT_MOUSE_MOTION == _mouseemu_last_event, |
| "Mouse motion event: %d", _mouseemu_last_event); |
| SDLTest_AssertCheck(121.25f == _mouseemu_last_x && 110.75f == _mouseemu_last_y, |
| "Motion to correct position: %f,%f", _mouseemu_last_x, _mouseemu_last_y); |
| SDLTest_AssertCheck(SDL_PEN_MOUSEID == _mouseemu_last_mouseid, |
| "Observed the expected mouse ID: 0x%x", _mouseemu_last_mouseid); |
| SDLTest_AssertCheck(0 == _mouseemu_last_relative, |
| "Absolute motion event"); |
| SDLTest_AssertPass("Motion emulation"); |
| _mouseemu_last_event = 0; |
| |
| /* Test button press reporting */ |
| for (i = 1; i <= 2; ++i) { |
| SDL_SendPenButton(0, ptest.ids[0], SDL_PRESSED, (Uint8)i); |
| SDLTest_AssertCheck(0 == _mouseemu_last_event, |
| "Non-touching button press suppressed: %d", _mouseemu_last_event); |
| SDL_SendPenButton(0, ptest.ids[0], SDL_RELEASED, (Uint8)i); |
| SDLTest_AssertCheck(0 == _mouseemu_last_event, |
| "Non-touching button release suppressed: %d", _mouseemu_last_event); |
| } |
| |
| /* Touch surface */ |
| SDL_SendPenTipEvent(0, ptest.ids[0], SDL_PRESSED); |
| _penmouse_expect_button(SDL_PRESSED, 1); |
| SDL_SendPenTipEvent(0, ptest.ids[0], SDL_RELEASED); |
| _penmouse_expect_button(SDL_RELEASED, 1); |
| |
| /* Test button press reporting, releasing extra button AFTER lifting pen */ |
| for (i = 1; i <= 2; ++i) { |
| SDL_SendPenButton(0, ptest.ids[0], SDL_PRESSED, (Uint8)i); |
| SDLTest_AssertCheck(0 == _mouseemu_last_event, |
| "Non-touching button press suppressed (A.1): %d", _mouseemu_last_event); |
| SDL_SendPenTipEvent(0, ptest.ids[0], SDL_PRESSED); |
| _penmouse_expect_button(SDL_PRESSED, i + 1); |
| |
| SDL_SendPenTipEvent(0, ptest.ids[0], SDL_RELEASED); |
| _penmouse_expect_button(SDL_RELEASED, i + 1); |
| |
| SDL_SendPenButton(0, ptest.ids[0], SDL_RELEASED, (Uint8)i); |
| SDLTest_AssertCheck(0 == _mouseemu_last_event, |
| "Non-touching button press suppressed (A.2): %d", _mouseemu_last_event); |
| } |
| SDLTest_AssertPass("Delayed button press mouse emulation, touching without releasing button"); |
| |
| /* Test button press reporting, releasing extra button BEFORE lifting pen */ |
| for (i = 1; i <= 2; ++i) { |
| SDL_SendPenButton(0, ptest.ids[0], SDL_PRESSED, (Uint8)i); |
| SDLTest_AssertCheck(0 == _mouseemu_last_event, |
| "Non-touching button press suppressed (B.1): %d", _mouseemu_last_event); |
| SDL_SendPenTipEvent(0, ptest.ids[0], SDL_PRESSED); |
| _penmouse_expect_button(SDL_PRESSED, i + 1); |
| |
| SDL_SendPenButton(0, ptest.ids[0], SDL_RELEASED, (Uint8)i); |
| SDLTest_AssertCheck(0 == _mouseemu_last_event, |
| "Non-touching button press suppressed (B.2): %d", _mouseemu_last_event); |
| SDL_SendPenTipEvent(0, ptest.ids[0], SDL_RELEASED); |
| _penmouse_expect_button(SDL_RELEASED, i + 1); |
| } |
| SDLTest_AssertPass("Delayed button press mouse emulation, touching and then releasing button"); |
| |
| /* Cleanup */ |
| SDL_PenGCMark(); |
| _pen_trackGCSweep(&ptest); |
| _teardown_test(&ptest, backup); |
| return TEST_COMPLETED; |
| } |
| |
| /** |
| * @brief Ensure that all SDL_Pen*Event structures have compatible memory layout, as expected by SDL_pen.c |
| */ |
| static int |
| pen_memoryLayout(void *arg) |
| { |
| #define LAYOUT_COMPATIBLE(field) \ |
| SDLTest_AssertCheck(offsetof(SDL_PenTipEvent, field) == offsetof(SDL_PenMotionEvent, field), \ |
| "Memory layout SDL_PenTipEvent and SDL_PenMotionEvent compatibility: '" #field "'"); \ |
| SDLTest_AssertCheck(offsetof(SDL_PenTipEvent, field) == offsetof(SDL_PenButtonEvent, field), \ |
| "Memory layout SDL_PenTipEvent and SDL_PenBUttonEvent compatibility: '" #field "'"); |
| |
| LAYOUT_COMPATIBLE(which); |
| LAYOUT_COMPATIBLE(x); |
| LAYOUT_COMPATIBLE(y); |
| LAYOUT_COMPATIBLE(axes); |
| |
| return TEST_COMPLETED; |
| } |
| |
| /* ================= Test Setup and Teardown ================== */ |
| |
| static void |
| pen_test_setup(void *arg) { |
| SDL_PenInit(); |
| } |
| |
| static void |
| pen_test_teardown(void *arg) { |
| SDL_PenQuit(); |
| } |
| |
| /* ================= Test References ================== */ |
| |
| /* Pen test cases */ |
| static const SDLTest_TestCaseReference penTest1 = { (SDLTest_TestCaseFp)pen_iteration, "pen_iteration", "Iterate over all pens with SDL_PenIDForIndex", TEST_ENABLED }; |
| |
| static const SDLTest_TestCaseReference penTest2 = { (SDLTest_TestCaseFp)pen_hotplugging, "pen_hotplugging", "Hotplug pens and validate their status, including SDL_PenConnected", TEST_ENABLED }; |
| |
| static const SDLTest_TestCaseReference penTest3 = { (SDLTest_TestCaseFp)pen_GUIDs, "pen_GUIDs", "Check Pen SDL_GUID operations", TEST_ENABLED }; |
| |
| static const SDLTest_TestCaseReference penTest4 = { (SDLTest_TestCaseFp)pen_buttonReporting, "pen_buttonReporting", "Check pen button presses", TEST_ENABLED }; |
| |
| static const SDLTest_TestCaseReference penTest5 = { (SDLTest_TestCaseFp)pen_movementAndAxes, "pen_movementAndAxes", "Check pen movement and axis update reporting", TEST_ENABLED }; |
| |
| static const SDLTest_TestCaseReference penTest6 = { (SDLTest_TestCaseFp)pen_initAndInfo, "pen_info", "Check pen self-description and initialisation", TEST_ENABLED }; |
| |
| static const SDLTest_TestCaseReference penTest7 = { (SDLTest_TestCaseFp)pen_mouseEmulation, "pen_mouseEmulation", "Check pen-as-mouse event forwarding (direct)", TEST_ENABLED }; |
| |
| static const SDLTest_TestCaseReference penTest8 = { (SDLTest_TestCaseFp)pen_mouseEmulationDelayed, "pen_mouseEmulationDelayed", "Check pen-as-mouse event forwarding (delayed)", TEST_ENABLED }; |
| |
| static const SDLTest_TestCaseReference penTest9 = { (SDLTest_TestCaseFp)pen_memoryLayout, "pen_memoryLayout", "Check that all pen events have compatible layout (required by SDL_pen.c)", TEST_ENABLED }; |
| |
| /* Sequence of Pen test cases */ |
| static const SDLTest_TestCaseReference *penTests[] = { |
| &penTest1, &penTest2, &penTest3, &penTest4, &penTest5, &penTest6, &penTest7, &penTest8, &penTest9, NULL |
| }; |
| |
| /* Pen test suite (global) */ |
| SDLTest_TestSuiteReference penTestSuite = { |
| "Pen", |
| (SDLTest_TestCaseSetUpFp)pen_test_setup, |
| penTests, |
| (SDLTest_TestCaseTearDownFp)pen_test_teardown |
| }; |
| |
| #else |
| |
| #include <SDL3/SDL_test.h> |
| #include "testautomation_suites.h" |
| |
| /* Sequence of Mouse test cases */ |
| static const SDLTest_TestCaseReference *penTests[] = { |
| NULL |
| }; |
| |
| /* Mouse test suite (global) */ |
| SDLTest_TestSuiteReference penTestSuite = { |
| "Pen", |
| NULL, |
| penTests, |
| NULL |
| }; |
| |
| #endif |