Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153042297
D35754.id108033.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D35754.id108033.diff
View Options
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3466,6 +3466,7 @@
dev/vt/hw/vga/vt_vga.c optional vt vt_vga
dev/vt/logo/logo_freebsd.c optional vt splash
dev/vt/logo/logo_beastie.c optional vt splash
+dev/vt/vt_accessibility.c optional vt
dev/vt/vt_buf.c optional vt
dev/vt/vt_consolectl.c optional vt
dev/vt/vt_core.c optional vt
diff --git a/sys/dev/vt/vt.h b/sys/dev/vt/vt.h
--- a/sys/dev/vt/vt.h
+++ b/sys/dev/vt/vt.h
@@ -84,6 +84,8 @@
#endif
#define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG)
+SYSCTL_DECL(_kern_vt);
+
#define VT_SYSCTL_INT(_name, _default, _descr) \
int vt_##_name = (_default); \
SYSCTL_INT(_kern_vt, OID_AUTO, _name, CTLFLAG_RWTUN, &vt_##_name, 0, _descr)
@@ -168,6 +170,8 @@
term_color_t *vd_drawnbg; /* (?) Most recent bg color drawn. */
};
+extern struct vt_device *main_vd;
+
#define VD_PASTEBUF(vd) ((vd)->vd_pastebuf.vpb_buf)
#define VD_PASTEBUFSZ(vd) ((vd)->vd_pastebuf.vpb_bufsz)
#define VD_PASTEBUFLEN(vd) ((vd)->vd_pastebuf.vpb_len)
@@ -240,6 +244,7 @@
int vtbuf_get_marked_len(struct vt_buf *vb);
void vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz);
#endif
+int vtbuf_extract_accessibility(char *buf, size_t *, term_pos_t *, size_t lines, size_t bufsz);
#define VTB_MARK_NONE 0
#define VTB_MARK_END 1
diff --git a/sys/dev/vt/vt_accessibility.c b/sys/dev/vt/vt_accessibility.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/vt/vt_accessibility.c
@@ -0,0 +1,134 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2022 Hans Petter Selasky
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/sx.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/reboot.h>
+
+#include <dev/vt/vt.h>
+
+#define VT_ACCESS_UTF8_DATA_MAX 1000 /* bytes */
+
+static MALLOC_DEFINE(M_VTACCESS, "vtaccess", "VT accessibility");
+
+static SYSCTL_NODE(_kern_vt, OID_AUTO, accessibility,
+ CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "Accessibility parameters");
+
+static int vt_access_text_utf8(SYSCTL_HANDLER_ARGS);
+static int vt_access_feed(SYSCTL_HANDLER_ARGS);
+
+static term_pos_t vt_access_cursor;
+
+static char *vt_access_utf8_data;
+static size_t vt_access_utf8_length;
+
+static struct sx vt_access_sx;
+
+SX_SYSINIT(vt_access_sx, &vt_access_sx, "VT accessibility");
+
+#define VT_ACCESS_LOCK() sx_xlock(&vt_access_sx)
+#define VT_ACCESS_UNLOCK() sx_xunlock(&vt_access_sx)
+
+static unsigned vt_access_lines = 1; /* default value */
+
+SYSCTL_UINT(_kern_vt_accessibility, OID_AUTO, lines, CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
+ &vt_access_lines, 0, "Number of lines the VT accessibility module will feed, between 1 and 1000");
+
+SYSCTL_U16(_kern_vt_accessibility, OID_AUTO, row, CTLFLAG_RD | CTLFLAG_MPSAFE,
+ &vt_access_cursor.tp_row, 0, "Current VT accessibility row number, between 0 and 65535 inclusivly");
+
+SYSCTL_U16(_kern_vt_accessibility, OID_AUTO, col, CTLFLAG_RD | CTLFLAG_MPSAFE,
+ &vt_access_cursor.tp_col, 0, "Current VT accessibility column number, between 0 and 65535 inclusivly");
+
+SYSCTL_PROC(_kern_vt_accessibility, OID_AUTO, text_utf8, CTLTYPE_STRING | CTLFLAG_RD |
+ CTLFLAG_MPSAFE, NULL, 0, &vt_access_text_utf8, "A", "Current VT accessibility buffer in UTF-8 format");
+
+SYSCTL_PROC(_kern_vt_accessibility, OID_AUTO, feed,
+ CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, NULL,
+ 0, &vt_access_feed, "IU", "Set to non-zero to feed a new VT accessibility buffer");
+
+static int
+vt_access_text_utf8(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+
+ VT_ACCESS_LOCK();
+ if (vt_access_utf8_data != NULL)
+ error = SYSCTL_OUT(req, vt_access_utf8_data, vt_access_utf8_length);
+ else
+ error = 0;
+ VT_ACCESS_UNLOCK();
+
+ return (error);
+}
+
+static int
+vt_access_feed(SYSCTL_HANDLER_ARGS)
+{
+ unsigned max_ln;
+ unsigned val;
+ int error;
+
+ VT_ACCESS_LOCK();
+
+ val = 0;
+ error = SYSCTL_OUT(req, &val, sizeof(val));
+ if (error || !req->newptr)
+ goto done;
+
+ error = SYSCTL_IN(req, &val, sizeof(val));
+ if (error || val == 0)
+ goto done;
+
+ if (vt_access_utf8_data == NULL) {
+ vt_access_utf8_data =
+ malloc(VT_ACCESS_UTF8_DATA_MAX, M_VTACCESS, M_WAITOK | M_ZERO);
+ } else {
+ /* Re-use the UTF-8 buffer */
+ }
+
+ max_ln = vt_access_lines;
+ if (max_ln < 1)
+ max_ln = 1;
+ else if (max_ln > 1000)
+ max_ln = 1000;
+
+ vt_access_utf8_length = 0;
+
+ /* Update the accessibility buffer: */
+ if (vtbuf_extract_accessibility(vt_access_utf8_data,
+ &vt_access_utf8_length, &vt_access_cursor, max_ln, VT_ACCESS_UTF8_DATA_MAX) != 0)
+ vt_access_utf8_length = 0;
+done:
+ VT_ACCESS_UNLOCK();
+ return (error);
+}
diff --git a/sys/dev/vt/vt_buf.c b/sys/dev/vt/vt_buf.c
--- a/sys/dev/vt/vt_buf.c
+++ b/sys/dev/vt/vt_buf.c
@@ -746,6 +746,7 @@
return (sz * sizeof(term_char_t));
}
+#endif
static bool
tchar_is_word_separator(term_char_t ch)
@@ -770,6 +771,203 @@
}
}
+static bool
+vtbuf_extract_utf8(term_char_t ch, char *buffer, size_t *ppos, size_t size)
+{
+ char temp[4];
+ size_t len;
+
+ ch = TCHAR_CHARACTER(ch);
+
+ /* Convert to UTF-8. */
+
+ if (ch < 0x80) {
+ temp[0] = ch;
+ len = 1;
+ } else if (ch < 0x800) {
+ temp[0] = 0xc0 | (ch >> 6);
+ temp[1] = 0x80 | (ch & 0x3f);
+ len = 2;
+ } else if (ch < 0x10000) {
+ temp[0] = 0xe0 | (ch >> 12);
+ temp[1] = 0x80 | ((ch >> 6) & 0x3f);
+ temp[2] = 0x80 | (ch & 0x3f);
+ len = 3;
+ } else {
+ temp[0] = 0xf0 | (ch >> 18);
+ temp[1] = 0x80 | ((ch >> 12) & 0x3f);
+ temp[2] = 0x80 | ((ch >> 6) & 0x3f);
+ temp[3] = 0x80 | (ch & 0x3f);
+ len = 4;
+ }
+
+ /*
+ * Make sure everything fits into the buffer.
+ */
+ if (*ppos + len > size)
+ return (false);
+
+ memcpy(buffer + *ppos, temp, len);
+ *ppos += len;
+ return (true);
+}
+
+static const char vt_access_overflow[] = { "Line is not accessible" };
+
+int
+vtbuf_extract_accessibility(char *buffer, size_t *ppos, term_pos_t *cursor,
+ size_t lines, size_t bufsz)
+{
+ struct vt_device *vd;
+ struct vt_window *vw;
+ struct vt_buf *vb;
+ term_pos_t max;
+ term_char_t ch;
+ size_t lines_old;
+ size_t last_sep_off;
+ size_t last_line_off;
+ int last_sep_col;
+ int c;
+ int i;
+ int r;
+
+ MPASS(bufsz != 0);
+ MPASS(lines != 0);
+
+ vd = main_vd;
+ if (vd == NULL)
+ return (EINVAL);
+ vw = vd->vd_curwindow;
+ if (vw == NULL)
+ return (EINVAL);
+ vb = &vw->vw_buf;
+ max = vb->vb_scr_size;
+ lines_old = lines;
+
+ /* set default cursor */
+ cursor->tp_row = 0;
+ cursor->tp_col = 0;
+
+ VTBUF_LOCK(vb);
+ for (i = 0; lines != 0 && i != max.tp_row; i++) {
+ /* Get real row number in VT buffer. */
+ r = (vb->vb_roffset + i) % vb->vb_history_size;
+
+ /* Find first character, get whole word, if any. */
+ for (c = 0; c != max.tp_col; c++) {
+ ch = vb->vb_rows[r][c];
+
+ if (TCHAR_ACCESSIBILITY(ch) != 0 ||
+ TCHAR_CHARACTER(ch) == 0)
+ continue;
+ if (tchar_is_word_separator(ch))
+ break;
+ /* Go back a bit to get context, if any. */
+ while (c != 0) {
+ c--;
+ ch = vb->vb_rows[r][c];
+ if (TCHAR_CHARACTER(ch) == 0)
+ continue;
+ if (tchar_is_word_separator(ch))
+ break;
+ }
+ break;
+ }
+
+ /* Skip initial word separators, if any. */
+ for (; c != max.tp_col; c++) {
+ ch = vb->vb_rows[r][c];
+
+ if (TCHAR_CHARACTER(ch) == 0 ||
+ tchar_is_word_separator(ch))
+ continue;
+ break;
+ }
+
+ if (c == max.tp_col)
+ continue;
+
+ if (lines == lines_old) {
+ cursor->tp_row = i;
+ cursor->tp_col = c;
+ }
+
+ lines--;
+ last_sep_col = c;
+ last_sep_off = *ppos;
+ last_line_off = *ppos;
+
+ /* Try to output line. */
+ for( ; c != max.tp_col; c++) {
+ ch = vb->vb_rows[r][c];
+
+ if (TCHAR_CHARACTER(ch) == 0)
+ continue;
+
+ if (tchar_is_word_separator(ch)) {
+ if (vtbuf_extract_utf8(ch, buffer, ppos, bufsz) == false)
+ break;
+ /* Keep track of sensible stop locations. */
+ last_sep_col = c + 1;
+ last_sep_off = *ppos;
+ } else {
+ if (vtbuf_extract_utf8(ch, buffer, ppos, bufsz) == false)
+ break;
+ }
+ }
+
+ /* Check if buffer is full (whole line was not consumed). */
+ if (c != max.tp_col) {
+ /* Check if this is the first line. */
+ if (last_line_off == 0) {
+ /* XXX Pretend line was consumed. */
+ *ppos = last_line_off;
+ c = max.tp_col;
+
+ for (size_t i = 0; vt_access_overflow[i]; i++) {
+ if (vtbuf_extract_utf8(vt_access_overflow[i],
+ buffer, ppos, bufsz) == false)
+ break;
+ }
+ } else {
+ /* Stop at last separator, if any. */
+ *ppos = last_sep_off;
+ c = last_sep_col;
+ }
+
+ /* Don't output this part again. */
+ while (c--)
+ vb->vb_rows[r][c] |= TACCESSIBILITY;
+ break;
+ } else {
+ /* Don't output this line again. */
+ while (c--)
+ vb->vb_rows[r][c] |= TACCESSIBILITY;
+
+ /* Remove trailing white space. */
+ while (*ppos != last_line_off && buffer[*ppos - 1] == ' ')
+ (*ppos)--;
+
+ if (*ppos == last_line_off) {
+ /* Grab another line, this one is empty. */
+ lines++;
+ } else {
+ /* Insert a word separator, just in case. */
+ if (vtbuf_extract_utf8(' ', buffer, ppos, bufsz))
+ break;
+ }
+ }
+ }
+ VTBUF_UNLOCK(vb);
+
+ /* Remove trailing white space from last line. */
+ while (*ppos != 0 && buffer[*ppos - 1] == ' ')
+ (*ppos)--;
+
+ return (lines != lines_old ? 0 : ENOENT);
+}
+
+#ifndef SC_NO_CUTPASTE
void
vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz)
{
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -126,7 +126,7 @@
#define VT_UNIT(vw) ((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \
(vw)->vw_number)
-static SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
"vt(9) parameters");
static VT_SYSCTL_INT(enable_altgr, 1, "Enable AltGr key (Do not assume R.Alt as Alt)");
static VT_SYSCTL_INT(enable_bell, 0, "Enable bell");
diff --git a/sys/sys/terminal.h b/sys/sys/terminal.h
--- a/sys/sys/terminal.h
+++ b/sys/sys/terminal.h
@@ -69,19 +69,25 @@
* 21-25: Bold, underline, blink, reverse, right part of CJK fullwidth character
* 26-28: Foreground color
* 29-31: Background color
+ * 32: Used by VT accessibility layer
+ * 33-63: Unused
*/
-typedef uint32_t term_char_t;
+typedef uint64_t term_char_t;
#define TCHAR_CHARACTER(c) ((c) & 0x1fffff)
#define TCHAR_FORMAT(c) (((c) >> 21) & 0x1f)
#define TCHAR_FGCOLOR(c) (((c) >> 26) & 0x7)
#define TCHAR_BGCOLOR(c) (((c) >> 29) & 0x7)
+#define TCHAR_ACCESSIBILITY(c) (((c) >> 32) & 0x1)
+
+/* bit used by VT accessibility layer */
+#define TACCESSIBILITY ((term_char_t)1 << 32)
typedef teken_attr_t term_attr_t;
typedef teken_color_t term_color_t;
#define TCOLOR_FG(c) (((c) & 0x7) << 26)
-#define TCOLOR_BG(c) (((c) & 0x7) << 29)
+#define TCOLOR_BG(c) ((term_char_t)((c) & 0x7) << 29)
#define TCOLOR_LIGHT(c) ((c) | 0x8)
#define TCOLOR_DARK(c) ((c) & ~0x8)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 19, 7:32 PM (4 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31793108
Default Alt Text
D35754.id108033.diff (12 KB)
Attached To
Mode
D35754: vt(4): Add support for console screen reader using sysctls.
Attached
Detach File
Event Timeline
Log In to Comment