pythonpython-curseswidechar

Python Curses, reading wide character's attribute from screen


The problem I'm trying to solve is to get a couple ch,att representing the character and the associated attribute currently displayed at some given position.

Now, when the displayed character is not a wide one (i.e. an ASCII character), the method .inch does the job up to masking correctly the results. The issue comes when the displayed character is wide. More precisely I know how to get the given character through .instr, however this function does not return any information about the attribute.

Since, as far as I know, there is no specific function to get the attribute alone, my first attempt was to use .inch, drop the 8 less significant bit and interpret the result as the attribute. This seemed to work to some extent but double checking I realized that reading greek letters (u"u\03b1" for instance) with no attribute in this way returns att = 11.0000.0000 instead of 0. Is there a better way to approach the problem?

EDIT, a minimal example for Python3

import curses

def bin(x):
    out = ''
    while x > 0:
        out = str(x % 2) + out
        x = x // 2

    return out

def main(s):
    s.addstr(1, 1, u'\u03b1')
    s.refresh()

    chratt = s.inch(1, 1)

    att = chratt & 0xFF00

    s.addstr(2, 1, bin(att))
    s.refresh()

    while True:
        pass

curses.wrapper(main)

Solution

  • In curses, inch and instr is only for ascii characters as you suspected. "complex" or "wide" characters like characters from utf-8 have another system, as explained here on stackoverflow by one of the ncurses creators.

    However, onto the bad news. They aren't implemented in python curses (yet). A pull request was submitted here and it is very close to merging (90%), so if you really need it then why not go contribute yourself?

    And if that isn't an option, then you could try to store every change you make to your screen in a variable and then pull the wide characters from there.