Hi Crystal, I tried your patch on my laptop. With it applied, and my TERM set to 'xterm', I do get colors in mutt and tmux. The latter, however, shows '^@^@' before the PS1 prompt upon starting a new session (`tmux new`), behavior I don't see with a 'real' xterm.
I like the idea, thanks for your work on this diff. Paul On Wed, Jan 04, 2023 at 10:42:56AM -0300, Crystal Kolipe wrote: | Continuing the move towards xterm becoming the default termtype for the | console... | | This third version of the patchset adds the following features. New features | since the last version are highlighted first: | | NEW - Control sequences for dim text, invisible text, strike through, italic, | and double underline attributes are now recognised and set flags in | wscons. | | NEW - Rendering of dim, invisible, struck, and double underlined text is now | supported in rasops32.c, so users of 32bpp displays will see these text | effects on the console. | | NEW - The default number of scrollback screens has been increased from five to | twenty. | | * F1 - F4 now send different sequences. | * F13 - F24 now send different sequences, but see notes below about F13 - F16. | * With numlock OFF, keypad 5 is now 'begin' rather than unused. | * Home, End, keypad home, and keypad end now send different sequences. | * A new keysym has been added - KS_Backtab. | * Shift-TAB is now defined as KS_Backtab and sends ESC [ Z. | * Shift-F1 - Shift-F12 now send F13 - F24. | * Five new escape sequences added for cursor movement. | | Running with this patch, all of the curses-based programs that I use on a | regular basis are working and usable with TERM=xterm. | | The overall experience is much improved over TERM=vt220, as we get colour. | | Even compared to pccon, we gain the ability to use colour together with | underline, show and hide the cursor, and use backtab. We also gain the | practicality of relying on a very widely and well supported terminal | definition, (xterm), which could much more reasonably become the default than | could pccon. | | Additionally, a small side benefit of changing the function key sequences from | those expected by pccon to those expected by xterm is that any programs or | scripts which ignore terminfo and are hard coded to work with xterm will now | work on the console as well. | | --- dev/wscons/wsemul_vt100_keys.c.dist Sat Mar 14 00:38:50 2015 | +++ dev/wscons/wsemul_vt100_keys.c Mon Jan 2 16:01:42 2023 | @@ -37,11 +37,9 @@ | #include <dev/wscons/wsemulvar.h> | #include <dev/wscons/wsemul_vt100var.h> | | +#define vt100_fkeys_len(x) (5+(x>=8)+(x>=12)) | + | static const u_char *vt100_fkeys[] = { | - "\033[11~", /* F1 */ | - "\033[12~", | - "\033[13~", /* F1-F5 normally don't send codes */ | - "\033[14~", | "\033[15~", /* F5 */ | "\033[17~", /* F6 */ | "\033[18~", | @@ -50,18 +48,18 @@ | "\033[21~", | "\033[23~", /* VT100: ESC */ | "\033[24~", /* VT100: BS */ | - "\033[25~", /* VT100: LF */ | - "\033[26~", | - "\033[28~", /* help */ | - "\033[29~", /* do */ | - "\033[31~", | - "\033[32~", | - "\033[33~", | - "\033[34~", /* F20 */ | - "\033[35~", | - "\033[36~", | - "\033[37~", | - "\033[38~" | + "\033[1;2P", /* VT100: LF */ | + "\033[1;2Q", | + "\033[1;2R", /* help */ | + "\033[1;2S", /* do */ | + "\033[15;2~", | + "\033[17;2~", | + "\033[18;2~", | + "\033[19;2~", /* F20 */ | + "\033[20;2~", | + "\033[21;2~", | + "\033[23;2~", | + "\033[24;2~" | }; | | static const u_char *vt100_pfkeys[] = { | @@ -96,14 +94,22 @@ | edp->translatebuf, edp->flags & VTFL_UTF8)); | } | | - if (in >= KS_f1 && in <= KS_f24) { | - *out = vt100_fkeys[in - KS_f1]; | - return (5); | + if (in >= KS_f1 && in <= KS_f4) { | + *out = vt100_pfkeys[in - KS_f1]; | + return (3); | } | - if (in >= KS_F1 && in <= KS_F24) { | - *out = vt100_fkeys[in - KS_F1]; | - return (5); | + if (in >= KS_F1 && in <= KS_F4) { | + *out = vt100_pfkeys[in - KS_F1]; | + return (3); | } | + if (in >= KS_f5 && in <= KS_f24) { | + *out = vt100_fkeys[in - KS_f5]; | + return vt100_fkeys_len(in - KS_f5); | + } | + if (in >= KS_F5 && in <= KS_F24) { | + *out = vt100_fkeys[in - KS_F5]; | + return vt100_fkeys_len(in - KS_F5); | + } | if (in >= KS_KP_F1 && in <= KS_KP_F4) { | *out = vt100_pfkeys[in - KS_KP_F1]; | return (3); | @@ -148,12 +154,12 @@ | } | switch (in) { | case KS_Help: | - *out = vt100_fkeys[15 - 1]; | + *out = vt100_fkeys[15 - 1 + 4]; /* vt100_fkeys starts at F5 */ | return (5); | case KS_Execute: /* "Do" */ | - *out = vt100_fkeys[16 - 1]; | + *out = vt100_fkeys[16 - 1 + 4]; /* vt100_fkeys starts at F5 */ | return (5); | - case KS_Find: | + case KS_Find: /* Not defined in xterm terminfo */ | *out = "\033[1~"; | return (4); | case KS_Insert: | @@ -163,7 +169,7 @@ | case KS_KP_Delete: | *out = "\033[3~"; | return (4); | - case KS_Select: | + case KS_Select: /* Not defined in xterm terminfo */ | *out = "\033[4~"; | return (4); | case KS_Prior: | @@ -174,14 +180,27 @@ | case KS_KP_Next: | *out = "\033[6~"; | return (4); | + case KS_Backtab: | + *out = "\033[Z"; | + return (3); | + /* | + * Unlike insert, delete, page up, and page down, we purposely don't | + * send the same sequence of \033OE for the non-keypad 'begin' key. | + * | + * This is because the terminfo xterm entry is mapping this to kb2, | + * which is defined as 'centre of keypad'. | + */ | + case KS_KP_Begin: | + *out = "\033OE"; | + return (3); | case KS_Home: | case KS_KP_Home: | - *out = "\033[7~"; | - return (4); | + *out = "\033OH"; | + return (3); | case KS_End: | case KS_KP_End: | - *out = "\033[8~"; | - return (4); | + *out = "\033OF"; | + return (3); | case KS_Up: | case KS_KP_Up: | if (edp->flags & VTFL_APPLCURSOR) | --- dev/wscons/wsemul_vt100_subr.c.dist Mon May 25 06:55:49 2020 | +++ dev/wscons/wsemul_vt100_subr.c Wed Jan 4 09:25:38 2023 | @@ -461,6 +461,9 @@ | edp->ccol -= min(DEF1_ARG(0), edp->ccol); | edp->flags &= ~VTFL_LASTCHAR; | break; | + case 'G': /* HPA */ | + edp->ccol = min(DEF1_ARG(0)-1, edp->ncols-1); | + break; | case 'H': /* CUP */ | case 'f': /* HVP */ | if (edp->flags & VTFL_DECOM) | @@ -502,16 +505,37 @@ | WSEMULOP(rc, edp, &edp->abortstate, erasecols, | ERASECOLS(NCOLS - n, n, edp->bkgdattr)); | break; | + case 'S': /* INDN */ | + wsemul_vt100_scrollup (edp,DEF1_ARG(0)); | + break; | + case 'T': /* RIN */ | + wsemul_vt100_scrolldown (edp,DEF1_ARG(0)); | + break; | case 'X': /* ECH erase character */ | n = min(DEF1_ARG(0), COLS_LEFT + 1); | WSEMULOP(rc, edp, &edp->abortstate, erasecols, | ERASECOLS(edp->ccol, n, edp->bkgdattr)); | break; | + case 'Z': /* KCBT */ | + if (!edp->ccol) | + break; | + if (edp->tabs) { | + for (n=edp->ccol-1 ; n>0; n--) | + if (edp->tabs[n]) | + break; | + } else { | + n=((edp->ccol - 1) & 8); | + } | + edp->ccol=n; | + break; | case 'c': /* DA primary */ | if (ARG(0) == 0) | wsdisplay_emulinput(edp->cbcookie, WSEMUL_VT_ID1, | sizeof(WSEMUL_VT_ID1)); | break; | + case 'd': /* VPA */ | + edp->crow = min(DEF1_ARG(0)-1, edp->nrows-1); | + break; | case 'g': /* TBC */ | if (edp->tabs != NULL) | switch (ARG(0)) { | @@ -549,6 +573,12 @@ | case 1: /* bold */ | flags |= WSATTR_HILIT; | break; | + case 2: /* dim */ | + flags |= WSATTR_DIM; | + break; | + case 3: /* italic */ | + flags |= WSATTR_ITALIC; | + break; | case 4: /* underline */ | flags |= WSATTR_UNDERLINE; | break; | @@ -558,17 +588,43 @@ | case 7: /* reverse */ | flags |= WSATTR_REVERSE; | break; | - case 22: /* ~bold VT300 only */ | + /* | + * Invisible text only makes the _glyph_ invisible. | + * | + * Other active attributes such as underlining and | + * strikeout are still displayed in the character cell. | + */ | + case 8: /* invisible */ | + flags |= WSATTR_INVISIBLE; | + break; | + case 9: /* strike */ | + flags |= WSATTR_STRIKE; | + break; | + case 21: /* double underline */ | + flags |= WSATTR_DOUBLE_UNDERLINE; | + break; | + case 22: /* ~bold ~dim VT300 only */ | flags &= ~WSATTR_HILIT; | + flags &= ~WSATTR_DIM; | break; | + case 23: /* ~italic */ | + flags &= WSATTR_ITALIC; | + break; | case 24: /* ~underline VT300 only */ | flags &= ~WSATTR_UNDERLINE; | + flags &= ~WSATTR_DOUBLE_UNDERLINE; | break; | case 25: /* ~blink VT300 only */ | flags &= ~WSATTR_BLINK; | break; | case 27: /* ~reverse VT300 only */ | flags &= ~WSATTR_REVERSE; | + break; | + case 28: /* ~invisible */ | + flags &= ~WSATTR_INVISIBLE; | + break; | + case 29: /* ~strike */ | + flags &= ~WSATTR_STRIKE; | break; | case 30: case 31: case 32: case 33: | case 34: case 35: case 36: case 37: | --- dev/wscons/wsksymdef.h.dist Mon Sep 20 14:32:39 2021 | +++ dev/wscons/wsksymdef.h Mon Jan 2 15:48:18 2023 | @@ -626,6 +626,7 @@ | #define KS_Open 0xf393 | #define KS_Paste 0xf394 | #define KS_Cut 0xf395 | +#define KS_Backtab 0xf396 | | #define KS_Menu 0xf3c0 | #define KS_Pause 0xf3c1 | --- dev/wscons/wsdisplayvar.h.dist Sun Sep 13 07:05:46 2020 | +++ dev/wscons/wsdisplayvar.h Wed Jan 4 09:24:12 2023 | @@ -94,11 +94,16 @@ | #define WSCOL_CYAN 6 | #define WSCOL_WHITE 7 | /* flag values: */ | -#define WSATTR_REVERSE 1 | -#define WSATTR_HILIT 2 | -#define WSATTR_BLINK 4 | -#define WSATTR_UNDERLINE 8 | -#define WSATTR_WSCOLORS 16 | +#define WSATTR_REVERSE 1 | +#define WSATTR_HILIT 2 | +#define WSATTR_BLINK 4 | +#define WSATTR_UNDERLINE 8 | +#define WSATTR_WSCOLORS 16 | +#define WSATTR_DIM 32 | +#define WSATTR_STRIKE 64 | +#define WSATTR_DOUBLE_UNDERLINE 128 | +#define WSATTR_INVISIBLE 256 | +#define WSATTR_ITALIC 512 | }; | | #define WSSCREEN_NAME_SIZE 16 | --- dev/pckbc/wskbdmap_mfii.c.dist Sat May 1 13:11:16 2021 | +++ dev/pckbc/wskbdmap_mfii.c Mon Jan 2 13:51:12 2023 | @@ -59,7 +59,7 @@ | KC(12), KS_minus, KS_underscore, | KC(13), KS_equal, KS_plus, | KC(14), KS_Cmd_ResetEmul, KS_Delete, | - KC(15), KS_Tab, | + KC(15), KS_Tab, KS_Backtab, | KC(16), KS_q, | KC(17), KS_w, | KC(18), KS_e, | @@ -103,16 +103,16 @@ | KC(56), KS_Cmd2, KS_Alt_L, | KC(57), KS_space, | KC(58), KS_Caps_Lock, | - KC(59), KS_Cmd_Screen0, KS_f1, | - KC(60), KS_Cmd_Screen1, KS_f2, | - KC(61), KS_Cmd_Screen2, KS_f3, | - KC(62), KS_Cmd_Screen3, KS_f4, | - KC(63), KS_Cmd_Screen4, KS_f5, | - KC(64), KS_Cmd_Screen5, KS_f6, | - KC(65), KS_Cmd_Screen6, KS_f7, | - KC(66), KS_Cmd_Screen7, KS_f8, | - KC(67), KS_Cmd_Screen8, KS_f9, | - KC(68), KS_Cmd_Screen9, KS_f10, | + KC(59), KS_Cmd_Screen0, KS_f1, KS_f13, | + KC(60), KS_Cmd_Screen1, KS_f2, KS_f14, | + KC(61), KS_Cmd_Screen2, KS_f3, KS_f15, | + KC(62), KS_Cmd_Screen3, KS_f4, KS_f16, | + KC(63), KS_Cmd_Screen4, KS_f5, KS_f17, | + KC(64), KS_Cmd_Screen5, KS_f6, KS_f18, | + KC(65), KS_Cmd_Screen6, KS_f7, KS_f19, | + KC(66), KS_Cmd_Screen7, KS_f8, KS_f20, | + KC(67), KS_Cmd_Screen8, KS_f9, KS_f21, | + KC(68), KS_Cmd_Screen9, KS_f10, KS_f22, | KC(69), KS_Num_Lock, | KC(70), KS_Hold_Screen, | KC(71), KS_KP_Home, KS_KP_7, | @@ -128,8 +128,8 @@ | KC(81), KS_KP_Next, KS_KP_3, | KC(82), KS_KP_Insert, KS_KP_0, | KC(83), KS_KP_Delete, KS_KP_Decimal, | - KC(87), KS_Cmd_Screen10, KS_f11, | - KC(88), KS_Cmd_Screen11, KS_f12, | + KC(87), KS_Cmd_Screen10, KS_f11, KS_f23, | + KC(88), KS_Cmd_Screen11, KS_f12, KS_f24, | KC(91), KS_f13, | KC(92), KS_f14, | KC(93), KS_f15, | }; | | #if !defined(WSKBD_NO_INTL_LAYOUTS) | --- dev/rasops/rasops.c.dist Thu Jul 23 06:17:03 2020 | +++ dev/rasops/rasops.c Wed Jan 4 09:53:30 2023 | @@ -141,7 +141,7 @@ | uint32_t rs_defattr; | | int rs_sbscreens; | -#define RS_SCROLLBACK_SCREENS 5 | +#define RS_SCROLLBACK_SCREENS 20 | int rs_dispoffset; /* rs_bs index, start of our actual screen */ | int rs_visibleoffset; /* rs_bs index, current scrollback screen */ | }; | @@ -568,7 +568,19 @@ | if ((flg & WSATTR_HILIT) != 0) | fg += 8; | | - flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0); | + /* | + * The rapops code expects a different layout of the bitfields in flg: | + * | + * WSATTR_UNDERLINE is moved to bit 0 | + * Bits 1 and 2 are re-purposed to indicate whether the foreground and | + * background are grey or not, (I.E. red==green==blue). | + * | + * This was probably a convenient hack when we only had to deal with | + * underlining, but further attributes should maintain their original | + * bit positions for consistency between the wscons and rasops code. | + */ | + | + flg = ((flg & 0xfff8) | (flg & WSATTR_UNDERLINE ? 1 : 0)); | | if (rasops_isgray[fg]) | flg |= 2; | --- dev/rasops/rasops32.c.dist Mon Jul 20 09:40:45 2020 | +++ dev/rasops/rasops32.c Wed Jan 4 09:22:07 2023 | @@ -93,11 +93,40 @@ | | b = ri->ri_devcmap[(attr >> 16) & 0xf]; | f = ri->ri_devcmap[(attr >> 24) & 0xf]; | + | + /* | + * Implement dim by shifting each of the red, green and blue values by one bit. | + * | + * Since we are shifting each channel equally, this works for both RGB and BGR as | + * long as the values are stored in the lower 24 bits. | + * | + * XXX should we shift the upper 8 bits as well, to support devices that work in | + * 0xRRGGBBXX and 0xBBGGRRXX formats? Or will that break devices that expect a | + * special value in the high byte? | + */ | + | + if ((attr & WSATTR_DIM)!=0) { | + f=(f>>1) & 0x007F7F7F; | + } | + | u.d[0][0] = b; u.d[0][1] = b; | u.d[1][0] = b; u.d[1][1] = f; | u.d[2][0] = f; u.d[2][1] = b; | u.d[3][0] = f; u.d[3][1] = f; | | + /* | + * Implement 'invisible' attribute by changing the character to a space. | + * | + * We need to do this rather than just ignoring the character or filling | + * the bits with 0x00 and returning as a special case, because effects | + * such as underline and strikethrough are still rendered on invisible | + * characters, (at least they are in xterm). | + */ | + | + if ((attr & WSATTR_INVISIBLE)!=0) { | + uc=' '; | + } | + | if (uc == ' ') { | while (height--) { | /* the general, pixel-at-a-time case is fast enough */ | @@ -202,12 +231,44 @@ | } | } | | + /* Double underline relies on normal underlining being done as well. */ | + | /* Do underline a pixel at a time */ | - if ((attr & 1) != 0) { | + if ((attr & (WSATTR_DOUBLE_UNDERLINE | 1)) != 0) { | rp -= step; | for (cnt = 0; cnt < width; cnt++) | ((int *)rp)[cnt] = f; | } | + | + /* | + * Double underline now just needs to paint the second underline two | + * rows up. */ | + | + if ((attr & WSATTR_DOUBLE_UNDERLINE)!=0) { | + rp-=(step << 1); | + for (cnt=0; cnt< width; cnt++) | + ((int *)rp)[cnt]=f; | + /* | + * Reset row pointer to ensure that strikethough appears at a | + * consistent height if combined with double underlining. | + */ | + | + rp+=(step << 1); | + } | + | + /* | + * Reset pointer to ensure that strikethough appears at a consistent | + * height if combined with single underlining. | + */ | + | + if ((attr & WSATTR_STRIKE)!=0) { | + if ((attr & 1)==1) { | + rp+=step ; | + } | + rp -= (1+ri->ri_font->fontheight/2)*step; | + for (cnt=0; cnt< width; cnt++) | + ((int *)rp)[cnt]=f; | + } | | return 0; | } | -- >++++++++[<++++++++++>-]<+++++++.>+++[<------>-]<.>+++[<+ +++++++++++>-]<.>++[<------------>-]<+.--------------.[-] http://www.weirdnet.nl/