MyPaint built from source detects wrong keyboard

I am trying to use MyPaint on Mac with M2 chip.

I managed to install MyPaint via macports. However, with use of xorg-server the icons and text look pixelated:

(Also for some reason the background is actually black but appears as white on the screen captures.)

I also managed to install MyPaint from source, which gives much better quality of text and icons

Description of the Problem, or Question?

The problem is that with MyPaint installed from source I can’t use hotkeys. MyPaint detects key press and release as it shows in debug > test input devices. However when I modify keyboard mappings and press “s” button, MyPaint see it as “⇧ß” while in other programs it gives “s” as expected. My setup makes it even more complicated: I use English layout called on my system “U.S” and Russian layout called “Russian – PC”, while the computer have AZERTY keyboard.

So, when I change layout from US to Russian, I get another symbol when press the “s” button, this time “⇧Z”.

Note that in installation from macports MyPaint detects the keyboard correctly and put “s” for “s” whichever layout I use.

Basic System Details

MyPaint version: (installed from source)
2.1.0-alpha+git.f95972f2
(Python 3.11.7, GTK 3.24.41, GdkPixbuf 2.42.10, Cairo 1.18.0, GLib 2.78.0)

Operating System + Version:
Mac OS 13.5 (22G74) Ventura

** Are there any Errors Popping Up? If so, paste the text in the area shown below.**

MyPaint is working, all functions are working well, only there is a problem with hotkeys.
When running mypaint (installed from source) from terminal, it outputs

INFO: mypaint: Running from installed script...
INFO: mypaint: ...using static relative paths
INFO: gui.main: No locale setting found, using system locale
ERROR: lib.i18n: OSX: failed to import AppKit.NSLocale
Traceback (most recent call last):
  File "/usr/local/lib/mypaint/lib/i18n.py", line 143, in set_i18n_envvars
    from AppKit import NSLocale
ModuleNotFoundError: No module named 'AppKit'
WARNING: lib.i18n: OSX: falling back to POSIX mechanisms.
INFO: lib.i18n: OSX: LANG=None
INFO: lib.i18n: OSX: LANGUAGE=None
WARNING: /usr/local/lib/mypaint/lib/gettext_setup.py: No bindtextdomain builtins found in module 'locale'.
INFO: /usr/local/lib/mypaint/lib/gettext_setup.py: Trying platform-specific fallback hacks to find bindtextdomain funcs.
ERROR: /usr/local/lib/mypaint/lib/gettext_setup.py: No platform-specific fallback for locating bindtextdomain is known for 'darwin'
INFO: gui.compatibility: Setting mode to 2.x (standard)
INFO: gui.compatibility: Setting default layer type to Pigment
WARNING: gui.keyboard: Ignoring keybinding for '<Actions>/WindowActions/BackgroundWindow'
WARNING: gui.keyboard: Ignoring keybinding for '<Actions>/WindowActions/BackgroundWindow'
INFO: gui.document: Initialized background from '/usr/local/share/mypaint/backgrounds/mrmamurk/mamurk_e_1.png'
WARNING: gui.keyboard: Ignoring keybinding for '<Actions>/BrushModifierActions/BlendModeMenu'
INFO: gui.brushmanager: Switching default pigment setting to On
INFO: lib.document: load_ora: '/Users/slisakov/.local/share/mypaint/scratchpads/autosave.ora'
INFO: lib.document: 0.015s load_ora total
INFO: gui.filehandling: Loaded scratchpad from '/Users/slisakov/.local/share/mypaint/scratchpads/autosave.ora'
INFO: gui.compatibility: Setting default layer type to Pigment

(mypaint:3594): Gdk-CRITICAL **: 15:53:02.159: gdk_device_get_vendor_id: assertion 'gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER' failed

Does this issue describe the problems you’re facing?

I don’t have a fix for you, I’m a new developer for the project (and first committed one in years) so I’m still trying to understand the codebase.

Thanks for the prompt replies anyway. The issue you mentioned is very similar, but in my case, it’s even worse: hotkeys don’t work with either the English or the Russian keyboard layouts.

Also, I’d like to note that when installing from MacPorts the problem doesn’t occur.

Glad to hear about a new developer joining the project! I wish you good luck with it!

A quick update: MyPaint appears to interpret the symbol input as if I’m pressing ‘option+symbol.’ For instance, when I type ‘option+s’ in a text editor, I get the ‘ß’ symbol, but in MyPaint, it registers ‘s’ as if it’s being pressed along with the ‘option’ key.

1 Like

For now, I’ve just added your experience to the issue. The current goal for me is to do some spring cleaning around the codebase (which is using a number of out of date tools) and do a point release, since it’s been a while since the last release.

After I modernise the code in that point release, I’ll try to fix this issue in the next major release as there really isn’t an excuse for locale-based issues in applications these days.

1 Like

Some updates.

  1. MyPaint detects locale correctly if set
export LANG=en_US.UTF-8
export LANGUAGE=en_US:en
export LC_ALL=en_US.UTF-8
  1. ERROR: lib.i18n: OSX: failed to import AppKit.NSLocale is fixed by installing
pip install pyobjc

This however doesn’t help with the issue.

I also managed to fix

ERROR: /usr/local/lib/mypaint/lib/gettext_setup.py: No platform-specific fallback for locating bindtextdomain is known for 'darwin'

by modifying init_gettext function in /usr/local/lib/mypaint/lib/gettext_setup.py:

def init_gettext(localepath):
    custom_bindtextdomain_successful = False

    import ctypes
    import locale
    import lib.i18n

    logger.debug("localepath: %r", localepath)

    # Use ctypes to load libintl and calling bindtextdomainand and textdomain
    try:
        libintl = ctypes.cdll.LoadLibrary('libintl.dylib')
        libintl.bindtextdomain.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
        libintl.bindtextdomain.restype = ctypes.c_char_p
        libintl.textdomain.argtypes = [ctypes.c_char_p]
        libintl.textdomain.restype = ctypes.c_char_p

        domain = 'mypaint'.encode('utf-8')
        locale_dir = '/opt/homebrew/Cellar/libmypaint/1.6.1_1/share/locale'.encode('utf-8')
        result_bindtextdomain = libintl.bindtextdomain(domain, locale_dir)
        result_textdomain = libintl.textdomain(domain)

        logger.info("bindtextdomain: %s, textdomain: %s" % (result_bindtextdomain.decode('utf-8'), result_textdomain.decode('utf-8')))
        custom_bindtextdomain_successful = True

    except Exception as e:
        logger.error("Error using libintl for bindtextdomain and textdomain: %s" % e)

    if custom_bindtextdomain_successful:
        return

I thought it might help, but it didn’t.