Forum Archive

New button addition.

shinya.ta

I want to add a new button.
All Text Reading Buttons.
Then, from the beginning of the text, it is the button to read the position of the cursor.
Is it possible?

```
import keyboard
import ui
from objc_util import *
import clipboard
import speech
import sys

import time
import threading

class MyView(ui.View):
def init(self, args, kwargs):
super().init(self,
args, **kwargs)
self.background_color = 'lightgray'

    # bounds not yet known in init, let some delay      
    ui.delay(self.dimensions,0.1)

def dimensions(self):               
    w,h = self.bounds.size

    h_icons = 40

    dd = 2
    d = (h-4*dd-h_icons)/3
    x0 = (w -3*d - 2*dd)/2

    x = x0 - d/2
    y = h_icons + dd        
    b_top = ui.Button()
    b_top.frame = (x,y,d,d)
    b_top.corner_radius = d/4
    b_top.title = '文頭' # begin of sentence
    b_top.background_color = 'white'
    b_top.border_width = 1
    def b_top_action(sender):
        t = keyboard.get_input_context()    # current line
        l = len(t[0])
        keyboard.move_cursor(-l)
    b_top.action = b_top_action
    self.add_subview(b_top)

    x = x0 + 1 * (d + dd)
    y = h_icons + dd
    b_up = ui.Button()
    b_up.frame = (x,y,d,d)
    b_up.corner_radius = d/4
    b_up.title = '⬆️'
    b_up.background_color = 'white'
    b_up.border_width = 1
    def b_up_action(sender):
        t = keyboard.get_input_context()    # current line
        l0 = len(t[0])
        l1 = len(t[1])
        keyboard.move_cursor(-l0)
        keyboard.move_cursor(-1)                    # end of previous line
        t = keyboard.get_input_context()    # previous line
        l2 = len(t[0])
        l3 = len(t[1])
        #sender.title = str(l0)+' '+str(l1)+' '+str(l2)+' '+str(l3)
        if l2 >= l0:
            keyboard.move_cursor(-(l2-l0))
        else:
            pass                                            # line is shorter than l0, thus stay at end
    b_up.action = b_up_action
    self.add_subview(b_up)

    x = x0
    y = h_icons + dd + 1 * (d + dd)
    b_left = ui.Button()
    b_left.frame = (x,y,d,d)
    b_left.corner_radius = d/4
    b_left.title = '⬅️'
    b_left.background_color = 'white'
    b_left.border_width = 1
    def b_left_action(sender):
        keyboard.move_cursor(-1)
    b_left.action = b_left_action
    self.add_subview(b_left)
    x = x0 + 1 * (d + dd)
    y = h_icons + dd + 1 * (d + dd)
    b_bottom = ui.Button()
    b_bottom.frame = (x,y,d,d)
    b_bottom.corner_radius = d/4
    b_bottom.title = '文末'   # end of sentence
    b_bottom.background_color = 'white'
    b_bottom.border_width = 1
    def b_bottom_action(sender):
        t = keyboard.get_input_context()    # current line
        l = len(t[1])
        keyboard.move_cursor(+l)
        move = my_thread(1)
        move.start()
    b_bottom.action = b_bottom_action
    self.add_subview(b_bottom)

    x = x0 + 2 * (d + dd)
    y = h_icons + dd + 1 * (d + dd)
    b_right = ui.Button()
    b_right.frame = (x,y,d,d)
    b_right.corner_radius = d/4
    b_right.title = '➡️'
    b_right.background_color = 'white'
    b_right.border_width = 1
    def b_right_action(sender):
        keyboard.move_cursor(+1)
    b_right.action = b_right_action
    self.add_subview(b_right)

    x = x0 - d/2
    y = h_icons + dd + 2 * (d + dd)     
    b_copy = ui.Button()
    b_copy.frame = (x,y,d,d)
    b_copy.corner_radius = d/4
    if keyboard.has_full_access():
        b_copy.title = 'copy'
    else:
        b_copy.title = 'no full'            
    b_copy.background_color = 'white'
    b_copy.border_width = 1
    def b_copy_action(sender):
        t = keyboard.get_selected_text()
        clipboard.set(t)
    b_copy.action = b_copy_action
    self.add_subview(b_copy)

    x = x0 + 1 * (d + dd)
    y = h_icons + dd + 2 * (d + dd)
    b_down = ui.Button()
    b_down.frame = (x,y,d,d)
    b_down.corner_radius = d/4
    b_down.title = '⬇️'
    b_down.background_color = 'white'
    b_down.border_width = 1
    def b_down_action(sender):
        t = keyboard.get_input_context()    # current line
        l0 = len(t[0])
        l1 = len(t[1])
        keyboard.move_cursor(l1)
        keyboard.move_cursor(1)                     # begin of next line
        t = keyboard.get_input_context()    # next line
        l2 = len(t[0])
        l3 = len(t[1])
        if (l2+l3) >= l0:
            keyboard.move_cursor(l0)
        else:
            pass
            #keyboard.move_cursor(2)#l0-l2)
    b_down.action = b_down_action
    self.add_subview(b_down)

    x = x0 + 2 * (d + dd) + dd + d/2
    y = h_icons + dd + 2 * (d + dd)
    b_delete = ui.Button()
    b_delete.frame = (x,y,d,d)
    b_delete.corner_radius = d/4
    b_delete.title = '左削除'  # delete
    b_delete.background_color = 'white'
    b_delete.border_width = 1
    def b_delete_action(sender):
        keyboard.backspace(times=1)
    b_delete.action = b_delete_action
    self.add_subview(b_delete)

    d = 32
    dd = 4
    w_buttons = 0

    #create normal keys
    emojis = '😊😜😱💦☔️(笑)☀️☁️☃️❄️🍙🍔🚗🌈⭐️😀😃😄😁😆😅😂🤣☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛😝😜🤪🤨🧐🤓😎🤩🥳😏😒😞😔😟😕🙁☹️😣😖😫😩🥺😢😭😤😠😡🤬🤯😳🥵🥶😨😰😥😓🤗🤔🤭🤫🤥😶😐😑😬😦😧😮😲😴'
    n_emojis_in_set = 10
    n_sets = 1 + int((len(emojis)-1)/n_emojis_in_set)
    self.vv_array = []
    for i_set in range(0,n_sets):
        l = int(len(emojis)/n_sets)
        i = i_set * l
        set_emojis = emojis[i:i+l] + '⏩'
        w, h = ui.get_screen_size() 
        vv = ui.View(name='set'+str(i_set))
        vv.background_color = 'lightgray'
        h = 0
        x = dd
        y = dd
        for button_title in set_emojis:
            b = ui.Button(title=button_title)
            if button_title == '⏩':
                b_action = self.nextSet
                b.i_set = i_set
                b.n_sets = n_sets
                b.name = 'nextSet'
            else:
                b_action = self.typeChar
            b.action=b_action
            b.frame = (x,y,d,d)
            b.font = ('.SFUIText', d)
            if (y+d+dd) > h:
                h = y + d + dd
            vv.add_subview(b)
            x = x + d + dd
            if (x+d+dd) > w:
                x = dd
                y = y + d + dd
        vv.frame = (w_buttons,0,w-w_buttons,h)
        self.vv_array.append(vv)
        self.add_subview(vv)

    i_set = 0
    self.nextSet(self.vv_array[n_sets-1]['nextSet'])  # display 1st set

def typeChar(self,sender):
    keyboard.insert_text(sender.title)

def nextSet(self,sender):
    i_set = sender.i_set + 1
    if i_set == sender.n_sets:
        i_set = 0
    #attach our accessory to the textfield, and textview
    ww = self.vv_array[i_set]
    ww.bring_to_front()

def main():
if not keyboard.is_keyboard():
return
v = MyView()
keyboard.set_view(v, 'expanded')

if name == 'main':
main() ```

ccc

You might be able to reduce repetitive code by adding a self.make_button() method that takes a few parameters and returns a ui.Button.

cvp

@ccc it's not his fault, this is my code and, at the time, he requested one button at a time ...

cvp

@shinya.ta said:

I want to add a new button.
All Text Reading Buttons.
Then, from the beginning of the text, it is the button to read the position of the cursor.
Is it possible?

I understand you want a new button, but I don't understand its function.

What is "all text reading buttons"?

Do you want that the button action displays the position of the cursor? Like row,column?
And, if yes, where to display it?

cvp

@ccc said:

reduce repetitive code by adding a self.make_button() method

But you're right, I'll do it

ccc

My sense was that this was cursor up, down, left, right buttons on the top row of the on-screen keyboard to the right of cut, copy, paste.

JonB

@cvp I gather he wants something to read (text to speech) starting from the cursor...

cvp

@ccc @JonB you could be right, but, please, I want to be sure...

shinya.ta

I'm sorry, I'm not good at English, so I couldn't write well.

I would like you to read the text at the cursor position.
And I want you to read all the text fields in the text field.

cvp

@shinya.ta I understand your language problem, English is not my mother language and I also have a lot of problems of comprehension 😅
Thus, do you want to have two buttons?
One to read the text at the cursor (only one character? One word? All from the cursor?)
A second button to read the entire text?

shinya.ta

All from the cursor.
And the whole text.

cvp

@shinya.ta ok, last (I hope) questions: where do you want these buttons and which title on them?

cvp

@shinya.ta first of all, @ccc advice followed here Emojis Keyboard.py
Please try it, thanks

shinya.ta

Yes, it's necessary for me.

cvp

@shinya.ta said:

Yes, it's necessary for me.

sorry, I don't understand to which questions you answer 🤔

cvp

@shinya.ta I have still an important question: do you use this keyboard in a text field of more than one line? Because Pythonista keyboard module does not support it easily.

shinya.ta

I need this reading button for my wife.

cvp

@shinya.ta i understand why you need it but you don't answer to my questions:
1) where do you want these buttons?
2) which title?
3 ) do you use it in a text field of multiple lines?

Ex:

shinya.ta
  1. I want to have a button here.
  2. It's okay with the title of the picture.
  3. I use it in multiple lines.
cvp

@shinya.ta said:

I want to have a button here.

Sorry, but one more time I don't understand. For the moment, I'll keep "my" positions

cvp

@shinya.ta said:

I use it in multiple lines.

Let us begin with one line at once because Pythonista's keyboard module does not support multiple lines in keyboard.get_input_context() module

cvp

@shinya.ta I've problems with uploading to GitHub, just now, thus, please try this, it works for me in English and for one line, that's just the beginning.

import keyboard
import ui
from objc_util import *
import clipboard
import speech
import sys

import time
import threading

class MyView(ui.View):
    def __init__(self, *args, **kwargs):
        super().__init__(self, *args, **kwargs)
        self.background_color = 'lightgray'

        # bounds not yet known in init, let some delay      
        ui.delay(self.dimensions,0.1)

    def dimensions(self):               
        w,h = self.bounds.size

        h_icons = 40

        dd = 2
        d = (h-4*dd-h_icons)/3
        x0 = (w -3*d - 2*dd)/2

        x = x0 - d/2
        y = h_icons + dd        
        def b_top_action(sender):
            t = keyboard.get_input_context()    # current line
            l = len(t[0])
            keyboard.move_cursor(-l)
        self.d = d
        self.make_button(x,y,d,'文頭',b_top_action) # begin of sentence

        x = x0 + 1 * (d + dd)
        y = h_icons + dd
        def b_up_action(sender):
            t = keyboard.get_input_context()    # current line
            l0 = len(t[0])
            l1 = len(t[1])
            keyboard.move_cursor(-l0)
            keyboard.move_cursor(-1)                    # end of previous line
            t = keyboard.get_input_context()    # previous line
            l2 = len(t[0])
            l3 = len(t[1])
            #sender.title = str(l0)+' '+str(l1)+' '+str(l2)+' '+str(l3)
            if l2 >= l0:
                keyboard.move_cursor(-(l2-l0))
            else:
                pass                                            # line is shorter than l0, thus stay at end
        self.make_button(x,y,d,'⬆️',b_up_action)

        x = x0 + 2 * (d + dd)
        y = h_icons + dd
        def b_read_from_action(sender):
            t = keyboard.get_input_context()
            speech.say(t[1],'jp-JP')
            #speech.say(t[1],'en-EN')
        self.make_button(x,y,d,'read\nfrom',b_read_from_action)

        x = x0 + 3 * (d + dd)
        y = h_icons + dd
        def b_read_all_action(sender):
            keyboard.move_cursor(-1000)
            t = keyboard.get_input_context()
            speech.say(t[1],'jp-JP')
            #speech.say(t[1],'en-EN')
        self.make_button(x,y,d,'read\nall',b_read_all_action)

        x = x0
        y = h_icons + dd + 1 * (d + dd)
        def b_left_action(sender):
            keyboard.move_cursor(-1)
        self.make_button(x,y,d,'⬅️',b_left_action)

        x = x0 + 1 * (d + dd)
        y = h_icons + dd + 1 * (d + dd)
        def b_bottom_action(sender):
            t = keyboard.get_input_context()    # current line
            l = len(t[1])
            keyboard.move_cursor(+l)
            move = my_thread(1)
            move.start()
        self.make_button(x,y,d,'文末',b_bottom_action)   # end of sentence

        x = x0 + 2 * (d + dd)
        y = h_icons + dd + 1 * (d + dd)
        def b_right_action(sender):
            keyboard.move_cursor(+1)
        self.make_button(x,y,d,'➡️',b_right_action)

        x = x0 - d/2
        y = h_icons + dd + 2 * (d + dd)     
        def b_copy_action(sender):
            context = keyboard.get_input_context()
            t = keyboard.get_selected_text()
            clipboard.set(t)
        if keyboard.has_full_access():
            self.make_button(x,y,d,'copy',b_copy_action)
        else:
            self.make_button(x,y,d,'no full',b_copy_action)    

        x = x0 + 1 * (d + dd)
        y = h_icons + dd + 2 * (d + dd)
        def b_down_action(sender):
            t = keyboard.get_input_context()    # current line
            l0 = len(t[0])
            l1 = len(t[1])
            keyboard.move_cursor(l1)
            keyboard.move_cursor(1)                     # begin of next line
            t = keyboard.get_input_context()    # next line
            l2 = len(t[0])
            l3 = len(t[1])
            if (l2+l3) >= l0:
                keyboard.move_cursor(l0)
            else:
                pass
                #keyboard.move_cursor(2)#l0-l2)
        self.make_button(x,y,d,'⬇️',b_down_action)

        x = x0 + 2 * (d + dd) + dd + d/2
        y = h_icons + dd + 2 * (d + dd)
        def b_delete_action(sender):
            keyboard.backspace(times=1)
        self.make_button(x,y,d,'左削除',b_delete_action)  # delete

        d = 32
        dd = 4
        w_buttons = 0

        #create normal keys
        emojis = '😊😜😱💦☔️(笑)☀️☁️☃️❄️🍙🍔🚗🌈⭐️😀😃😄😁😆😅😂🤣☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛😝😜🤪🤨🧐🤓😎🤩🥳😏😒😞😔😟😕🙁☹️😣😖😫😩🥺😢😭😤😠😡🤬🤯😳🥵🥶😨😰😥😓🤗🤔🤭🤫🤥😶😐😑😬😦😧😮😲😴'
        n_emojis_in_set = 10
        n_sets = 1 + int((len(emojis)-1)/n_emojis_in_set)
        self.vv_array = []
        for i_set in range(0,n_sets):
            l = int(len(emojis)/n_sets)
            i = i_set * l
            set_emojis = emojis[i:i+l] + '⏩'
            w, h = ui.get_screen_size() 
            vv = ui.View(name='set'+str(i_set))
            vv.background_color = 'lightgray'
            h = 0
            x = dd
            y = dd
            for button_title in set_emojis:
                b = ui.Button(title=button_title)
                if button_title == '⏩':
                    b_action = self.nextSet
                    b.i_set = i_set
                    b.n_sets = n_sets
                    b.name = 'nextSet'
                else:
                    b_action = self.typeChar
                b.action=b_action
                b.frame = (x,y,d,d)
                b.font = ('.SFUIText', d)
                if (y+d+dd) > h:
                    h = y + d + dd
                vv.add_subview(b)
                x = x + d + dd
                if (x+d+dd) > w:
                    x = dd
                    y = y + d + dd
            vv.frame = (w_buttons,0,w-w_buttons,h)
            self.vv_array.append(vv)
            self.add_subview(vv)  

        i_set = 0
        self.nextSet(self.vv_array[n_sets-1]['nextSet'])  # display 1st set

    def make_button(self,x,y,d,title,action):
        b = ui.Button()
        b.frame = (x,y,d,d)
        b.background_color = 'white'
        b.border_width = 1
        b.corner_radius = self.d/4
        b.title = title
        if '\n' in title:
            bo = ObjCInstance(b)
            for sv in bo.subviews(): 
                if hasattr(sv,'titleLabel'):
                    tl = sv.titleLabel()
                    tl.numberOfLines = 0
        b.action = action
        self.add_subview(b)

    def typeChar(self,sender):
        keyboard.insert_text(sender.title)

    def nextSet(self,sender):
        i_set = sender.i_set + 1
        if i_set == sender.n_sets:
            i_set = 0
        #attach our accessory to the textfield, and textview
        ww = self.vv_array[i_set]
        ww.bring_to_front()

def main():
    if not keyboard.is_keyboard():
        return
    v = MyView()
    keyboard.set_view(v, 'expanded')

if __name__ == '__main__':
    main()
cvp

Github version ok

shinya.ta

It's OK here.
After that it's only reading.

cvp

@shinya.ta said:

After that it's only reading.

Is it not reading in Japanese?

shinya.ta

I don't speak anything.

cvp

@shinya.ta I remember that in the past you met the same problem with the iPhone of your wife.
Could you change in the script, two times,

            speech.say(t[1],'jp-JP')
            #speech.say(t[1],'en-EN')

by

            #speech.say(t[1],'jp-JP')
            speech.say(t[1],'en-EN')

And test it, it should say the text in English, if you type English words, of course
For me, it is ok

And put the cursor in the middle of a line

shinya.ta

I won't talk even if I change it.

cvp

@shinya.ta It seems that you have one more time some problem with the speech module...

cvp

@shinya.ta remember in this topic

shinya.ta

Is there a way to check it?

cvp

@shinya.ta said:

check

You select a word or sentence and you do a long press, you will have a pop up menu with
speak and spell, like here in French énoncer and épeler.
Tap one and you should hear the text

shinya.ta

There is no speech item.

cvp

@shinya.ta said:

There is no speech item.

Did you check your iOS settings?

shinya.ta

I don't know the setting.

cvp

@shinya.ta iOS settings: accessibility, what I see in French, but I suppose same rows

shinya.ta

It's done.
But the Pythonista button doesn't work.

cvp

@shinya.ta sure your volume is set 🙄

shinya.ta

What is volume?
Where is it?

cvp

@shinya.ta in control center, with a speaker as symbol

Volume = sound intensity

cvp

@shinya.ta does this script say something? For me, only English works

import speech
speech.say('hello','en-En')
speech.say('こんにちは','jp-Jp')
shinya.ta

I read it.
But what should I do with the button of the application?

cvp

@shinya.ta when you try the keyboard app, is there a text after your cursor?

shinya.ta

I have text, but the button doesn't say anything.

cvp

@shinya.ta in the little script of three lines, do you hear the text in English AND in Japanese?

shinya.ta

@cvp

I can only hear it in Japanese.

cvp

@shinya.ta ok, thus the say function of Pythonista works, thus the "read" buttons should work

cvp

@shinya.ta I can't easily help you more if the little script reads in Japanese but the big one does not...I'm very sorry

cvp

@shinya.ta do you have some news about your problem?

esme_02

I need this button. No doubt it is very helpful. @lab