[win] Fix sync between mouse cursor <-> stylus cursor (fix #4539)

Added a new option (enabled by default) to set the mouse cursor when a
pen/pointer message is received. This fixes a couple of issues:

1) When we zoom in/out with keys or scrolling the trackpad, the last
   known position will be used (the pen position if we are using the
   pen).

2) If we are recording the stream/live streaming with a software like
   OBS Studio, the cursor position will correctly be in the pen
   position if we're painting with the pen.
This commit is contained in:
David Capello 2024-06-18 13:44:19 -03:00
parent 2827618786
commit f29ec83c6c
6 changed files with 60 additions and 78 deletions

View File

@ -230,6 +230,7 @@
</section>
<section id="tablet" text="Tablet">
<option id="api" type="std::string" />
<option id="set_cursor_fix" type="bool" default="true" />
</section>
<section id="experimental" text="Experimental">
<option id="multiple_windows" type="bool" default="false" />

View File

@ -1504,10 +1504,11 @@ native_file_dialog = Use native file dialog
shaders_for_color_selectors = Use shaders for color selectors
hue_with_sat_value = Apply Saturation/Value to Hue slider on Tint/Shade/Tone selector
cache_compressed_tilesets = Cache compressed tilesets for faster save (uses more memory)
windows_pointer = Windows Pointer options
one_finger_as_mouse_movement = Interpret one finger as mouse movement
one_finger_as_mouse_movement_tooltip = Only for Windows 8/10 Pointer API: Interprets one finger as mouse movement\nand two fingers as pan/scroll. Uncheck this to use the old behavior:\nOne finger pans/scrolls
load_wintab_driver = Load wintab32 library
load_wintab_driver_tooltip = Loads wintab32.dll driver to use Wacom-like devices\nwhen Aseprite is started
one_finger_as_mouse_movement_tooltip = Interprets one finger as mouse movement and two fingers as pan/scroll.\nUncheck this to use the old behavior: one finger pans/scrolls
set_cursor_fix = Set cursor position from stylus location
set_cursor_fix_tooltip = Sets the mouse position to the pen location when\nyou have two pointers available (e.g. mouse and pen)\n\nUseful to zoom in/out from the pen position and to get the\ncorrect cursor location when screencasting/live streaming.
wintab_more_info = (More Information)
flash_selected_layer = Flash layer when it is selected
non_active_layer_opacity = Opacity for non-active layers:

View File

@ -95,19 +95,25 @@
<vbox id="section_tablet">
<separator text="@.section_tablet" horizontal="true" />
<radio id="tablet_api_windows_pointer" text="@.tablet_api_windows_pointer" group="1" />
<radio id="tablet_api_wintab_system" text="@.tablet_api_wintab_system" group="1" />
<radio id="tablet_api_wintab_direct" text="@.tablet_api_wintab_direct" group="1" />
<separator horizontal="true" />
<check id="one_finger_as_mouse_movement"
text="@.one_finger_as_mouse_movement"
tooltip="@.one_finger_as_mouse_movement_tooltip"
pref="experimental.one_finger_as_mouse_movement" />
<hbox>
<check id="load_wintab_driver"
text="@.load_wintab_driver"
tooltip="@.load_wintab_driver_tooltip" />
<radio id="tablet_api_wintab_system" text="@.tablet_api_wintab_system" group="1" />
<link text="@.wintab_more_info" url="https://www.aseprite.org/docs/wintab/" />
</hbox>
<radio id="tablet_api_wintab_direct" text="@.tablet_api_wintab_direct" group="1" />
<vbox id="windows_pointer_options">
<separator text="@.windows_pointer" horizontal="true" />
<check id="one_finger_as_mouse_movement"
text="@.one_finger_as_mouse_movement"
tooltip="@.one_finger_as_mouse_movement_tooltip"
pref="experimental.one_finger_as_mouse_movement" />
<hbox>
<check id="set_cursor_fix"
text="@.set_cursor_fix"
tooltip="@.set_cursor_fix_tooltip"
pref="tablet.set_cursor_fix" />
<link text="(#4539)" url="https://github.com/aseprite/aseprite/issues/4539" />
</hbox>
</vbox>
</vbox>
<!-- Files -->
@ -575,12 +581,6 @@
<check id="tint_shade_tone_hue_with_sat_value"
text="@.hue_with_sat_value"
pref="experimental.hue_with_sat_value_for_color_selector" />
<hbox id="load_wintab_driver_box">
<check id="load_wintab_driver2"
text="@.load_wintab_driver"
tooltip="@.load_wintab_driver_tooltip" />
<link text="@.wintab_more_info" url="https://www.aseprite.org/docs/wintab/" />
</hbox>
<check id="flash_layer" text="@.flash_selected_layer" />
<hbox>
<label text="@.non_active_layer_opacity" />

2
laf

@ -1 +1 @@
Subproject commit feba52e4ca7855219044e9fdf936ecb6b9b4d1ca
Subproject commit ff41af60e95517fa9e922374c9a3a43442bce5b4

View File

@ -283,27 +283,34 @@ int App::initialize(const AppOptions& options)
m_isShell = options.startShell();
m_coreModules = std::make_unique<CoreModules>();
auto& pref = preferences();
#if LAF_WINDOWS
os::TabletOptions tabletOptions;
if (options.disableWintab() ||
!preferences().experimental.loadWintabDriver() ||
preferences().tablet.api() == "pointer") {
system->setTabletAPI(os::TabletAPI::WindowsPointerInput);
!pref.experimental.loadWintabDriver() ||
pref.tablet.api() == "pointer") {
tabletOptions.api = os::TabletAPI::WindowsPointerInput;
}
else if (preferences().tablet.api() == "wintab_packets")
system->setTabletAPI(os::TabletAPI::WintabPackets);
else // preferences().tablet.api() == "wintab"
system->setTabletAPI(os::TabletAPI::Wintab);
else if (pref.tablet.api() == "wintab_packets") {
tabletOptions.api = os::TabletAPI::WintabPackets;
}
else { // pref.tablet.api() == "wintab"
tabletOptions.api = os::TabletAPI::Wintab;
}
tabletOptions.setCursorFix = pref.tablet.setCursorFix();
system->setTabletOptions(tabletOptions);
#elif LAF_MACOS
if (!preferences().general.osxAsyncView())
if (!pref.general.osxAsyncView())
os::osx_set_async_view(false);
#elif LAF_LINUX
{
const std::string& stylusId = preferences().general.x11StylusId();
const std::string& stylusId = pref.general.x11StylusId();
if (!stylusId.empty())
os::x11_set_user_defined_string_to_detect_stylus(stylusId);
}
@ -331,7 +338,7 @@ int App::initialize(const AppOptions& options)
break;
}
initialize_color_spaces(preferences());
initialize_color_spaces(pref);
#ifdef ENABLE_DRM
LOG("APP: Initializing DRM...\n");
@ -344,14 +351,14 @@ int App::initialize(const AppOptions& options)
#endif
// Load modules
m_modules = std::make_unique<Modules>(createLogInDesktop, preferences());
m_modules = std::make_unique<Modules>(createLogInDesktop, pref);
m_legacy = std::make_unique<LegacyModules>(isGui() ? REQUIRE_INTERFACE: 0);
#ifdef ENABLE_UI
m_brushes = std::make_unique<AppBrushes>();
#endif
// Data recovery is enabled only in GUI mode
if (isGui() && preferences().general.dataRecovery())
if (isGui() && pref.general.dataRecovery())
m_modules->createDataRecovery(context());
if (isPortable())
@ -371,8 +378,8 @@ int App::initialize(const AppOptions& options)
m_uiSystem->setClipboardDelegate(&m_modules->m_clipboard);
// Setup the GUI cursor and redraw screen
ui::set_use_native_cursors(preferences().cursor.useNativeCursor());
ui::set_mouse_cursor_scale(preferences().cursor.cursorScale());
ui::set_use_native_cursors(pref.cursor.useNativeCursor());
ui::set_mouse_cursor_scale(pref.cursor.cursorScale());
ui::set_mouse_cursor(kArrowCursor);
auto manager = ui::Manager::getDefault();
@ -385,7 +392,7 @@ int App::initialize(const AppOptions& options)
m_mod->modMainWindow(m_mainWindow.get());
// Data recovery is enabled only in GUI mode
if (preferences().general.dataRecovery())
if (pref.general.dataRecovery())
m_modules->searchDataRecoverySessions();
// Default status of the main window.

View File

@ -429,33 +429,20 @@ public:
!nativeFileDialog()->isSelected());
});
#ifdef _WIN32 // Show Tablet section on Windows
#ifdef LAF_WINDOWS // Show Tablet section on Windows
{
os::TabletAPI tabletAPI = os::instance()->tabletAPI();
if (tabletAPI == os::TabletAPI::Wintab) {
const os::TabletAPI tabletAPI = os::instance()->tabletAPI();
if (tabletAPI == os::TabletAPI::Wintab)
tabletApiWintabSystem()->setSelected(true);
loadWintabDriver()->setSelected(true);
loadWintabDriver2()->setSelected(true);
}
else if (tabletAPI == os::TabletAPI::WintabPackets) {
else if (tabletAPI == os::TabletAPI::WintabPackets)
tabletApiWintabDirect()->setSelected(true);
loadWintabDriver()->setSelected(true);
loadWintabDriver2()->setSelected(true);
}
else {
else
tabletApiWindowsPointer()->setSelected(true);
loadWintabDriver()->setSelected(false);
loadWintabDriver2()->setSelected(false);
}
onTabletAPIChange();
tabletApiWindowsPointer()->Click.connect([this](){ onTabletAPIChange(); });
tabletApiWintabSystem()->Click.connect([this](){ onTabletAPIChange(); });
tabletApiWintabDirect()->Click.connect([this](){ onTabletAPIChange(); });
loadWintabDriver()->Click.connect(
[this](){ onLoadWintabChange(loadWintabDriver()->isSelected()); });
loadWintabDriver2()->Click.connect(
[this](){ onLoadWintabChange(loadWintabDriver2()->isSelected()); });
}
#else // For macOS and Linux
{
@ -467,8 +454,6 @@ public:
}
}
sectionTablet()->setVisible(false);
loadWintabDriverBox()->setVisible(false);
loadWintabDriverBox()->setVisible(false);
}
#endif
@ -832,7 +817,7 @@ public:
m_pref.experimental.nonactiveLayersOpacity(nonactiveLayersOpacity()->getValue());
m_pref.quantization.rgbmapAlgorithm(m_rgbmapAlgorithmSelector.algorithm());
#ifdef _WIN32
#ifdef LAF_WINDOWS
{
os::TabletAPI tabletAPI = os::TabletAPI::Default;
std::string tabletStr;
@ -860,7 +845,10 @@ public:
->setInterpretOneFingerGestureAsMouseMovement(
oneFingerAsMouseMovement()->isSelected());
os::instance()->setTabletAPI(tabletAPI);
os::TabletOptions options;
options.api = tabletAPI;
options.setCursorFix = m_pref.tablet.setCursorFix();
os::instance()->setTabletOptions(options);
}
#endif
@ -1782,28 +1770,13 @@ private:
}
}
#ifdef _WIN32
#ifdef LAF_WINDOWS
void onTabletAPIChange() {
if (tabletApiWindowsPointer()->isSelected()) {
loadWintabDriver()->setSelected(false);
loadWintabDriver2()->setSelected(false);
}
else if (tabletApiWintabSystem()->isSelected() ||
tabletApiWintabDirect()->isSelected()) {
loadWintabDriver()->setSelected(true);
loadWintabDriver2()->setSelected(true);
}
const bool pointerApi = tabletApiWindowsPointer()->isSelected();
windowsPointerOptions()->setVisible(pointerApi);
sectionTablet()->layout();
}
void onLoadWintabChange(bool state) {
loadWintabDriver()->setSelected(state);
loadWintabDriver2()->setSelected(state);
if (state)
tabletApiWintabSystem()->setSelected(true);
else
tabletApiWindowsPointer()->setSelected(true);
}
#endif // _WIN32
#endif // LAF_WINDOWS
Context* m_context;
Preferences& m_pref;