View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0012636 | Dwarf Fortress | Technical -- Input/Keybinding/Macros | public | 2023-12-06 14:26 | 2024-11-12 15:48 |
Reporter | Konig | Assigned To | |||
Priority | normal | Severity | minor | Reproducibility | always |
Status | new | Resolution | open | ||
Platform | Steam | OS | Windows | OS Version | 11 |
Product Version | 50.11 | ||||
Summary | 0012636: Strange behaviour of lists when scrolling down with ThinkPad touchpad gesture | ||||
Description | On a brand-new ThinkPad laptop, when I "two-finger swipe" up on the touchpad (a normal scroll movement) it scrolls up menus/lists in DF fine, but when I swipe down it kind of scrolls down but then scrolls up a bit. This is on default keybindings. | ||||
Steps To Reproduce | 1) Get a ThinkPad laptop 2) Download DF 3) Launch DF 4) Try to scroll down on a menu with the touchpad | ||||
Additional Information | 1) Swipe speed affects it - if I swipe down slow, the up-movement is more pronounced, to such an extent that I'll often end up higher in the list than where I started if I go real slow, and if I swipe down fast it's just a little tick back up at the end of the scroll movement. 2) The touchpad scrolls as normal in all other programs. Changing the scroll behaviour in Windows (so that swiping down scrolls me up instead, like a Macbook) doesn't change the behaviour in DF; scrolling up in a menu (by swiping down now) behaves as normal, and scrolling down has the janky movement. 3) Plugging in a traditional mouse solves the problem - menus scroll as normal. 4) Reversing the DF keybindings for anything default bound to Mwheel Down/Up seems to have the effect of disabling scrolling down in DF menus entirely (again, just the "mouse wheel scroll down" DF input seems to be affected, whether I'm swiping down for scroll down or swiping up for scroll down at the OS-level). 5) Rebinding scrolling to anything else (e.g. 1 and 2) fixes the problem and I can scroll up or down menus like normal. It only happens with Mwheel Down. 6) This bug happens in both the main menu options and in fortress mode - so probably everywhere. 7) Windowed/Fullscreen has no effect. 8) Locking Graphical FPS to something lower (tried 30) doesn't seem to have an effect. System Specs ThinkPad E14 Gen 5 Intel Processor: 13th Gen Intel Core i5-1335U 1.30 GHz RAM: 16GB Graphics: Integrated Intel Iris Xe Graphics OS: Windows 11 Home 64 | ||||
Tags | interface, menu, mouse | ||||
|
Looks like this might be related to/the same as another bug https://dwarffortressbugtracker.com/view.php?id=12635 |
|
I can reproduce this bug on my MX Master 3 mouse on Linux. I suspect this has something to do with hi-resolution scrolling, and the bug here is how dwarf fortress handles scroll events. Here's some code to show what's going on: ``` #include <SDL2/SDL.h> #include <iostream> int main(int argc, char* argv[]) { if (SDL_Init(SDL_INIT_VIDEO) != 0) { std::cerr << "SDL_Init Error: " << SDL_GetError() << std::endl; return 1; } std::cout << "SDL initialized successfully." << std::endl; SDL_Window* window = SDL_CreateWindow("Mouse Scroll Logger", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN); if (window == nullptr) { std::cerr << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl; SDL_Quit(); return 1; } SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (renderer == nullptr) { std::cerr << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl; SDL_DestroyWindow(window); SDL_Quit(); return 1; } SDL_Event event; bool running = true; int scrollPosition = 0; while (running) { while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { running = false; } else if (event.type == SDL_MOUSEWHEEL) { scrollPosition += event.wheel.y; std::cout << "Mouse Scroll: " << (event.wheel.y > 0 ? "Up" : event.wheel.x < 0 ? "Dn" : "00") << ", Position: " << scrollPosition << std::endl; } } SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255); SDL_RenderClear(renderer); SDL_RenderPresent(renderer); } SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; } ``` And here's how I reproduced it on Linux. After starting the program, I only scrolled up: ``` $ g++ -o mouse_scroll_logger main.cpp $(sdl2-config --cflags --libs) $ ./mouse_scroll_logger SDL initialized successfully. Mouse Scroll: 00, Position: 0 Mouse Scroll: 00, Position: 0 Mouse Scroll: Up, Position: 1 Mouse Scroll: 00, Position: 1 Mouse Scroll: Up, Position: 2 Mouse Scroll: 00, Position: 2 Mouse Scroll: Up, Position: 3 Mouse Scroll: 00, Position: 3 Mouse Scroll: Up, Position: 4 Mouse Scroll: 00, Position: 4 Mouse Scroll: Up, Position: 5 Mouse Scroll: 00, Position: 5 Mouse Scroll: 00, Position: 5 Mouse Scroll: Up, Position: 6 Mouse Scroll: 00, Position: 6 Mouse Scroll: Up, Position: 7 Mouse Scroll: 00, Position: 7 Mouse Scroll: 00, Position: 7 Mouse Scroll: 00, Position: 7 Mouse Scroll: Up, Position: 8 ``` Note the number of "00" events. These are printed when event.wheel.x == 0. I suspect what's going on is that Dwarf Fortress has buggy code that looks like this: ``` void onScrollEvent(event) { if event.wheel.x > 0 { scrollUp() } else { scrollDown() } } ``` This code needs to be changed to something like this to handle scroll events where the wheel position change is not 1: ``` void onScrollEvent(event) { if event.wheel.x > 0 { for(int i = 0; i < event.wheel.x; i++) { scrollUp() } } else { for(int i = 0; i > event.wheel.x; i--) { scrollDown() } } } ``` If it makes the developers feel better, the first version of my test program had the exact same bug :) |
|
1. every time I said `wheel.x` in the above comment, I should have said `wheel.y`. 2. The following LD_PRELOAD patch fixes the bug on linux: ``` #include <SDL2/SDL.h> #include <dlfcn.h> #include <stdio.h> // Function pointer to hold the original SDL_PollEvent int (*original_SDL_PollEvent)(SDL_Event *) = NULL; // Function to print event details in a human-readable format void print_event(SDL_Event *event) { switch (event->type) { case SDL_QUIT: printf("Event: SDL_QUIT\n"); break; case SDL_KEYDOWN: printf("Event: SDL_KEYDOWN, Key: %s\n", SDL_GetKeyName(event->key.keysym.sym)); break; case SDL_KEYUP: printf("Event: SDL_KEYUP, Key: %s\n", SDL_GetKeyName(event->key.keysym.sym)); break; case SDL_MOUSEBUTTONDOWN: printf("Event: SDL_MOUSEBUTTONDOWN, Button: %d\n", event->button.button); break; case SDL_MOUSEBUTTONUP: printf("Event: SDL_MOUSEBUTTONUP, Button: %d\n", event->button.button); break; case SDL_MOUSEMOTION: printf("Event: SDL_MOUSEMOTION, X: %d, Y: %d, Xrel: %d, Yrel: %d\n", event->motion.x, event->motion.y, event->motion.xrel, event->motion.yrel); break; case SDL_MOUSEWHEEL: printf("Event: SDL_MOUSEWHEEL, X: %d, Y: %d, Direction: %d\n", event->wheel.x, event->wheel.y, event->wheel.direction); break; case SDL_WINDOWEVENT: printf("Event: SDL_WINDOWEVENT, WindowEvent: %d\n", event->window.event); break; case SDL_SYSWMEVENT: printf("Event: SDL_SYSWMEVENT\n"); break; case SDL_TEXTEDITING: printf("Event: SDL_TEXTEDITING, Text: %s, Start: %d, Length: %d\n", event->edit.text, event->edit.start, event->edit.length); break; case SDL_USEREVENT: printf("Event: SDL_USEREVENT, Code: %d\n", event->user.code); break; default: printf("Event: %d (unknown)\n", event->type); break; } } // Our replacement for SDL_PollEvent int SDL_PollEvent(SDL_Event *event) { if (!original_SDL_PollEvent) { // Get the original SDL_PollEvent function original_SDL_PollEvent = dlsym(RTLD_NEXT, "SDL_PollEvent"); if (!original_SDL_PollEvent) { fprintf(stderr, "Error: could not find original SDL_PollEvent\n"); return 0; } else { printf("Successfully hooked SDL_PollEvent.\n"); } } // Call the original SDL_PollEvent int result = original_SDL_PollEvent(event); if (result == 0) { return result; } // Print the event details // print_event(event); if (event->type == SDL_MOUSEWHEEL && event->wheel.y == 0) { return SDL_PollEvent(event); // Recursively call to get the next event } // Return the event if it's not ignored return result; } ``` compile with `gcc -fPIC -shared -o sdl_patch.so sdl_patch.c -ldl -lSDL2`, copy to the `~/.local/share/Steam/steamapps/common/Dwarf Fortress` folder, and run using `LD_PRELOAD=./sdl_patch.so ./dwarfort` |
|
Having this issue on a Macbook with Crossover, is there a fix for Windows? |
Date Modified | Username | Field | Change |
---|---|---|---|
2023-12-06 14:26 | Konig | New Issue | |
2023-12-06 14:26 | Konig | Tag Attached: interface | |
2023-12-06 14:26 | Konig | Tag Attached: menu | |
2023-12-06 14:26 | Konig | Tag Attached: mouse | |
2023-12-06 14:31 | Konig | Note Added: 0041943 | |
2024-05-20 11:55 | safflower | Note Added: 0042239 | |
2024-05-20 12:38 | safflower | Note Added: 0042240 | |
2024-11-12 15:47 | protobirth | Note Added: 0042424 |