Discussion:
[patch 0/3] speakup: support 16bit unicode screen reading
Samuel Thibault
2017-03-02 01:53:53 UTC
Permalink
Hello,

This patch series adds 16bit unicode support to speakup, through three
patches:

- extend synth buffer to 16bit unicode characters
- convert screen reading to 16bit characters
- add unicode variant of /dev/softsynth

Samuel
--
Samuel
<erno> hm. I've lost a machine.. literally _lost_. it responds to ping, it works completely, I just can't figure out where in my apartment it is.
Samuel Thibault
2017-03-02 01:53:56 UTC
Permalink
This adds /dev/softsynthu, along /dev/softsynth, which emits output in
UTF-8 encoding, thus allowing to support 16bit characters. Most of the
code is shared, only the read function has to behave differently in
latin1 and in unicode mode. Since Linux only supports 16bit characters,
we can just hardcode the UTF-8 encoding.

Signed-off-by: Samuel Thibault <***@ens-lyon.org>

Index: linux-4.10/drivers/staging/speakup/speakup_soft.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_soft.c
+++ linux-4.10/drivers/staging/speakup/speakup_soft.c
@@ -29,6 +29,7 @@

#define DRV_VERSION "2.6"
#define SOFTSYNTH_MINOR 26 /* might as well give it one more than /dev/synth */
+#define SOFTSYNTHU_MINOR 27 /* might as well give it one more than /dev/synth */
#define PROCSPEECH 0x0d
#define CLEAR_SYNTH 0x18

@@ -37,7 +38,7 @@ static void softsynth_release(void);
static int softsynth_is_alive(struct spk_synth *synth);
static unsigned char get_index(void);

-static struct miscdevice synth_device;
+static struct miscdevice synth_device, synthu_device;
static int init_pos;
static int misc_registered;

@@ -199,13 +200,13 @@ static int softsynth_close(struct inode
return 0;
}

-static ssize_t softsynth_read(struct file *fp, char __user *buf, size_t count,
- loff_t *pos)
+static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count,
+ loff_t *pos, int unicode)
{
int chars_sent = 0;
char __user *cp;
char *init;
- char ch;
+ u16 ch;
int empty;
unsigned long flags;
DEFINE_WAIT(wait);
@@ -213,7 +214,8 @@ static ssize_t softsynth_read(struct fil
spin_lock_irqsave(&speakup_info.spinlock, flags);
while (1) {
prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE);
- synth_buffer_skip_nonlatin1();
+ if (!unicode)
+ synth_buffer_skip_nonlatin1();
if (!synth_buffer_empty() || speakup_info.flushing)
break;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
@@ -232,23 +234,57 @@ static ssize_t softsynth_read(struct fil

cp = buf;
init = get_initstring();
- while (chars_sent < count) {
+
+ /* Keep 3 bytes available for a 16bit UTF-8-encoded character */
+ while (chars_sent <= count - 3) {
if (speakup_info.flushing) {
speakup_info.flushing = 0;
ch = '\x18';
- } else if (synth_buffer_empty()) {
- break;
} else if (init[init_pos]) {
ch = init[init_pos++];
} else {
+ if (!unicode)
+ synth_buffer_skip_nonlatin1();
+ if (synth_buffer_empty())
+ break;
ch = synth_buffer_getc();
}
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- if (copy_to_user(cp, &ch, 1))
- return -EFAULT;
+
+ if ((!unicode && ch < 0x100) || (unicode && ch < 0x80)) {
+ u_char c = ch;
+
+ if (copy_to_user(cp, &c, 1))
+ return -EFAULT;
+
+ chars_sent++;
+ cp++;
+ } else if (unicode && ch < 0x800) {
+ u_char s[2] = {
+ 0xc0 | (ch >> 6),
+ 0x80 | (ch & 0x3f)
+ };
+
+ if (copy_to_user(cp, s, sizeof(s)))
+ return -EFAULT;
+
+ chars_sent += sizeof(s);
+ cp += sizeof(s);
+ } else if (unicode) {
+ u_char s[3] = {
+ 0xe0 | (ch >> 12),
+ 0x80 | ((ch >> 6) & 0x3f),
+ 0x80 | (ch & 0x3f)
+ };
+
+ if (copy_to_user(cp, s, sizeof(s)))
+ return -EFAULT;
+
+ chars_sent += sizeof(s);
+ cp += sizeof(s);
+ }
+
spin_lock_irqsave(&speakup_info.spinlock, flags);
- chars_sent++;
- cp++;
}
*pos += chars_sent;
empty = synth_buffer_empty();
@@ -260,6 +296,18 @@ static ssize_t softsynth_read(struct fil
return chars_sent;
}

+static ssize_t softsynth_read(struct file *fp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ return softsynthx_read(fp, buf, count, pos, 0);
+}
+
+static ssize_t softsynthu_read(struct file *fp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ return softsynthx_read(fp, buf, count, pos, 1);
+}
+
static int last_index;

static ssize_t softsynth_write(struct file *fp, const char __user *buf,
@@ -309,6 +357,15 @@ static const struct file_operations soft
.release = softsynth_close,
};

+static const struct file_operations softsynthu_fops = {
+ .owner = THIS_MODULE,
+ .poll = softsynth_poll,
+ .read = softsynthu_read,
+ .write = softsynth_write,
+ .open = softsynth_open,
+ .release = softsynth_close,
+};
+
static int softsynth_probe(struct spk_synth *synth)
{
if (misc_registered != 0)
@@ -322,16 +379,28 @@ static int softsynth_probe(struct spk_sy
return -ENODEV;
}

+ memset(&synthu_device, 0, sizeof(synthu_device));
+ synthu_device.minor = SOFTSYNTHU_MINOR;
+ synthu_device.name = "softsynthu";
+ synthu_device.fops = &softsynthu_fops;
+ if (misc_register(&synthu_device)) {
+ pr_warn("Couldn't initialize miscdevice /dev/softsynth.\n");
+ return -ENODEV;
+ }
+
misc_registered = 1;
pr_info("initialized device: /dev/softsynth, node (MAJOR 10, MINOR 26)\n");
+ pr_info("initialized device: /dev/softsynthu, node (MAJOR 10, MINOR 27)\n");
return 0;
}

static void softsynth_release(void)
{
misc_deregister(&synth_device);
+ misc_deregister(&synthu_device);
misc_registered = 0;
pr_info("unregistered /dev/softsynth\n");
+ pr_info("unregistered /dev/softsynthu\n");
}

static int softsynth_is_alive(struct spk_synth *synth)
Chris Brannon
2017-03-03 18:40:11 UTC
Permalink
Post by Samuel Thibault
This adds /dev/softsynthu, along /dev/softsynth, which emits output in
UTF-8 encoding, thus allowing to support 16bit characters. Most of the
code is shared, only the read function has to behave differently in
latin1 and in unicode mode. Since Linux only supports 16bit characters,
we can just hardcode the UTF-8 encoding.
Reviewed-by: Chris Brannon <***@the-brannons.com>

Looks good to me.
Samuel Thibault
2017-03-04 19:46:45 UTC
Permalink
Hello William,

Could you commit this to the espeakup repository? That's all we need to
do on the espeakup side to support unicode :)

Samuel

Index: espeakup-0.80/softsynth.c
===================================================================
--- espeakup-0.80.orig/softsynth.c
+++ espeakup-0.80/softsynth.c
@@ -235,7 +235,10 @@ int open_softsynth(void)
}

/* open the softsynth. */
- softFD = open("/dev/softsynth", O_RDWR | O_NONBLOCK);
+ softFD = open("/dev/softsynthu", O_RDWR | O_NONBLOCK);
+ if (softFD < 0 && errno == ENOENT)
+ /* Kernel without unicode support? Try without unicode. */
+ softFD = open("/dev/softsynth", O_RDWR | O_NONBLOCK);
if (softFD < 0) {
perror("Unable to open the softsynth device");
rc = -1;
Samuel Thibault
2017-03-02 01:53:54 UTC
Permalink
This extends the synth buffer slots to 16bit, so as to hold 16bit
unicode characters.

synth_buffer_getc and synth_buffer_peek now return 16bit characters.
Speech synthesizers which do not support characters beyond latin1 can
use the synth_buffer_skip_nonlatin1() helper to skip the non-latin1
characters before getting or peeking. All synthesizers are made to use
it for now.

This makes synth_buffer_add take a 16bit character. For simplicity for
now, synth_printf is left to using latin1 formats and strings.
synth_putwc, synth_putwc_s, synth_putws and synth_putws_s helpers are
however added to put 16bit characters and strings.

Signed-off-by: Samuel Thibault <***@ens-lyon.org>

Index: linux-4.10/drivers/staging/speakup/spk_priv.h
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/spk_priv.h
+++ linux-4.10/drivers/staging/speakup/spk_priv.h
@@ -48,8 +48,9 @@ unsigned char spk_serial_in_nowait(void)
int spk_serial_out(const char ch);
void spk_serial_release(void);

-char synth_buffer_getc(void);
-char synth_buffer_peek(void);
+void synth_buffer_skip_nonlatin1(void);
+u16 synth_buffer_getc(void);
+u16 synth_buffer_peek(void);
int synth_buffer_empty(void);
struct var_t *spk_get_var(enum var_id_t var_id);
ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
@@ -64,6 +65,10 @@ void spk_synth_flush(struct spk_synth *s
int spk_synth_is_alive_nop(struct spk_synth *synth);
int spk_synth_is_alive_restart(struct spk_synth *synth);
void synth_printf(const char *buf, ...);
+void synth_putwc(u16 wc);
+void synth_putwc_s(u16 wc);
+void synth_putws(const u16 *buf);
+void synth_putws_s(const u16 *buf);
int synth_request_region(u_long, u_long);
int synth_release_region(u_long, u_long);
int synth_add(struct spk_synth *in_synth);
Index: linux-4.10/drivers/staging/speakup/speakup.h
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup.h
+++ linux-4.10/drivers/staging/speakup/speakup.h
@@ -70,7 +70,7 @@ void synth_release(void);

void spk_do_flush(void);
void speakup_start_ttys(void);
-void synth_buffer_add(char ch);
+void synth_buffer_add(u16 ch);
void synth_buffer_clear(void);
void speakup_clear_selection(void);
int speakup_set_selection(struct tty_struct *tty);
Index: linux-4.10/drivers/staging/speakup/synth.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/synth.c
+++ linux-4.10/drivers/staging/speakup/synth.c
@@ -109,6 +109,7 @@ void spk_do_catch_up(struct spk_synth *s
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
@@ -255,6 +256,35 @@ void synth_printf(const char *fmt, ...)
}
EXPORT_SYMBOL_GPL(synth_printf);

+void synth_putwc(u16 wc)
+{
+ synth_buffer_add(wc);
+}
+EXPORT_SYMBOL_GPL(synth_putwc);
+
+void synth_putwc_s(u16 wc)
+{
+ synth_buffer_add(wc);
+ synth_start();
+}
+EXPORT_SYMBOL_GPL(synth_putwc_s);
+
+void synth_putws(const u16 *buf)
+{
+ const u16 *p;
+
+ for (p = buf; *p; p++)
+ synth_buffer_add(*p);
+}
+EXPORT_SYMBOL_GPL(synth_putws);
+
+void synth_putws_s(const u16 *buf)
+{
+ synth_putws(buf);
+ synth_start();
+}
+EXPORT_SYMBOL_GPL(synth_putws_s);
+
static int index_count;
static int sentence_count;

Index: linux-4.10/drivers/staging/speakup/buffers.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/buffers.c
+++ linux-4.10/drivers/staging/speakup/buffers.c
@@ -7,10 +7,10 @@

#define SYNTH_BUF_SIZE 8192 /* currently 8K bytes */

-static u_char synth_buffer[SYNTH_BUF_SIZE]; /* guess what this is for! */
-static u_char *buff_in = synth_buffer;
-static u_char *buff_out = synth_buffer;
-static u_char *buffer_end = synth_buffer + SYNTH_BUF_SIZE - 1;
+static u16 synth_buffer[SYNTH_BUF_SIZE]; /* guess what this is for! */
+static u16 *buff_in = synth_buffer;
+static u16 *buff_out = synth_buffer;
+static u16 *buffer_end = synth_buffer + SYNTH_BUF_SIZE - 1;

/* These try to throttle applications by stopping the TTYs
* Note: we need to make sure that we will restart them eventually, which is
@@ -44,13 +44,13 @@ static void speakup_stop_ttys(void)

static int synth_buffer_free(void)
{
- int bytes_free;
+ int chars_free;

if (buff_in >= buff_out)
- bytes_free = SYNTH_BUF_SIZE - (buff_in - buff_out);
+ chars_free = SYNTH_BUF_SIZE - (buff_in - buff_out);
else
- bytes_free = buff_out - buff_in;
- return bytes_free;
+ chars_free = buff_out - buff_in;
+ return chars_free;
}

int synth_buffer_empty(void)
@@ -59,7 +59,7 @@ int synth_buffer_empty(void)
}
EXPORT_SYMBOL_GPL(synth_buffer_empty);

-void synth_buffer_add(char ch)
+void synth_buffer_add(u16 ch)
{
if (!synth->alive) {
/* This makes sure that we won't stop TTYs if there is no synth
@@ -78,9 +78,9 @@ void synth_buffer_add(char ch)
buff_in = synth_buffer;
}

-char synth_buffer_getc(void)
+u16 synth_buffer_getc(void)
{
- char ch;
+ u16 ch;

if (buff_out == buff_in)
return 0;
@@ -91,7 +91,7 @@ char synth_buffer_getc(void)
}
EXPORT_SYMBOL_GPL(synth_buffer_getc);

-char synth_buffer_peek(void)
+u16 synth_buffer_peek(void)
{
if (buff_out == buff_in)
return 0;
@@ -99,6 +99,18 @@ char synth_buffer_peek(void)
}
EXPORT_SYMBOL_GPL(synth_buffer_peek);

+void synth_buffer_skip_nonlatin1(void)
+{
+ while (buff_out != buff_in) {
+ if (*buff_out < 0x100)
+ return;
+ buff_out++;
+ if (buff_out > buffer_end)
+ buff_out = synth_buffer;
+ }
+}
+EXPORT_SYMBOL_GPL(synth_buffer_skip_nonlatin1);
+
void synth_buffer_clear(void)
{
buff_in = synth_buffer;
Index: linux-4.10/drivers/staging/speakup/speakup_acntpc.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_acntpc.c
+++ linux-4.10/drivers/staging/speakup/speakup_acntpc.c
@@ -196,6 +196,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_apollo.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_apollo.c
+++ linux-4.10/drivers/staging/speakup/speakup_apollo.c
@@ -160,6 +160,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_decext.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_decext.c
+++ linux-4.10/drivers/staging/speakup/speakup_decext.c
@@ -175,6 +175,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_decpc.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_decpc.c
+++ linux-4.10/drivers/staging/speakup/speakup_decpc.c
@@ -392,6 +392,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_dectlk.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_dectlk.c
+++ linux-4.10/drivers/staging/speakup/speakup_dectlk.c
@@ -239,6 +239,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_dtlk.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_dtlk.c
+++ linux-4.10/drivers/staging/speakup/speakup_dtlk.c
@@ -209,6 +209,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_keypc.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_keypc.c
+++ linux-4.10/drivers/staging/speakup/speakup_keypc.c
@@ -198,6 +198,7 @@ spin_lock_irqsave(&speakup_info.spinlock
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_soft.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_soft.c
+++ linux-4.10/drivers/staging/speakup/speakup_soft.c
@@ -213,6 +213,7 @@ static ssize_t softsynth_read(struct fil
spin_lock_irqsave(&speakup_info.spinlock, flags);
while (1) {
prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE);
+ synth_buffer_skip_nonlatin1();
if (!synth_buffer_empty() || speakup_info.flushing)
break;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
Chris Brannon
2017-03-03 18:39:30 UTC
Permalink
Post by Samuel Thibault
This extends the synth buffer slots to 16bit, so as to hold 16bit
unicode characters.
synth_buffer_getc and synth_buffer_peek now return 16bit characters.
Speech synthesizers which do not support characters beyond latin1 can
use the synth_buffer_skip_nonlatin1() helper to skip the non-latin1
characters before getting or peeking. All synthesizers are made to use
it for now.
This makes synth_buffer_add take a 16bit character. For simplicity for
now, synth_printf is left to using latin1 formats and strings.
synth_putwc, synth_putwc_s, synth_putws and synth_putws_s helpers are
however added to put 16bit characters and strings.
Reviewed-by: Chris Brannon <***@the-brannons.com>


Looks good to me.
Samuel Thibault
2017-03-02 01:53:55 UTC
Permalink
This adds 16bit character support to most of the screen reading by
extending characters to u16 throughout the code.

Non-latin1 characters are assumed to be alphabetic type for now.

non-latin1 vt_notifier_call-provided characters are not ignored any
more, and the 16bit character returned by get_char is not truncated any
more. For simplicity, speak_char still only supports latin1 characters.
Its direct mode however does support 16bit characters, so in practice
this will not be a limitation, non-latin1 languages will be handled by
the synthesizer. spelling words does not support direct mode yet, for
simplicity for now it will ignore 16bit characters.

For simplicity again, speakup messages are left in latin1 for now.

Some coding style is fixed along the way.

Signed-off-by: Samuel Thibault <***@ens-lyon.org>

Index: linux-4.10/drivers/staging/speakup/main.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/main.c
+++ linux-4.10/drivers/staging/speakup/main.c
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(quiet, "Do not announce
special_func spk_special_handler;

short spk_pitch_shift, synth_flags;
-static char buf[256];
+static u16 buf[256];
int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
int spk_no_intr, spk_spell_delay;
int spk_key_echo, spk_say_word_ctl;
@@ -112,7 +112,7 @@ enum {

static struct tty_struct *tty;

-static void spkup_write(const char *in_buf, int count);
+static void spkup_write(const u16 *in_buf, int count);

static char *phonetic[] = {
"alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
@@ -238,7 +238,8 @@ static u_short default_chartab[256] = {
struct task_struct *speakup_task;
struct bleep spk_unprocessed_sound;
static int spk_keydown;
-static u_char spk_lastkey, spk_close_press, keymap_flags;
+static u16 spk_lastkey;
+static u_char spk_close_press, keymap_flags;
static u_char last_keycode, this_speakup_key;
static u_long last_spk_jiffy;

@@ -426,9 +427,9 @@ static void announce_edge(struct vc_data
spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
}

-static void speak_char(u_char ch)
+static void speak_char(u16 ch)
{
- char *cp = spk_characters[ch];
+ char *cp;
struct var_t *direct = spk_get_var(DIRECT);

if (direct && direct->u.n.value) {
@@ -436,11 +437,15 @@ static void speak_char(u_char ch)
spk_pitch_shift++;
synth_printf("%s", spk_str_caps_start);
}
- synth_printf("%c", ch);
+ synth_putwc_s(ch);
if (IS_CHAR(ch, B_CAP))
synth_printf("%s", spk_str_caps_stop);
return;
}
+
+ if (ch >= 0x100)
+ return;
+ cp = spk_characters[ch];
if (cp == NULL) {
pr_info("speak_char: cp == NULL!\n");
return;
@@ -486,7 +491,7 @@ static u16 get_char(struct vc_data *vc,

static void say_char(struct vc_data *vc)
{
- u_short ch;
+ u16 ch;

spk_old_attr = spk_attr;
ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
@@ -496,20 +501,20 @@ static void say_char(struct vc_data *vc)
if (spk_attrib_bleep & 2)
say_attributes(vc);
}
- speak_char(ch & 0xff);
+ speak_char(ch);
}

static void say_phonetic_char(struct vc_data *vc)
{
- u_short ch;
+ u16 ch;

spk_old_attr = spk_attr;
ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
- if (isascii(ch) && isalpha(ch)) {
+ if (ch <= 0x7f && isalpha(ch)) {
ch &= 0x1f;
synth_printf("%s\n", phonetic[--ch]);
} else {
- if (IS_CHAR(ch, B_NUM))
+ if (ch < 0x100 && IS_CHAR(ch, B_NUM))
synth_printf("%s ", spk_msg_get(MSG_NUMBER));
speak_char(ch);
}
@@ -551,42 +556,42 @@ static void say_next_char(struct vc_data
static u_long get_word(struct vc_data *vc)
{
u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
- char ch;
- u_short attr_ch;
+ u16 ch;
+ u16 attr_ch;
u_char temp;

spk_old_attr = spk_attr;
- ch = (char)get_char(vc, (u_short *)tmp_pos, &temp);
+ ch = get_char(vc, (u_short *)tmp_pos, &temp);

/* decided to take out the sayword if on a space (mis-information */
if (spk_say_word_ctl && ch == SPACE) {
*buf = '\0';
synth_printf("%s\n", spk_msg_get(MSG_SPACE));
return 0;
- } else if ((tmpx < vc->vc_cols - 2)
- && (ch == SPACE || ch == 0 || IS_WDLM(ch))
- && ((char)get_char(vc, (u_short *)&tmp_pos + 1, &temp) >
- SPACE)) {
+ } else if (tmpx < vc->vc_cols - 2 &&
+ (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
+ get_char(vc, (u_short *)&tmp_pos + 1, &temp) > SPACE) {
tmp_pos += 2;
tmpx++;
} else
while (tmpx > 0) {
- ch = (char)get_char(vc, (u_short *)tmp_pos - 1, &temp);
- if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
- && ((char)get_char(vc, (u_short *)tmp_pos, &temp) >
- SPACE))
+ ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
+ if ((ch == SPACE || ch == 0 ||
+ (ch < 0x100 && IS_WDLM(ch))) &&
+ get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
break;
tmp_pos -= 2;
tmpx--;
}
attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
- buf[cnt++] = attr_ch & 0xff;
+ buf[cnt++] = attr_ch;
while (tmpx < vc->vc_cols - 1) {
tmp_pos += 2;
tmpx++;
- ch = (char)get_char(vc, (u_short *)tmp_pos, &temp);
- if ((ch == SPACE) || ch == 0
- || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
+ ch = get_char(vc, (u_short *)tmp_pos, &temp);
+ if (ch == SPACE || ch == 0 ||
+ (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
+ ch > SPACE))
break;
buf[cnt++] = ch;
}
@@ -610,7 +615,7 @@ static void say_word(struct vc_data *vc)
static void say_prev_word(struct vc_data *vc)
{
u_char temp;
- char ch;
+ u16 ch;
u_short edge_said = 0, last_state = 0, state = 0;

spk_parked |= 0x01;
@@ -639,10 +644,10 @@ static void say_prev_word(struct vc_data
} else
spk_x--;
spk_pos -= 2;
- ch = (char)get_char(vc, (u_short *)spk_pos, &temp);
+ ch = get_char(vc, (u_short *)spk_pos, &temp);
if (ch == SPACE || ch == 0)
state = 0;
- else if (IS_WDLM(ch))
+ else if (ch < 0x100 && IS_WDLM(ch))
state = 1;
else
state = 2;
@@ -663,7 +668,7 @@ static void say_prev_word(struct vc_data
static void say_next_word(struct vc_data *vc)
{
u_char temp;
- char ch;
+ u16 ch;
u_short edge_said = 0, last_state = 2, state = 0;

spk_parked |= 0x01;
@@ -672,10 +677,10 @@ static void say_next_word(struct vc_data
return;
}
while (1) {
- ch = (char)get_char(vc, (u_short *)spk_pos, &temp);
+ ch = get_char(vc, (u_short *)spk_pos, &temp);
if (ch == SPACE || ch == 0)
state = 0;
- else if (IS_WDLM(ch))
+ else if (ch < 0x100 && IS_WDLM(ch))
state = 1;
else
state = 2;
@@ -703,13 +708,18 @@ static void say_next_word(struct vc_data
static void spell_word(struct vc_data *vc)
{
static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
- char *cp = buf, *str_cap = spk_str_caps_stop;
- char *cp1, *last_cap = spk_str_caps_stop;
- u_char ch;
+ u16 *cp = buf;
+ char *cp1;
+ char *str_cap = spk_str_caps_stop;
+ char *last_cap = spk_str_caps_stop;
+ u16 ch;

if (!get_word(vc))
return;
- while ((ch = (u_char)*cp)) {
+ while ((ch = *cp)) {
+ if (ch >= 0x100)
+ /* FIXME */
+ continue;
if (cp != buf)
synth_printf(" %s ", delay_str[spk_spell_delay]);
if (IS_CHAR(ch, B_CAP)) {
@@ -724,9 +734,9 @@ static void spell_word(struct vc_data *v
synth_printf("%s", str_cap);
last_cap = str_cap;
}
- if (this_speakup_key == SPELL_PHONETIC
- && (isascii(ch) && isalpha(ch))) {
- ch &= 31;
+ if (this_speakup_key == SPELL_PHONETIC &&
+ ch <= 0x7f && isalpha(ch)) {
+ ch &= 0x1f;
cp1 = phonetic[--ch];
} else {
cp1 = spk_characters[ch];
@@ -751,7 +761,7 @@ static int get_line(struct vc_data *vc)
spk_old_attr = spk_attr;
spk_attr = get_attributes(vc, (u_short *)spk_pos);
for (i = 0; i < vc->vc_cols; i++) {
- buf[i] = (u_char)get_char(vc, (u_short *)tmp, &tmp2);
+ buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
tmp += 2;
}
for (--i; i >= 0; i--)
@@ -763,7 +773,7 @@ static int get_line(struct vc_data *vc)
static void say_line(struct vc_data *vc)
{
int i = get_line(vc);
- char *cp;
+ u16 *cp;
u_short saved_punc_mask = spk_punc_mask;

if (i == 0) {
@@ -816,7 +826,7 @@ static int say_from_to(struct vc_data *v
spk_old_attr = spk_attr;
spk_attr = get_attributes(vc, (u_short *)from);
while (from < to) {
- buf[i++] = (char)get_char(vc, (u_short *)from, &tmp);
+ buf[i++] = get_char(vc, (u_short *)from, &tmp);
from += 2;
if (i >= vc->vc_size_row)
break;
@@ -852,11 +862,11 @@ static void say_line_from_to(struct vc_d

static int currsentence;
static int numsentences[2];
-static char *sentbufend[2];
-static char *sentmarks[2][10];
+static u16 *sentbufend[2];
+static u16 *sentmarks[2][10];
static int currbuf;
static int bn;
-static char sentbuf[2][256];
+static u16 sentbuf[2][256];

static int say_sentence_num(int num, int prev)
{
@@ -892,7 +902,7 @@ static int get_sentence_buf(struct vc_da
spk_attr = get_attributes(vc, (u_short *)start);

while (start < end) {
- sentbuf[bn][i] = (char)get_char(vc, (u_short *)start, &tmp);
+ sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
if (i > 0) {
if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
&& numsentences[bn] < 9) {
@@ -995,7 +1005,7 @@ static void right_edge(struct vc_data *v
static void say_first_char(struct vc_data *vc)
{
int i, len = get_line(vc);
- u_char ch;
+ u16 ch;

spk_parked |= 0x01;
if (len == 0) {
@@ -1015,7 +1025,7 @@ static void say_first_char(struct vc_dat
static void say_last_char(struct vc_data *vc)
{
int len = get_line(vc);
- u_char ch;
+ u16 ch;

spk_parked |= 0x01;
if (len == 0) {
@@ -1040,9 +1050,8 @@ static void say_position(struct vc_data
static void say_char_num(struct vc_data *vc)
{
u_char tmp;
- u_short ch = get_char(vc, (u_short *)spk_pos, &tmp);
+ u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);

- ch &= 0xff;
synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
}

@@ -1070,10 +1079,10 @@ static void say_to_right(struct vc_data

/* end of stub functions. */

-static void spkup_write(const char *in_buf, int count)
+static void spkup_write(const u16 *in_buf, int count)
{
static int rep_count;
- static u_char ch = '\0', old_ch = '\0';
+ static u16 ch = '\0', old_ch = '\0';
static u_short char_type, last_type;
int in_count = count;

@@ -1085,8 +1094,11 @@ static void spkup_write(const char *in_b
(currsentence <= numsentences[bn]))
synth_insert_next_index(currsentence++);
}
- ch = (u_char)*in_buf++;
- char_type = spk_chartab[ch];
+ ch = *in_buf++;
+ if (ch < 0x100)
+ char_type = spk_chartab[ch];
+ else
+ char_type = ALPHA;
if (ch == old_ch && !(char_type & B_NUM)) {
if (++rep_count > 2)
continue;
@@ -1106,10 +1118,10 @@ static void spkup_write(const char *in_b
} else if (char_type & B_ALPHA) {
if ((synth_flags & SF_DEC) && (last_type & PUNC))
synth_buffer_add(SPACE);
- synth_printf("%c", ch);
+ synth_putwc_s(ch);
} else if (char_type & B_NUM) {
rep_count = 0;
- synth_printf("%c", ch);
+ synth_putwc_s(ch);
} else if (char_type & spk_punc_mask) {
speak_char(ch);
char_type &= ~PUNC; /* for dec nospell processing */
@@ -1122,7 +1134,7 @@ static void spkup_write(const char *in_b
* repeats on you don't get nothing repeated count
*/
if (ch != old_ch)
- synth_printf("%c", ch);
+ synth_putwc_s(ch);
else
rep_count = 0;
} else {
@@ -1533,7 +1545,7 @@ static void do_handle_cursor(struct vc_d
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}

-static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
+static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
{
int i, bi, hi;
int vc_num = vc->vc_num;
@@ -1548,7 +1560,7 @@ static void update_color_buffer(struct v
speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
}
while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
- if ((ic[i] > 32) && (ic[i] < 127)) {
+ if (ic[i] > 32) {
speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
hi++;
} else if ((ic[i] == 32) && (hi != 0)) {
@@ -1718,7 +1730,7 @@ static void speakup_bs(struct vc_data *v
}

/* called by: vt_notifier_call() */
-static void speakup_con_write(struct vc_data *vc, const char *str, int len)
+static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
{
unsigned long flags;

@@ -1908,6 +1920,7 @@ static int handle_goto(struct vc_data *v
static int num;
int maxlen;
char *cp;
+ u16 wch;

if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
goto do_goto;
@@ -1916,18 +1929,20 @@ static int handle_goto(struct vc_data *v
if (type != 0)
goto oops;
if (ch == 8) {
+ u16 wch;
if (num == 0)
return -1;
- ch = goto_buf[--num];
+ wch = goto_buf[--num];
goto_buf[num] = '\0';
- spkup_write(&ch, 1);
+ spkup_write(&wch, 1);
return 1;
}
if (ch < '+' || ch > 'y')
goto oops;
+ wch = ch;
goto_buf[num++] = ch;
goto_buf[num] = '\0';
- spkup_write(&ch, 1);
+ spkup_write(&wch, 1);
maxlen = (*goto_buf >= '0') ? 3 : 4;
if ((ch == '+' || ch == '-') && num == 1)
return 1;
@@ -2254,9 +2269,8 @@ static int vt_notifier_call(struct notif
case VT_WRITE:
if (param->c == '\b')
speakup_bs(vc);
- else if (param->c < 0x100) {
- char d = param->c;
-
+ else {
+ u16 d = param->c;
speakup_con_write(vc, &d, 1);
}
break;
Index: linux-4.10/drivers/staging/speakup/spk_types.h
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/spk_types.h
+++ linux-4.10/drivers/staging/speakup/spk_types.h
@@ -55,7 +55,7 @@ struct spk_highlight_color_track {
/* Count of each background color */
unsigned int bgcount[8];
/* Buffer for characters drawn with each background color */
- char highbuf[8][COLOR_BUFFER_SIZE];
+ u16 highbuf[8][COLOR_BUFFER_SIZE];
/* Current index into highbuf */
unsigned int highsize[8];
/* Reading Position for each color */
Index: linux-4.10/drivers/staging/speakup/speakup.h
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup.h
+++ linux-4.10/drivers/staging/speakup/speakup.h
@@ -38,6 +38,7 @@
#define B_SYM 0x0800
#define B_CAPSYM (B_CAP|B_SYM)

+/* FIXME: u16 */
#define IS_WDLM(x) (spk_chartab[((u_char)x)]&B_WDLM)
#define IS_CHAR(x, type) (spk_chartab[((u_char)x)]&type)
#define IS_TYPE(x, type) ((spk_chartab[((u_char)x)]&type) == type)
Samuel Thibault
2017-03-02 23:58:23 UTC
Permalink
Hello,

Could some people review the patches? This is needed for inclusion in
the kernel :)

Okash, perhaps you could have a look?

Samuel
Okash Khawaja
2017-03-03 08:23:06 UTC
Permalink
Hi,
Post by Samuel Thibault
Hello,
Could some people review the patches? This is needed for inclusion in
the kernel :)
Okash, perhaps you could have a look?
Samuel
Sorry, been tied up shifting house so been a bit slow to respond generally. Checking it and will reply with feedback.
Samuel Thibault
2017-03-04 14:02:49 UTC
Permalink
Hello,

Thanks for the reviews, I have pushed the patches again with your
Reviewed-by tags.

Samuel
Samuel Thibault
2017-03-11 09:43:08 UTC
Permalink
Hello,
I found what causes the other two problems - with spelling words in cyrillic and reading individual cyrillic characters (I'll quote my previous findings at the end of this letter, in case you've missed my previous letter).
I indeed didn't receive it, and I can't find it in the mailing list
archive.
ch = inverse_translate(vc, c, 0);
u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode);
Oops, indeed. Will fix that.
if (direct && direct->u.n.value)
If the character is cyrillic (or probably any other character from the non-ascii range), it doesn't pass this check,
I don't think it's related to being non-ascii. Do you have 1 in
/sys/accessibility/speakup/soft/direct
? If not, put 1 there, so it's espeak which will do the spelling. On the
long run, I don't think we want to include in the kernel the spellling
of each and every unicode character, so it's probably better to just
have users use the direct mode. William, what do you think? I'd say
softsynth should default to enabling direct mode by itself, shouldn't
it?
if (ch >= 0x100)
return;
So nothing unicode ever gets out.
Yes, as mentioned above the kernel does not support unicode spelling by
itself.
In main.c, around line 723, in spell_word, where it says "fixme",
Here, the "fixme" is actually about supporting direct mode.
the following continue statement probably causes an infinite loop,
Oops.
which causes the freeze that I experianced (if I replace it with a brake statement - there's no freeze).
Could you try to just add cp++; before the continue;?
I use speakup exclusively all day today and haven't spotted other problems.
Cool :)
Follows a copy of my previous message about speakup not reading cyrillic (and probably any unicode characters) with the review commands (or any other action, except when the screen is updated).
Normally, only the spelling without enabling direct mode does not work
I also found, that inverse_translate is called in selection.c, line 31/32, too.
Indeed, selection still needs some work, because when pasting it has to
feed the console properly: either utf-8 or the proper 8bit encoding.

Thanks for the feedback!
Samuel
Samuel Thibault
2017-03-11 09:46:01 UTC
Permalink
Post by Samuel Thibault
I found what causes the other two problems - with spelling words in cyrillic and reading individual cyrillic characters (I'll quote my previous findings at the end of this letter, in case you've missed my previous letter).
I indeed didn't receive it, and I can't find it in the mailing list
archive.
Your mails don't seem to be reaching the mailing list.
Make sure to Cc me explicitly, and see with listmaster what the problem
might be :)

Samuel
Samuel Thibault
2017-03-11 17:11:12 UTC
Permalink
Yes, that works, but why not just fix it? (See below)
Sure, it's just to work on things step by step.

Samuel
Samuel Thibault
2017-03-12 23:07:42 UTC
Permalink
I didn't know about the direct mode - enabling it indeed fixes the problem, but has another unplesent effect - espeak doesn't read most characters, i.e. punctioation, space, etc.
That's not expected. Which version of espeakup are you using? Version
0.80 should be working fine in that regard.
Why not force it for everything aboveextended ascii (256)?
That'd get an even more odd situation: characters below 256 would be
spoken in "english", while others would be spoken in the espeakup
language. We should be able to just get the direct mode working fine
for everything.

Samuel
Chris Brannon
2017-03-13 11:20:15 UTC
Permalink
Post by Samuel Thibault
I didn't know about the direct mode - enabling it indeed fixes the
problem, but has another unplesent effect - espeak doesn't read most
characters, i.e. punctioation, space, etc.
That's not expected. Which version of espeakup are you using? Version
0.80 should be working fine in that regard.
Here's what you need to do to make synth punctuation spelling work in
direct mode:
echo 1 > /sys/accessibility/speakup/soft/punct
That sets espeakup's punctuation setting to "all". There are multiple
punctuation settings in Speakup.
soft/punct is the synthesizer's punctuation level.
It is the amount of punctuation that will be spoken by the synthesizer
when it receives punctuation characters. There's only one way to change
this: via /sys/accessibility/speakup/soft/punct. Ordinarily, you set it
once and don't mess with it. punclevel and reading_punc are used by
the screen reader, and control what amount of punctuation gets delivered
to the synthesizer. These are independent of the synth punctuation
setting, and they're the ones that can be changed with keyboard
commands. So we have three punctuation settings:

* synthesizer punctuation: what amount of the *received* punctuation is
actually spoken by the synthesizer? Set by /sys/accessibility/soft/punct.
* punclevel: when speaking text as it is displayed on the console, what
amount of punctuation do we deliver to the synthesizer? Set by
/sys/accessibility/speakup/punclevel, or keyboard commands.
* reading_punc: In review mode, when reviewing by line, what amount of
punctuation do we deliver to the synth? Set by
/sys/accessibility/speakup/reading_punc, or keyboard commands.

So to make a long story short, in direct mode, set soft/punct to 1 and
forget it. Just use punclevel and reading_punc keyboard commands to
control how much punctuation actually gets delivered to the synth.

Now here's another problem that I see. I don't think the synth
punctuation setting was ever documented. speechd-up does one thing,
espeakup does another.
With espeakup, 0 is no punctuation, 1 is all punctuation, and 2 is some
punctuation.
With speechd-up, 0 is all punctuation, 1 and 2 are some punctuation, 3
is no punctuation.

I don't think espeakup will speak the space character in direct mode,
and I don't know of the best way to make this happen. It just speaks
silence when you cursor over it.

There's one more problem with direct mode and punctuation. The various
messages that Speakup uses for help, errors, or indicating something to
the user have punctuation characters in them. With the synth
punctuation setting set to 'all", you're going to hear those characters,
even though they should never be heard by the user. Perhaps they need
to be stripped?

Hope this is all clear.

PS. Zahari, I am not seeing your messages. I'm seeing Samuel's. Are
you subscribed to the list? I think at one time the list was dropping
mail from non-subscribers, but I don't know whether that is still the
case.

-- Chris
Chris Brannon
2017-03-03 17:26:48 UTC
Permalink
Post by Samuel Thibault
Could some people review the patches? This is needed for inclusion in
the kernel :)
I haven't looked at kernel stuff in a long time, so take my reviews with
a grain of salt. I looked at patch 3 first, because I was familiar with
the softsynth code a few years ago. It looks good and correct to me.
So should I dig out that patch and reply with a Reviewed-by line, or
Acked-by line, or what?

-- Chris
Samuel Thibault
2017-03-03 17:44:49 UTC
Permalink
Post by Chris Brannon
Post by Samuel Thibault
Could some people review the patches? This is needed for inclusion in
the kernel :)
I haven't looked at kernel stuff in a long time, so take my reviews with
a grain of salt. I looked at patch 3 first, because I was familiar with
the softsynth code a few years ago. It looks good and correct to me.
So should I dig out that patch and reply with a Reviewed-by line, or
Acked-by line, or what?
A Reviewed-by line, yes, please :)

Samuel
Samuel Thibault
2017-03-04 14:01:54 UTC
Permalink
Hello,

This patch series adds 16bit unicode support to speakup, through three
patches:

- extend synth buffer to 16bit unicode characters
- convert screen reading to 16bit characters
- add unicode variant of /dev/softsynth

Samuel
--
Samuel
"...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and
the Ugly)."
(By Matt Welsh)
Samuel Thibault
2017-03-04 14:01:57 UTC
Permalink
This adds /dev/softsynthu, along /dev/softsynth, which emits output in
UTF-8 encoding, thus allowing to support 16bit characters. Most of the
code is shared, only the read function has to behave differently in
latin1 and in unicode mode. Since Linux only supports 16bit characters,
we can just hardcode the UTF-8 encoding.

Signed-off-by: Samuel Thibault <***@ens-lyon.org>
Reviewed-by: Chris Brannon <***@the-brannons.com>

Index: linux-4.10/drivers/staging/speakup/speakup_soft.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_soft.c
+++ linux-4.10/drivers/staging/speakup/speakup_soft.c
@@ -29,6 +29,7 @@

#define DRV_VERSION "2.6"
#define SOFTSYNTH_MINOR 26 /* might as well give it one more than /dev/synth */
+#define SOFTSYNTHU_MINOR 27 /* might as well give it one more than /dev/synth */
#define PROCSPEECH 0x0d
#define CLEAR_SYNTH 0x18

@@ -37,7 +38,7 @@ static void softsynth_release(void);
static int softsynth_is_alive(struct spk_synth *synth);
static unsigned char get_index(void);

-static struct miscdevice synth_device;
+static struct miscdevice synth_device, synthu_device;
static int init_pos;
static int misc_registered;

@@ -199,13 +200,13 @@ static int softsynth_close(struct inode
return 0;
}

-static ssize_t softsynth_read(struct file *fp, char __user *buf, size_t count,
- loff_t *pos)
+static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count,
+ loff_t *pos, int unicode)
{
int chars_sent = 0;
char __user *cp;
char *init;
- char ch;
+ u16 ch;
int empty;
unsigned long flags;
DEFINE_WAIT(wait);
@@ -213,7 +214,8 @@ static ssize_t softsynth_read(struct fil
spin_lock_irqsave(&speakup_info.spinlock, flags);
while (1) {
prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE);
- synth_buffer_skip_nonlatin1();
+ if (!unicode)
+ synth_buffer_skip_nonlatin1();
if (!synth_buffer_empty() || speakup_info.flushing)
break;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
@@ -232,23 +234,57 @@ static ssize_t softsynth_read(struct fil

cp = buf;
init = get_initstring();
- while (chars_sent < count) {
+
+ /* Keep 3 bytes available for a 16bit UTF-8-encoded character */
+ while (chars_sent <= count - 3) {
if (speakup_info.flushing) {
speakup_info.flushing = 0;
ch = '\x18';
- } else if (synth_buffer_empty()) {
- break;
} else if (init[init_pos]) {
ch = init[init_pos++];
} else {
+ if (!unicode)
+ synth_buffer_skip_nonlatin1();
+ if (synth_buffer_empty())
+ break;
ch = synth_buffer_getc();
}
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
- if (copy_to_user(cp, &ch, 1))
- return -EFAULT;
+
+ if ((!unicode && ch < 0x100) || (unicode && ch < 0x80)) {
+ u_char c = ch;
+
+ if (copy_to_user(cp, &c, 1))
+ return -EFAULT;
+
+ chars_sent++;
+ cp++;
+ } else if (unicode && ch < 0x800) {
+ u_char s[2] = {
+ 0xc0 | (ch >> 6),
+ 0x80 | (ch & 0x3f)
+ };
+
+ if (copy_to_user(cp, s, sizeof(s)))
+ return -EFAULT;
+
+ chars_sent += sizeof(s);
+ cp += sizeof(s);
+ } else if (unicode) {
+ u_char s[3] = {
+ 0xe0 | (ch >> 12),
+ 0x80 | ((ch >> 6) & 0x3f),
+ 0x80 | (ch & 0x3f)
+ };
+
+ if (copy_to_user(cp, s, sizeof(s)))
+ return -EFAULT;
+
+ chars_sent += sizeof(s);
+ cp += sizeof(s);
+ }
+
spin_lock_irqsave(&speakup_info.spinlock, flags);
- chars_sent++;
- cp++;
}
*pos += chars_sent;
empty = synth_buffer_empty();
@@ -260,6 +296,18 @@ static ssize_t softsynth_read(struct fil
return chars_sent;
}

+static ssize_t softsynth_read(struct file *fp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ return softsynthx_read(fp, buf, count, pos, 0);
+}
+
+static ssize_t softsynthu_read(struct file *fp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ return softsynthx_read(fp, buf, count, pos, 1);
+}
+
static int last_index;

static ssize_t softsynth_write(struct file *fp, const char __user *buf,
@@ -309,6 +357,15 @@ static const struct file_operations soft
.release = softsynth_close,
};

+static const struct file_operations softsynthu_fops = {
+ .owner = THIS_MODULE,
+ .poll = softsynth_poll,
+ .read = softsynthu_read,
+ .write = softsynth_write,
+ .open = softsynth_open,
+ .release = softsynth_close,
+};
+
static int softsynth_probe(struct spk_synth *synth)
{
if (misc_registered != 0)
@@ -322,16 +379,28 @@ static int softsynth_probe(struct spk_sy
return -ENODEV;
}

+ memset(&synthu_device, 0, sizeof(synthu_device));
+ synthu_device.minor = SOFTSYNTHU_MINOR;
+ synthu_device.name = "softsynthu";
+ synthu_device.fops = &softsynthu_fops;
+ if (misc_register(&synthu_device)) {
+ pr_warn("Couldn't initialize miscdevice /dev/softsynth.\n");
+ return -ENODEV;
+ }
+
misc_registered = 1;
pr_info("initialized device: /dev/softsynth, node (MAJOR 10, MINOR 26)\n");
+ pr_info("initialized device: /dev/softsynthu, node (MAJOR 10, MINOR 27)\n");
return 0;
}

static void softsynth_release(void)
{
misc_deregister(&synth_device);
+ misc_deregister(&synthu_device);
misc_registered = 0;
pr_info("unregistered /dev/softsynth\n");
+ pr_info("unregistered /dev/softsynthu\n");
}

static int softsynth_is_alive(struct spk_synth *synth)
Samuel Thibault
2017-03-04 14:01:56 UTC
Permalink
This adds 16bit character support to most of the screen reading by
extending characters to u16 throughout the code.

Non-latin1 characters are assumed to be alphabetic type for now.

non-latin1 vt_notifier_call-provided characters are not ignored any
more, and the 16bit character returned by get_char is not truncated any
more. For simplicity, speak_char still only supports latin1 characters.
Its direct mode however does support 16bit characters, so in practice
this will not be a limitation, non-latin1 languages will be handled by
the synthesizer. spelling words does not support direct mode yet, for
simplicity for now it will ignore 16bit characters.

For simplicity again, speakup messages are left in latin1 for now.

Some coding style is fixed along the way.

Signed-off-by: Samuel Thibault <***@ens-lyon.org>
Reviewed-by: Okash Khawaja <***@gmail.com>

Index: linux-4.10/drivers/staging/speakup/main.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/main.c
+++ linux-4.10/drivers/staging/speakup/main.c
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(quiet, "Do not announce
special_func spk_special_handler;

short spk_pitch_shift, synth_flags;
-static char buf[256];
+static u16 buf[256];
int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
int spk_no_intr, spk_spell_delay;
int spk_key_echo, spk_say_word_ctl;
@@ -112,7 +112,7 @@ enum {

static struct tty_struct *tty;

-static void spkup_write(const char *in_buf, int count);
+static void spkup_write(const u16 *in_buf, int count);

static char *phonetic[] = {
"alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
@@ -238,7 +238,8 @@ static u_short default_chartab[256] = {
struct task_struct *speakup_task;
struct bleep spk_unprocessed_sound;
static int spk_keydown;
-static u_char spk_lastkey, spk_close_press, keymap_flags;
+static u16 spk_lastkey;
+static u_char spk_close_press, keymap_flags;
static u_char last_keycode, this_speakup_key;
static u_long last_spk_jiffy;

@@ -426,9 +427,9 @@ static void announce_edge(struct vc_data
spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
}

-static void speak_char(u_char ch)
+static void speak_char(u16 ch)
{
- char *cp = spk_characters[ch];
+ char *cp;
struct var_t *direct = spk_get_var(DIRECT);

if (direct && direct->u.n.value) {
@@ -436,11 +437,15 @@ static void speak_char(u_char ch)
spk_pitch_shift++;
synth_printf("%s", spk_str_caps_start);
}
- synth_printf("%c", ch);
+ synth_putwc_s(ch);
if (IS_CHAR(ch, B_CAP))
synth_printf("%s", spk_str_caps_stop);
return;
}
+
+ if (ch >= 0x100)
+ return;
+ cp = spk_characters[ch];
if (cp == NULL) {
pr_info("speak_char: cp == NULL!\n");
return;
@@ -486,7 +491,7 @@ static u16 get_char(struct vc_data *vc,

static void say_char(struct vc_data *vc)
{
- u_short ch;
+ u16 ch;

spk_old_attr = spk_attr;
ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
@@ -496,20 +501,20 @@ static void say_char(struct vc_data *vc)
if (spk_attrib_bleep & 2)
say_attributes(vc);
}
- speak_char(ch & 0xff);
+ speak_char(ch);
}

static void say_phonetic_char(struct vc_data *vc)
{
- u_short ch;
+ u16 ch;

spk_old_attr = spk_attr;
ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
- if (isascii(ch) && isalpha(ch)) {
+ if (ch <= 0x7f && isalpha(ch)) {
ch &= 0x1f;
synth_printf("%s\n", phonetic[--ch]);
} else {
- if (IS_CHAR(ch, B_NUM))
+ if (ch < 0x100 && IS_CHAR(ch, B_NUM))
synth_printf("%s ", spk_msg_get(MSG_NUMBER));
speak_char(ch);
}
@@ -551,42 +556,42 @@ static void say_next_char(struct vc_data
static u_long get_word(struct vc_data *vc)
{
u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
- char ch;
- u_short attr_ch;
+ u16 ch;
+ u16 attr_ch;
u_char temp;

spk_old_attr = spk_attr;
- ch = (char)get_char(vc, (u_short *)tmp_pos, &temp);
+ ch = get_char(vc, (u_short *)tmp_pos, &temp);

/* decided to take out the sayword if on a space (mis-information */
if (spk_say_word_ctl && ch == SPACE) {
*buf = '\0';
synth_printf("%s\n", spk_msg_get(MSG_SPACE));
return 0;
- } else if ((tmpx < vc->vc_cols - 2)
- && (ch == SPACE || ch == 0 || IS_WDLM(ch))
- && ((char)get_char(vc, (u_short *)&tmp_pos + 1, &temp) >
- SPACE)) {
+ } else if (tmpx < vc->vc_cols - 2 &&
+ (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
+ get_char(vc, (u_short *)&tmp_pos + 1, &temp) > SPACE) {
tmp_pos += 2;
tmpx++;
} else
while (tmpx > 0) {
- ch = (char)get_char(vc, (u_short *)tmp_pos - 1, &temp);
- if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
- && ((char)get_char(vc, (u_short *)tmp_pos, &temp) >
- SPACE))
+ ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
+ if ((ch == SPACE || ch == 0 ||
+ (ch < 0x100 && IS_WDLM(ch))) &&
+ get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
break;
tmp_pos -= 2;
tmpx--;
}
attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
- buf[cnt++] = attr_ch & 0xff;
+ buf[cnt++] = attr_ch;
while (tmpx < vc->vc_cols - 1) {
tmp_pos += 2;
tmpx++;
- ch = (char)get_char(vc, (u_short *)tmp_pos, &temp);
- if ((ch == SPACE) || ch == 0
- || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
+ ch = get_char(vc, (u_short *)tmp_pos, &temp);
+ if (ch == SPACE || ch == 0 ||
+ (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
+ ch > SPACE))
break;
buf[cnt++] = ch;
}
@@ -610,7 +615,7 @@ static void say_word(struct vc_data *vc)
static void say_prev_word(struct vc_data *vc)
{
u_char temp;
- char ch;
+ u16 ch;
u_short edge_said = 0, last_state = 0, state = 0;

spk_parked |= 0x01;
@@ -639,10 +644,10 @@ static void say_prev_word(struct vc_data
} else
spk_x--;
spk_pos -= 2;
- ch = (char)get_char(vc, (u_short *)spk_pos, &temp);
+ ch = get_char(vc, (u_short *)spk_pos, &temp);
if (ch == SPACE || ch == 0)
state = 0;
- else if (IS_WDLM(ch))
+ else if (ch < 0x100 && IS_WDLM(ch))
state = 1;
else
state = 2;
@@ -663,7 +668,7 @@ static void say_prev_word(struct vc_data
static void say_next_word(struct vc_data *vc)
{
u_char temp;
- char ch;
+ u16 ch;
u_short edge_said = 0, last_state = 2, state = 0;

spk_parked |= 0x01;
@@ -672,10 +677,10 @@ static void say_next_word(struct vc_data
return;
}
while (1) {
- ch = (char)get_char(vc, (u_short *)spk_pos, &temp);
+ ch = get_char(vc, (u_short *)spk_pos, &temp);
if (ch == SPACE || ch == 0)
state = 0;
- else if (IS_WDLM(ch))
+ else if (ch < 0x100 && IS_WDLM(ch))
state = 1;
else
state = 2;
@@ -703,13 +708,18 @@ static void say_next_word(struct vc_data
static void spell_word(struct vc_data *vc)
{
static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
- char *cp = buf, *str_cap = spk_str_caps_stop;
- char *cp1, *last_cap = spk_str_caps_stop;
- u_char ch;
+ u16 *cp = buf;
+ char *cp1;
+ char *str_cap = spk_str_caps_stop;
+ char *last_cap = spk_str_caps_stop;
+ u16 ch;

if (!get_word(vc))
return;
- while ((ch = (u_char)*cp)) {
+ while ((ch = *cp)) {
+ if (ch >= 0x100)
+ /* FIXME */
+ continue;
if (cp != buf)
synth_printf(" %s ", delay_str[spk_spell_delay]);
if (IS_CHAR(ch, B_CAP)) {
@@ -724,9 +734,9 @@ static void spell_word(struct vc_data *v
synth_printf("%s", str_cap);
last_cap = str_cap;
}
- if (this_speakup_key == SPELL_PHONETIC
- && (isascii(ch) && isalpha(ch))) {
- ch &= 31;
+ if (this_speakup_key == SPELL_PHONETIC &&
+ ch <= 0x7f && isalpha(ch)) {
+ ch &= 0x1f;
cp1 = phonetic[--ch];
} else {
cp1 = spk_characters[ch];
@@ -751,7 +761,7 @@ static int get_line(struct vc_data *vc)
spk_old_attr = spk_attr;
spk_attr = get_attributes(vc, (u_short *)spk_pos);
for (i = 0; i < vc->vc_cols; i++) {
- buf[i] = (u_char)get_char(vc, (u_short *)tmp, &tmp2);
+ buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
tmp += 2;
}
for (--i; i >= 0; i--)
@@ -763,7 +773,7 @@ static int get_line(struct vc_data *vc)
static void say_line(struct vc_data *vc)
{
int i = get_line(vc);
- char *cp;
+ u16 *cp;
u_short saved_punc_mask = spk_punc_mask;

if (i == 0) {
@@ -816,7 +826,7 @@ static int say_from_to(struct vc_data *v
spk_old_attr = spk_attr;
spk_attr = get_attributes(vc, (u_short *)from);
while (from < to) {
- buf[i++] = (char)get_char(vc, (u_short *)from, &tmp);
+ buf[i++] = get_char(vc, (u_short *)from, &tmp);
from += 2;
if (i >= vc->vc_size_row)
break;
@@ -852,11 +862,11 @@ static void say_line_from_to(struct vc_d

static int currsentence;
static int numsentences[2];
-static char *sentbufend[2];
-static char *sentmarks[2][10];
+static u16 *sentbufend[2];
+static u16 *sentmarks[2][10];
static int currbuf;
static int bn;
-static char sentbuf[2][256];
+static u16 sentbuf[2][256];

static int say_sentence_num(int num, int prev)
{
@@ -892,7 +902,7 @@ static int get_sentence_buf(struct vc_da
spk_attr = get_attributes(vc, (u_short *)start);

while (start < end) {
- sentbuf[bn][i] = (char)get_char(vc, (u_short *)start, &tmp);
+ sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
if (i > 0) {
if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
&& numsentences[bn] < 9) {
@@ -995,7 +1005,7 @@ static void right_edge(struct vc_data *v
static void say_first_char(struct vc_data *vc)
{
int i, len = get_line(vc);
- u_char ch;
+ u16 ch;

spk_parked |= 0x01;
if (len == 0) {
@@ -1015,7 +1025,7 @@ static void say_first_char(struct vc_dat
static void say_last_char(struct vc_data *vc)
{
int len = get_line(vc);
- u_char ch;
+ u16 ch;

spk_parked |= 0x01;
if (len == 0) {
@@ -1040,9 +1050,8 @@ static void say_position(struct vc_data
static void say_char_num(struct vc_data *vc)
{
u_char tmp;
- u_short ch = get_char(vc, (u_short *)spk_pos, &tmp);
+ u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);

- ch &= 0xff;
synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
}

@@ -1070,10 +1079,10 @@ static void say_to_right(struct vc_data

/* end of stub functions. */

-static void spkup_write(const char *in_buf, int count)
+static void spkup_write(const u16 *in_buf, int count)
{
static int rep_count;
- static u_char ch = '\0', old_ch = '\0';
+ static u16 ch = '\0', old_ch = '\0';
static u_short char_type, last_type;
int in_count = count;

@@ -1085,8 +1094,11 @@ static void spkup_write(const char *in_b
(currsentence <= numsentences[bn]))
synth_insert_next_index(currsentence++);
}
- ch = (u_char)*in_buf++;
- char_type = spk_chartab[ch];
+ ch = *in_buf++;
+ if (ch < 0x100)
+ char_type = spk_chartab[ch];
+ else
+ char_type = ALPHA;
if (ch == old_ch && !(char_type & B_NUM)) {
if (++rep_count > 2)
continue;
@@ -1106,10 +1118,10 @@ static void spkup_write(const char *in_b
} else if (char_type & B_ALPHA) {
if ((synth_flags & SF_DEC) && (last_type & PUNC))
synth_buffer_add(SPACE);
- synth_printf("%c", ch);
+ synth_putwc_s(ch);
} else if (char_type & B_NUM) {
rep_count = 0;
- synth_printf("%c", ch);
+ synth_putwc_s(ch);
} else if (char_type & spk_punc_mask) {
speak_char(ch);
char_type &= ~PUNC; /* for dec nospell processing */
@@ -1122,7 +1134,7 @@ static void spkup_write(const char *in_b
* repeats on you don't get nothing repeated count
*/
if (ch != old_ch)
- synth_printf("%c", ch);
+ synth_putwc_s(ch);
else
rep_count = 0;
} else {
@@ -1533,7 +1545,7 @@ static void do_handle_cursor(struct vc_d
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}

-static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
+static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
{
int i, bi, hi;
int vc_num = vc->vc_num;
@@ -1548,7 +1560,7 @@ static void update_color_buffer(struct v
speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
}
while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
- if ((ic[i] > 32) && (ic[i] < 127)) {
+ if (ic[i] > 32) {
speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
hi++;
} else if ((ic[i] == 32) && (hi != 0)) {
@@ -1718,7 +1730,7 @@ static void speakup_bs(struct vc_data *v
}

/* called by: vt_notifier_call() */
-static void speakup_con_write(struct vc_data *vc, const char *str, int len)
+static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
{
unsigned long flags;

@@ -1908,6 +1920,7 @@ static int handle_goto(struct vc_data *v
static int num;
int maxlen;
char *cp;
+ u16 wch;

if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
goto do_goto;
@@ -1916,18 +1929,20 @@ static int handle_goto(struct vc_data *v
if (type != 0)
goto oops;
if (ch == 8) {
+ u16 wch;
if (num == 0)
return -1;
- ch = goto_buf[--num];
+ wch = goto_buf[--num];
goto_buf[num] = '\0';
- spkup_write(&ch, 1);
+ spkup_write(&wch, 1);
return 1;
}
if (ch < '+' || ch > 'y')
goto oops;
+ wch = ch;
goto_buf[num++] = ch;
goto_buf[num] = '\0';
- spkup_write(&ch, 1);
+ spkup_write(&wch, 1);
maxlen = (*goto_buf >= '0') ? 3 : 4;
if ((ch == '+' || ch == '-') && num == 1)
return 1;
@@ -2254,9 +2269,8 @@ static int vt_notifier_call(struct notif
case VT_WRITE:
if (param->c == '\b')
speakup_bs(vc);
- else if (param->c < 0x100) {
- char d = param->c;
-
+ else {
+ u16 d = param->c;
speakup_con_write(vc, &d, 1);
}
break;
Index: linux-4.10/drivers/staging/speakup/spk_types.h
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/spk_types.h
+++ linux-4.10/drivers/staging/speakup/spk_types.h
@@ -55,7 +55,7 @@ struct spk_highlight_color_track {
/* Count of each background color */
unsigned int bgcount[8];
/* Buffer for characters drawn with each background color */
- char highbuf[8][COLOR_BUFFER_SIZE];
+ u16 highbuf[8][COLOR_BUFFER_SIZE];
/* Current index into highbuf */
unsigned int highsize[8];
/* Reading Position for each color */
Index: linux-4.10/drivers/staging/speakup/speakup.h
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup.h
+++ linux-4.10/drivers/staging/speakup/speakup.h
@@ -38,6 +38,7 @@
#define B_SYM 0x0800
#define B_CAPSYM (B_CAP|B_SYM)

+/* FIXME: u16 */
#define IS_WDLM(x) (spk_chartab[((u_char)x)]&B_WDLM)
#define IS_CHAR(x, type) (spk_chartab[((u_char)x)]&type)
#define IS_TYPE(x, type) ((spk_chartab[((u_char)x)]&type) == type)
Samuel Thibault
2017-03-04 14:01:55 UTC
Permalink
This extends the synth buffer slots to 16bit, so as to hold 16bit
unicode characters.

synth_buffer_getc and synth_buffer_peek now return 16bit characters.
Speech synthesizers which do not support characters beyond latin1 can
use the synth_buffer_skip_nonlatin1() helper to skip the non-latin1
characters before getting or peeking. All synthesizers are made to use
it for now.

This makes synth_buffer_add take a 16bit character. For simplicity for
now, synth_printf is left to using latin1 formats and strings.
synth_putwc, synth_putwc_s, synth_putws and synth_putws_s helpers are
however added to put 16bit characters and strings.

Signed-off-by: Samuel Thibault <***@ens-lyon.org>
Reviewed-by: Chris Brannon <***@the-brannons.com>

Index: linux-4.10/drivers/staging/speakup/spk_priv.h
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/spk_priv.h
+++ linux-4.10/drivers/staging/speakup/spk_priv.h
@@ -48,8 +48,9 @@ unsigned char spk_serial_in_nowait(void)
int spk_serial_out(const char ch);
void spk_serial_release(void);

-char synth_buffer_getc(void);
-char synth_buffer_peek(void);
+void synth_buffer_skip_nonlatin1(void);
+u16 synth_buffer_getc(void);
+u16 synth_buffer_peek(void);
int synth_buffer_empty(void);
struct var_t *spk_get_var(enum var_id_t var_id);
ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
@@ -64,6 +65,10 @@ void spk_synth_flush(struct spk_synth *s
int spk_synth_is_alive_nop(struct spk_synth *synth);
int spk_synth_is_alive_restart(struct spk_synth *synth);
void synth_printf(const char *buf, ...);
+void synth_putwc(u16 wc);
+void synth_putwc_s(u16 wc);
+void synth_putws(const u16 *buf);
+void synth_putws_s(const u16 *buf);
int synth_request_region(u_long, u_long);
int synth_release_region(u_long, u_long);
int synth_add(struct spk_synth *in_synth);
Index: linux-4.10/drivers/staging/speakup/speakup.h
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup.h
+++ linux-4.10/drivers/staging/speakup/speakup.h
@@ -70,7 +70,7 @@ void synth_release(void);

void spk_do_flush(void);
void speakup_start_ttys(void);
-void synth_buffer_add(char ch);
+void synth_buffer_add(u16 ch);
void synth_buffer_clear(void);
void speakup_clear_selection(void);
int speakup_set_selection(struct tty_struct *tty);
Index: linux-4.10/drivers/staging/speakup/synth.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/synth.c
+++ linux-4.10/drivers/staging/speakup/synth.c
@@ -109,6 +109,7 @@ void spk_do_catch_up(struct spk_synth *s
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
@@ -255,6 +256,35 @@ void synth_printf(const char *fmt, ...)
}
EXPORT_SYMBOL_GPL(synth_printf);

+void synth_putwc(u16 wc)
+{
+ synth_buffer_add(wc);
+}
+EXPORT_SYMBOL_GPL(synth_putwc);
+
+void synth_putwc_s(u16 wc)
+{
+ synth_buffer_add(wc);
+ synth_start();
+}
+EXPORT_SYMBOL_GPL(synth_putwc_s);
+
+void synth_putws(const u16 *buf)
+{
+ const u16 *p;
+
+ for (p = buf; *p; p++)
+ synth_buffer_add(*p);
+}
+EXPORT_SYMBOL_GPL(synth_putws);
+
+void synth_putws_s(const u16 *buf)
+{
+ synth_putws(buf);
+ synth_start();
+}
+EXPORT_SYMBOL_GPL(synth_putws_s);
+
static int index_count;
static int sentence_count;

Index: linux-4.10/drivers/staging/speakup/buffers.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/buffers.c
+++ linux-4.10/drivers/staging/speakup/buffers.c
@@ -7,10 +7,10 @@

#define SYNTH_BUF_SIZE 8192 /* currently 8K bytes */

-static u_char synth_buffer[SYNTH_BUF_SIZE]; /* guess what this is for! */
-static u_char *buff_in = synth_buffer;
-static u_char *buff_out = synth_buffer;
-static u_char *buffer_end = synth_buffer + SYNTH_BUF_SIZE - 1;
+static u16 synth_buffer[SYNTH_BUF_SIZE]; /* guess what this is for! */
+static u16 *buff_in = synth_buffer;
+static u16 *buff_out = synth_buffer;
+static u16 *buffer_end = synth_buffer + SYNTH_BUF_SIZE - 1;

/* These try to throttle applications by stopping the TTYs
* Note: we need to make sure that we will restart them eventually, which is
@@ -44,13 +44,13 @@ static void speakup_stop_ttys(void)

static int synth_buffer_free(void)
{
- int bytes_free;
+ int chars_free;

if (buff_in >= buff_out)
- bytes_free = SYNTH_BUF_SIZE - (buff_in - buff_out);
+ chars_free = SYNTH_BUF_SIZE - (buff_in - buff_out);
else
- bytes_free = buff_out - buff_in;
- return bytes_free;
+ chars_free = buff_out - buff_in;
+ return chars_free;
}

int synth_buffer_empty(void)
@@ -59,7 +59,7 @@ int synth_buffer_empty(void)
}
EXPORT_SYMBOL_GPL(synth_buffer_empty);

-void synth_buffer_add(char ch)
+void synth_buffer_add(u16 ch)
{
if (!synth->alive) {
/* This makes sure that we won't stop TTYs if there is no synth
@@ -78,9 +78,9 @@ void synth_buffer_add(char ch)
buff_in = synth_buffer;
}

-char synth_buffer_getc(void)
+u16 synth_buffer_getc(void)
{
- char ch;
+ u16 ch;

if (buff_out == buff_in)
return 0;
@@ -91,7 +91,7 @@ char synth_buffer_getc(void)
}
EXPORT_SYMBOL_GPL(synth_buffer_getc);

-char synth_buffer_peek(void)
+u16 synth_buffer_peek(void)
{
if (buff_out == buff_in)
return 0;
@@ -99,6 +99,18 @@ char synth_buffer_peek(void)
}
EXPORT_SYMBOL_GPL(synth_buffer_peek);

+void synth_buffer_skip_nonlatin1(void)
+{
+ while (buff_out != buff_in) {
+ if (*buff_out < 0x100)
+ return;
+ buff_out++;
+ if (buff_out > buffer_end)
+ buff_out = synth_buffer;
+ }
+}
+EXPORT_SYMBOL_GPL(synth_buffer_skip_nonlatin1);
+
void synth_buffer_clear(void)
{
buff_in = synth_buffer;
Index: linux-4.10/drivers/staging/speakup/speakup_acntpc.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_acntpc.c
+++ linux-4.10/drivers/staging/speakup/speakup_acntpc.c
@@ -196,6 +196,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_apollo.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_apollo.c
+++ linux-4.10/drivers/staging/speakup/speakup_apollo.c
@@ -160,6 +160,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_decext.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_decext.c
+++ linux-4.10/drivers/staging/speakup/speakup_decext.c
@@ -175,6 +175,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_decpc.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_decpc.c
+++ linux-4.10/drivers/staging/speakup/speakup_decpc.c
@@ -392,6 +392,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_dectlk.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_dectlk.c
+++ linux-4.10/drivers/staging/speakup/speakup_dectlk.c
@@ -239,6 +239,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_dtlk.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_dtlk.c
+++ linux-4.10/drivers/staging/speakup/speakup_dtlk.c
@@ -209,6 +209,7 @@ static void do_catch_up(struct spk_synth
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_keypc.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_keypc.c
+++ linux-4.10/drivers/staging/speakup/speakup_keypc.c
@@ -198,6 +198,7 @@ spin_lock_irqsave(&speakup_info.spinlock
synth->flush(synth);
continue;
}
+ synth_buffer_skip_nonlatin1();
if (synth_buffer_empty()) {
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
break;
Index: linux-4.10/drivers/staging/speakup/speakup_soft.c
===================================================================
--- linux-4.10.orig/drivers/staging/speakup/speakup_soft.c
+++ linux-4.10/drivers/staging/speakup/speakup_soft.c
@@ -213,6 +213,7 @@ static ssize_t softsynth_read(struct fil
spin_lock_irqsave(&speakup_info.spinlock, flags);
while (1) {
prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE);
+ synth_buffer_skip_nonlatin1();
if (!synth_buffer_empty() || speakup_info.flushing)
break;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
Samuel Thibault
2017-03-09 16:33:42 UTC
Permalink
This is the second version of this series, correct? Next time, please
put a "v2" in them so that I know which to apply.
Ah, yes, sorry. The only difference was the Reviewed-by lines.

Thanks!
Samuel
Samuel Thibault
2017-03-14 21:19:57 UTC
Permalink
Hello,
Post by Samuel Thibault
That'd get an even more odd situation: characters below 256 would be
spoken in "english", while others would be spoken in the espeakup
language. We should be able to just get the direct mode working fine
for everything.
Yes, but speakup might also be localized, eventually.
Well, speakup is localizable since a long time, but one can only notice
that it hasn't been actually localized since, while espeak does have
everything in place, so why not just use that and be done.
And now you lose them in English, too.
I don't understand this. Is there perhaps yet another bug that wasn't
fixed or reported?
And if you won't support those characters, why cut them, instead of letting the synthesizer to handle them? You're not losing anything. The synthesizers that don't support them skip them anyway.
Right :)
Though I'd love to translate speakup in Bulgarian. I can't wait for the unicode support to be available for the internal messages, smile.
We'd have to think and code a bit about this. The kernel actually uses
ucs-2 encoding, while people will probably rather feed the internal
messages as utf-8 strings. But one has to know whether it's utf-8 or
some 8bit character set which is being used. That question is actually
related to pasting, for which we need to know the same :)

Samuel
Zahari Yurukov
2017-03-14 22:47:53 UTC
Permalink
Hi,

Samuel Thibault wrote:
Tue, Mar 14, 2017 at 10:19:57PM +0100
Post by Samuel Thibault
Well, speakup is localizable since a long time, but one can only notice
that it hasn't been actually localized since, while espeak does have
everything in place, so why not just use that and be done.
When I wrote that,I didn't know that soft/punct is different than
punclvl. Now I set it to 1, and I have punctuation which I can somewhat
control with punclvl and readingpunc, but now I can't get rid of
punctuation completely - even if I set punclvl and readingpunc to 0, I
still hear some symbols, like comma, dot, dash, etc.
Post by Samuel Thibault
And now you lose them in English, too.
I don't understand this. Is there perhaps yet another bug that wasn't
fixed or reported?
No, I mean if you use an English voice, but you don't use direct mode,
don't you want the unicode characters spoken?
It's worth noting that I send that letter just right before I saw you've
send a patch, which treats characters above 256 like in direct mode.
So I don't have other complaints about unicode reading.
Post by Samuel Thibault
We'd have to think and code a bit about this. The kernel actually uses
ucs-2 encoding, while people will probably rather feed the internal
messages as utf-8 strings. But one has to know whether it's utf-8 or
some 8bit character set which is being used. That question is actually
related to pasting, for which we need to know the same :)
Well, a byte order mark might be useful here. Or if there's no BOM, may
be assume UTF-8?
How did you know the ASCII encodings til now?
Post by Samuel Thibault
espeak doesn't speak spaces unless strongly being told to do so :)
Yes, that works. Thanks.
--
Best wishes,
Zahari
Samuel Thibault
2017-03-14 22:56:56 UTC
Permalink
Post by Zahari Yurukov
Post by Samuel Thibault
And now you lose them in English, too.
I don't understand this. Is there perhaps yet another bug that wasn't
fixed or reported?
No, I mean if you use an English voice, but you don't use direct mode,
don't you want the unicode characters spoken?
It's not really a "you don't want", but "I don't think we want to
implement that". Unicode is awfully big, I don't think we want to
include the pronunciation of 65536 glyphs in the kernel :)
Post by Zahari Yurukov
It's worth noting that I send that letter just right before I saw you've
send a patch,
Sure, I understand that :) I was just afraid that some bug was perhaps
being overlooked
Post by Zahari Yurukov
So I don't have other complaints about unicode reading.
Ok, cool :)
Post by Zahari Yurukov
Post by Samuel Thibault
We'd have to think and code a bit about this. The kernel actually uses
ucs-2 encoding, while people will probably rather feed the internal
messages as utf-8 strings. But one has to know whether it's utf-8 or
some 8bit character set which is being used. That question is actually
related to pasting, for which we need to know the same :)
Well, a byte order mark might be useful here. Or if there's no BOM, may
be assume UTF-8?
That wouldn't allow people to just run echo "foobar" > /sys/something,
while the kernel does know whether the console is in UTF-8 mode.
Post by Zahari Yurukov
How did you know the ASCII encodings til now?
That's the trick: you just didn't :) Speakup wouldn't care about which
8bit encoding was used, and would just send it to the softsynth. As
long as the characters you write to /sys and what espeakup eats are
encoded the same, there is no issue. But now, we have the in-kernel
ucs-2 encoding, so we have to know.
Post by Zahari Yurukov
Post by Samuel Thibault
espeak doesn't speak spaces unless strongly being told to do so :)
Yes, that works. Thanks.
Good :)

Samuel
Samuel Thibault
2017-03-14 21:45:23 UTC
Permalink
espeak indeed reads the punctuation, except it doesn't read the space,
I don't think espeakup will speak the space character in direct mode,
and I don't know of the best way to make this happen. It just speaks
silence when you cursor over it.
Then it's just a bug that nobody fixed or reported :)

Could you try the attached patch?
But when I wrote that it doesn't, I was misled by the fact, that it really doesn't, except when reading by character, and not when reading strings longer than one character, i.e. screen updates, reading by word, line etc. And that's the correct behaviour.
Well, depending on what the user wants, and...
In direct mode, I can't control how much punctuation is spoken through speakup, I can't change the level with the speakup commands, i. e. punctuation level and reading punctuation .
You want something different depending on the situation :)
Or you're saying, that changing punctuation level and reading punctuation in speakup with direct mode enabled should have effect in espeakup and espeak?
Well, I'm saying that we should make everything work as expected in
direct mode, so that we can just enable it by default.
Here's what you need to do to make synth punctuation spelling work in
echo 1 > /sys/accessibility/speakup/soft/punct
So to make a long story short, in direct mode, set soft/punct to 1 and
forget it.
And so perhaps we should actually make this a default (once bugs are
fixed of course)? (but see more about the value below)
Just use punclevel and reading_punc keyboard commands to
control how much punctuation actually gets delivered to the synth.
So once direct mode is enabled and punct is set to 1, the obtained
behavior is the same as other synths?

(I'm not a speakup user, so I don't know the details).
There are multiple punctuation settings in Speakup.
Thanks, that makes things clearer to me :)
* punclevel: when speaking text as it is displayed on the console, what
amount of punctuation do we deliver to the synthesizer? Set by
/sys/accessibility/speakup/punclevel, or keyboard commands.
It seems to be 1 by default, is this really what people want as default?
That being said, I don't see the spk_punc_level variable being used in
main.c, that's odd. And indeed, setting this to 0 doesn't prevent the
punctuation from being spoken...
Now here's another problem that I see. I don't think the synth
punctuation setting was ever documented. speechd-up does one thing,
espeakup does another.
With espeakup, 0 is no punctuation, 1 is all punctuation, and 2 is some
punctuation.
With speechd-up, 0 is all punctuation, 1 and 2 are some punctuation, 3
is no punctuation.
Urgl... AIUI, speechd-up was there before espeakup, so that could
explain why the default was 0, and now that people use espeakup, they
have learnt they should set it to 1? So the actual bug fix would be to
fix the interpretation of espeakup, to match the historic values (and
thus the intended default value)?

Now, that being said, AIUI, setting the soft synth punctuation to all
means that either one gets the full punctuation, or one doesn't get the
punctuation (because it was stripped by speakup), but then in the latter
case one doesn't get the prosody either since the punctuation will have
been stripped by speakup before the synth can use it for prosody. So
AIUI, what should actually happen is that for synths which have a
PUNCT string, speakup should not strip punctuation itself, and rather
dynamically update the PUNCT value of the synth, so that the synth can
always either pronounce the punctuation, or use it for prosody. What do
you thing?
There's one more problem with direct mode and punctuation. The various
messages that Speakup uses for help, errors, or indicating something to
the user have punctuation characters in them. With the synth
punctuation setting set to 'all", you're going to hear those characters,
even though they should never be heard by the user. Perhaps they need
to be stripped?
That's probably just a bug to be fixed, yes. Actually in the source
code I see a lot of lines like

synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));

We should instead define a helper function that just takes the
MSG_UNPARKED parameter, and does the synth_printf. To fix the bug
mentioned above, we could then make that helper temporarily disable the
punctuation from the synthesizer (while still getting the prosody).

Samuel
Chris Brannon
2017-03-15 00:01:29 UTC
Permalink
Post by Samuel Thibault
Post by Chris Brannon
Here's what you need to do to make synth punctuation spelling work in
echo 1 > /sys/accessibility/speakup/soft/punct
So to make a long story short, in direct mode, set soft/punct to 1 and
forget it.
And so perhaps we should actually make this a default (once bugs are
fixed of course)? (but see more about the value below)
Yeah, having soft/punct default to the "all" value seems like a good
thing for direct mode. But tying those two variables together seems
kind of problematic. Maybe just let this be something that happens in a
startup script, or even in some startup code in the softsynth daemon itself?
Post by Samuel Thibault
Post by Chris Brannon
Just use punclevel and reading_punc keyboard commands to
control how much punctuation actually gets delivered to the synth.
So once direct mode is enabled and punct is set to 1, the obtained
behavior is the same as other synths?
Oh, it seems I'm partially wrong about punc_level and reading_punc. No
matter what you set it to, it will always send some punctuation
characters to the synth for prosody. Examples are period, comma,
colon, question mark, maybe some others?
Try the following with espeakup, direct mode enabled, soft/punct set to 1.
Run the following command at each of the punctuation levels:
echo 'printf("Hello, world %d\n", 1 + 1 < 3);'
and listen to the output. Review that line on the screen at the
different reading_punc levels, with the speak-line commands. You'll
hear what I mean.
Post by Samuel Thibault
Post by Chris Brannon
* punclevel: when speaking text as it is displayed on the console, what
amount of punctuation do we deliver to the synthesizer? Set by
/sys/accessibility/speakup/punclevel, or keyboard commands.
It seems to be 1 by default, is this really what people want as default?
That probably depends on what the user does with the computer. It's not
the setting I usually use, but isn't a bad default.
Post by Samuel Thibault
That being said, I don't see the spk_punc_level variable being used in
main.c, that's odd. And indeed, setting this to 0 doesn't prevent the
punctuation from being spoken...
Explained above why they aren't working as expected. And the punc_level
parameter is magic. The spk_punc_level variable is never read.
Instead, the effect is carried out through some code in spk_set_num_var
in varhandlers.c.
Post by Samuel Thibault
Urgl... AIUI, speechd-up was there before espeakup, so that could
explain why the default was 0, and now that people use espeakup, they
have learnt they should set it to 1? So the actual bug fix would be to
fix the interpretation of espeakup, to match the historic values (and
thus the intended default value)?
Yeah, fixing espeakup to do what speechd-up does seems right.
Post by Samuel Thibault
Now, that being said, AIUI, setting the soft synth punctuation to all
means that either one gets the full punctuation, or one doesn't get the
punctuation (because it was stripped by speakup), but then in the latter
case one doesn't get the prosody either since the punctuation will have
been stripped by speakup before the synth can use it for prosody. So
AIUI, what should actually happen is that for synths which have a
PUNCT string, speakup should not strip punctuation itself, and rather
dynamically update the PUNCT value of the synth, so that the synth can
always either pronounce the punctuation, or use it for prosody. What do
you thing?
For direct mode, this sounds like an excellent idea. When not in
direct mode, Speakup is deciding how to pronounce the punctuation, so
this really doesn't work so well.
Also what about reading_punc? To accomodate that, you need to
account for whether a given utterance came from output to the screen or
a review command, and then use the appropriate punctuation level. It'll
get complicated.

I think my biggest take-away from this discussion is that it would be
really nice to simplify how Speakup handles punctuation. Ideally, we'd
just have one setting, used everywhere, rather than up to three
punctuation settings. In direct mode, that setting directly controls
the punctuation level of the synthesizer. All punctuation is always
passed to the synth, and the synth decides whether it is spoken and how
it is pronounced. In non-direct mode, which I'll call "processed" mode,
that setting determines what level of punctuation is spoken by Speakup.
The synth's punctuation setting is always "none", so that punctuation
used for prosody is never spoken, and Speakup decides which punctuation
characters to speak and how to pronounce them.
This also eliminates the distinction between punc_level (punctuation in
spoken output) and reading_punc (punctuation in reviewed text). Hope
this idea is clear and doesn't ruffle too many feathers.

-- Chris
Samuel Thibault
2017-03-15 00:06:28 UTC
Permalink
Re,

I agree with what you said, except
Post by Chris Brannon
This also eliminates the distinction between punc_level (punctuation in
spoken output) and reading_punc (punctuation in reviewed text).
Don't users want to keep this distinction? I can understand that you
usually do not want the punctuation, to have a nice flow of text with
prosody, and when reviewing, have the punctuation by default, since
usually you review to get to the details.

Samuel
Samuel Thibault
2017-03-15 00:10:12 UTC
Permalink
(Again, I'm not a speakup user, so don't take my mail as an opinion, I
don't have any, I'm just raising the question to make sure actual users
notice it and comment :) )

Samuel
Chris Brannon
2017-03-15 00:19:40 UTC
Permalink
Post by Samuel Thibault
Post by Chris Brannon
This also eliminates the distinction between punc_level (punctuation in
spoken output) and reading_punc (punctuation in reviewed text).
Don't users want to keep this distinction? I can understand that you
usually do not want the punctuation, to have a nice flow of text with
prosody, and when reviewing, have the punctuation by default, since
usually you review to get to the details.
As far as I have always known, reading_punc only affects review-by-line,
speak from top, maybe "read window", and maybe a few other things.
Review-by-word and review-by-character are unaffected by any of the
punctuation level settings, and they always read all of the
punctuation. I tend to keep punc_level and reading_punc set to the
same value, and use review by word and review by character to review
with all punctuation when I need to. Maybe I'm not the typical Speakup
user?

As an aside, the distinction between punc_level and reading_punc was
never even documented. It's been around for a long time though.

-- Chris
Gregory Nowak
2017-03-15 01:48:58 UTC
Permalink
Post by Chris Brannon
Review-by-word and review-by-character are unaffected by any of the
punctuation level settings, and they always read all of the
punctuation. I tend to keep punc_level and reading_punc set to the
same value, and use review by word and review by character to review
with all punctuation when I need to. Maybe I'm not the typical Speakup
user?
For what it's worth, I find myself doing exactly as you described
also.

Greg
--
web site: http://www.gregn.net
gpg public key: http://www.gregn.net/pubkey.asc
skype: gregn1
(authorization required, add me to your contacts list first)
If we haven't been in touch before, e-mail me before adding me to your contacts.

--
Free domains: http://www.eu.org/ or mail dns-***@EU.org
Zahari Yurukov
2017-03-15 00:28:59 UTC
Permalink
Hi,

Samuel Thibault wrote:
Wed, Mar 15, 2017 at 01:06:28AM +0100
Post by Samuel Thibault
Don't users want to keep this distinction? I can understand that you
usually do not want the punctuation, to have a nice flow of text with
prosody, and when reviewing, have the punctuation by default, since
usually you review to get to the details.
I think that's a nice feature of speakup - to have separate punctuation
setting for the cursor/screen updates and the review commands.
Sometimes you'll want them to be the same, but sometimes you'll want
them to be different, and that's where it comes handy.
--
Best wishes,
Zahari
Willem van der Walt
2017-03-15 05:31:05 UTC
Permalink
When I read xml or python code etc. I want to be able to hear things like
< / > " = etc.
Without having to review each word.
HTH, Willem
Post by Samuel Thibault
Re,
I agree with what you said, except
Post by Chris Brannon
This also eliminates the distinction between punc_level (punctuation in
spoken output) and reading_punc (punctuation in reviewed text).
Don't users want to keep this distinction? I can understand that you
usually do not want the punctuation, to have a nice flow of text with
prosody, and when reviewing, have the punctuation by default, since
usually you review to get to the details.
Samuel
_______________________________________________
Speakup mailing list
http://linux-speakup.org/cgi-bin/mailman/listinfo/speakup
--

This message is subject to the CSIR's copyright terms and conditions, e-mail legal notice, and implemented Open Document Format (ODF) standard.
The full disclaimer details can be found at http://www.csir.co.za/disclaimer.html.

Please consider the environment before printing this email.
Samuel Thibault
2017-03-15 08:06:14 UTC
Permalink
Hello,
When I read xml or python code etc. I want to be able to hear things like <
/ > " = etc.
Without having to review each word.
Sure, but what about the default?

Actually, put another way: what should it be for a beginner, who does
not know yet how to change it?

Samuel
Willem van der Walt
2017-03-15 08:20:45 UTC
Permalink
No sure, I have no problem with the default as was suggested.
Post by Samuel Thibault
Hello,
When I read xml or python code etc. I want to be able to hear things like <
/ > " = etc.
Without having to review each word.
Sure, but what about the default?
Actually, put another way: what should it be for a beginner, who does
not know yet how to change it?
Samuel
_______________________________________________
Speakup mailing list
http://linux-speakup.org/cgi-bin/mailman/listinfo/speakup
--

This message is subject to the CSIR's copyright terms and conditions, e-mail legal notice, and implemented Open Document Format (ODF) standard.
The full disclaimer details can be found at http://www.csir.co.za/disclaimer.html.

Please consider the environment before printing this email.
Tom Fowle
2017-03-16 02:03:54 UTC
Permalink
I've just figured out what the two settings do, and think I'll will use both
at different times, although probably "reading punc level" mostly.

Tom Fowle
Post by Willem van der Walt
When I read xml or python code etc. I want to be able to hear things
like < / > " = etc.
Without having to review each word.
HTH, Willem
Post by Samuel Thibault
Re,
I agree with what you said, except
Post by Chris Brannon
This also eliminates the distinction between punc_level (punctuation in
spoken output) and reading_punc (punctuation in reviewed text).
Don't users want to keep this distinction? I can understand that you
usually do not want the punctuation, to have a nice flow of text with
prosody, and when reviewing, have the punctuation by default, since
usually you review to get to the details.
Samuel
_______________________________________________
Speakup mailing list
http://linux-speakup.org/cgi-bin/mailman/listinfo/speakup
--
This message is subject to the CSIR's copyright terms and
conditions, e-mail legal notice, and implemented Open Document
Format (ODF) standard. The full disclaimer details can be found at
http://www.csir.co.za/disclaimer.html.
Please consider the environment before printing this email.
_______________________________________________
Speakup mailing list
http://linux-speakup.org/cgi-bin/mailman/listinfo/speakup
Larry Hart
2017-03-15 00:30:12 UTC
Permalink
Well, as a Speakup user, obviously in review, you want to see all of it. Whats
quite interesting, since I am enjoying a DecTalk USB, early after booting or
running this small script,
#!/bin/sh
cd /sys/accessibility/speakup/dectlk
#echo 329 >rate
#echo 113 >pitch
#echo 86 >vol
#echo 0 >punct
#echo '[dv ap 113 pr 250 ]' >caps_stop

#echo '[:dv pr 250 ]' >>direct
#echo "[:dv pr 250]" | sudo tee -a /sys/accessibility/speakup/synth_direct


sudo sh -c 'echo 329 >rate'
sudo sh -c 'echo 113 >pitch'
sudo sh -c 'echo 86 >vol'
sudo sh -c 'echo 0 >punct'
sudo sh -c 'echo "[dv ap 113 pr 250 ]" >caps_stop'

sudo sh -c 'echo "[:dv pr 250 ]" >>direct'
sudo sh -c 'echo "[:dv pr 250]" >> /sys/accessibility/speakup/synth_direct'
Back again live: Another Speakup user wrote most of that for me, which also
increases an inflection for the DecTalk.
So early after booting, it reads a little faster without pauses ignoring
punctuation. As an example it would say
"Pine 464"
But after the pitch, rate, and volume drop, it will read
"Pine 4 point 6 4"
I would much prefer hearing single digit numbers.
Anyway, I hope some of those patches will help the DecTalk. Thanks so much in
advance
Hart
Loading...