Forum Archive

IPhone doesn't make speech.

shinya.ta

I use the following programs for my wife's wife's iPhone for the visually impaired.

My wife's iPhone seven s max is going to give a speech.

However, I don't make speech in my iPhone XS Max.

Is this due to the difference in the device?

import ui
from objc_util import *
import clipboard
import speech

v = ui.View()
v.frame = (0,0,500,320)
v.name = 'Move cursor in TextView'

tv = ui.TextView()
tv.name = 'TextView'
tv.frame = (120,10,370,140)
tv.font = ('Arial Rounded MT Bold',20)
tv.text = 'aรฉ๐Ÿ˜ข๐Ÿ‡ฏ๐Ÿ‡ต๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฉโ€๐ŸŽจ'
v.add_subview(tv)

tv2 = ui.TextView()
tv2.name = 'TextView2'
tv2.frame = (120,160,370,140)
tv2.font = ('Arial Rounded MT Bold',24)
tv2.text = 'second'
v.add_subview(tv2)

def say_char(tv):
    # test speech character at cursor
    idxtopos = IndexToPos(tv,'') # list index to position
    i = tv.selected_range[0]
    #print(i,idxtopos)
    i = idxtopos[i] # used to check if same base character
    if i < len(tv.text):
        c = tv.text[i]
        if c == ' ':
            c ='space'
        speech.say(c,'jp-JP')

def selected_range(tv,i):
    tvo = ObjCInstance(tv)
    p1 = tvo.positionFromPosition_offset_(tvo.beginningOfDocument(), i)
    p2 = p1
    #p2 = tvo.positionFromPosition_offset_(tvo.beginningOfDocument(), i+1)
    tvo.selectedTextRange = tvo.textRangeFromPosition_toPosition_(p1, p2)
    say_char(tv)
    return

# some emoji like flags count as 2 for len but as 4 for selected_range
def IndexToPos(tv,type):
    tvo = ObjCInstance(tv)
    # build array index -> position in range
    idxtopos = []
    pre_x = -1
    #print(tv.text)
    i = 0
    for c in tv.text:
      # nbr characters used e=1 รฉ=1 ๐Ÿ˜‚=1 ๐Ÿ‡ฏ๐Ÿ‡ต=2 ๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง=7
      # some emoji generate more than one character, 
      # sometimes counted for more than one in range
      # 1,2,3->1  4->2
      nb = 1 + int(len(c.encode('utf-8'))/4)
      for j in range(0,nb):
        p1 = tvo.positionFromPosition_offset_(tvo.beginningOfDocument(), len(idxtopos))
        p2 = p1
        rge = tvo.textRangeFromPosition_toPosition_(p1, p2)
        rect = tvo.firstRectForRange_(rge)  # CGRect
        x = rect.origin.x
        if x == float('inf') or x == pre_x:
          # same x as previous one, composed character
          pass
        else:
          pre_x = x
          i = len(idxtopos)
        idxtopos.append(i)                      # start position of c
      #print(c,nb,len(idxtopos)-1,i,x)
    idxtopos.append(i+1)                            # end position of last c
    #print(idxtopos)
    # get index of actual cursor
    i = tv.selected_range[0]                # actual position of cursor
    # often p is one of sub_chars, not always the first one
    p = idxtopos[i]                                 # used to check if same base character
    #print(p,i,idxtopos)
    if type == 'left':
      if i == 0:
        return                                              # already before character
      while True:
        i = i - 1
        if idxtopos[i] != p:
          q = idxtopos[i]
          # seach first sub-character
          while i > 0:
            if idxtopos[i-1] != q:
              break
            i = i - 1
        break
    elif type == 'right':
      if i == (len(idxtopos)-1):
        return                                              # already after last character
      while True:
        i = i + 1
        if idxtopos[i] != p:
          break
    elif type == 'end':
      i = len(idxtopos)-1
    else:
      return idxtopos
    r = idxtopos[i]
    selected_range(tv,i)
    return idxtopos

b_top = ui.Button()
b_top.frame = (10,10,100,32)
b_top.title = 'begin'
b_top.background_color = 'white'
b_top.border_width = 1
def b_top_action(sender):
    name = str(ObjCClass('UIApplication').sharedApplication().keyWindow().firstResponder().name())
    tv = sender.superview[name]
    tv.selected_range = (0,0)
    say_char(tv)
b_top.action = b_top_action
v.add_subview(b_top)

b_left = ui.Button()
b_left.frame = (10,50,100,32)
b_left.title = 'left'
b_left.background_color = 'white'
b_left.border_width = 1
def b_left_action(sender):
    name = str(ObjCClass('UIApplication').sharedApplication().keyWindow().firstResponder().name())
    tv = sender.superview[name]
    idxtopos = IndexToPos(tv,'left')        # list index to position
b_left.action = b_left_action
v.add_subview(b_left)

b_right = ui.Button()
b_right.frame = (10,90,100,32)
b_right.title = 'right'
b_right.background_color = 'white'
b_right.border_width = 1
def b_right_action(sender):
    name = str(ObjCClass('UIApplication').sharedApplication().keyWindow().firstResponder().name())
    tv = sender.superview[name]
    idxtopos = IndexToPos(tv,'right')       # list index to position
b_right.action = b_right_action
v.add_subview(b_right)

b_bottom = ui.Button()
b_bottom.frame = (10,130,100,32)
b_bottom.title = 'end'
b_bottom.background_color = 'white'
b_bottom.border_width = 1
def b_bottom_action(sender):
    name = str(ObjCClass('UIApplication').sharedApplication().keyWindow().firstResponder().name())
    tv = sender.superview[name]
    idxtopos = IndexToPos(tv,'end')     # list index to position
b_bottom.action = b_bottom_action
v.add_subview(b_bottom)

def get_xy(tv):
    idxtopos = IndexToPos(tv,'')        # list index to position
    tvo = ObjCInstance(tv)
    x_y = []
    for i in range(0,len(idxtopos)+1):  # x,y of each character
      p1 = tvo.positionFromPosition_offset_(tvo.beginningOfDocument(), i)
      rge = tvo.textRangeFromPosition_toPosition_(p1,p1)
      rect = tvo.firstRectForRange_(rge)    # CGRect
      x,y = rect.origin.x,rect.origin.y
      if i == len(idxtopos):
        if i > 0:
          x,y = x_y[i-1]
        else:
          # text is empty
          x,y = 0,0
      if x == float('inf'):
        x,y = x_prec+15,y_prec
      x_prec,y_prec = x,y
      x_y.append((x,y))
    return x_y

b_up = ui.Button()
b_up.frame = (10,170,100,32)
b_up.title = 'up'
b_up.background_color = 'white'
b_up.border_width = 1
def b_up_action(sender):
    name = str(ObjCClass('UIApplication').sharedApplication().keyWindow().firstResponder().name())
    tv = sender.superview[name]
    x_y = get_xy(tv)
    c = tv.selected_range[0] 
    xc,yc = x_y[c]
    i = c - 1
    while i >=  0:
      x,y = x_y[i]
      if y < yc:
        # previous row
        if x <= xc:
          selected_range(tv,i)
          return
      i = i - 1
b_up.action = b_up_action
v.add_subview(b_up)

b_down = ui.Button()
b_down.frame = (10,210,100,32)
b_down.title = 'down'
b_down.background_color = 'white'
b_down.border_width = 1
def b_down_action(sender):
    name = str(ObjCClass('UIApplication').sharedApplication().keyWindow().firstResponder().name())
    tv = sender.superview[name]
    idxtopos = IndexToPos(tv,'')        # list index to position
    x_y = get_xy(tv)
    c = tv.selected_range[0] 
    #print(x_y,c)
    xc,yc = x_y[c]
    i = c# - 1          # I don't remember why this "- 1"
    while i < len(idxtopos):
      x,y = x_y[i]
      if y > yc:
        # next row
        if x >= xc:
          selected_range(tv,i)
          return
        else:
          if (i+1) < len(idxtopos):
            if x_y[i+1][1] > y: # i = last character of row under cursor
              selected_range(tv,i)
              return
            else:
              pass  # try next x
          else:
            # last character of last row
            selected_range(tv,i)
            return
      i = i + 1
b_down.action = b_down_action
v.add_subview(b_down)

b_copy = ui.Button()
b_copy.frame = (10,250,100,32)
b_copy.title = 'copy'
b_copy.background_color = 'white'
b_copy.border_width = 1
def b_copy_action(sender):
    name = str(ObjCClass('UIApplication').sharedApplication().keyWindow().firstResponder().name())
    tv = sender.superview[name]
    clipboard.set(tv.text)
b_copy.action = b_copy_action
v.add_subview(b_copy)

b_clear = ui.Button()
b_clear.frame = (10,290,100,32)
b_clear.title = 'clear'
b_clear.background_color = 'white'
b_clear.border_width = 1
def b_clear_action(sender):
    name = str(ObjCClass('UIApplication').sharedApplication().keyWindow().firstResponder().name())
    tv = sender.superview[name]
    tv.text = ''
b_clear.action = b_clear_action
v.add_subview(b_clear)

def typeChar(sender):
    '''finds active textinput, and types the button's title'''
    tf=sender.objc_instance.firstResponder()
    tf.insertText_(sender.title)

#create special keys
def prev(sender):
    '''simulates 'tab' key, go to next field '''

    s=sender.objc_instance.firstResponder()._previousKeyResponder().becomeFirstResponder()
    buttons.append(ui.Button(image=ui.Image.named('iob:ios7_arrow_back_32'),action=prev))

def next(sender):
    '''simulates 'tab' key, go to next field '''
    s=sender.objc_instance.firstResponder()._nextKeyResponder().becomeFirstResponder()
    buttons.append(ui.Button(image=ui.Image.named('iob:ios7_arrow_forward_32'),action=next))


#create normal keys
d = 32
dd = 4
emojis = '๐Ÿ˜Š๐Ÿ˜œ๐Ÿ˜ฑ๐Ÿ’ฆโ˜”๏ธ๐Ÿ˜€๐Ÿ˜ƒ๐Ÿ˜„๐Ÿ˜๐Ÿ˜†๐Ÿ˜…๐Ÿ˜‚๐Ÿคฃโ˜บ๏ธ๐Ÿ˜Š๐Ÿ˜‡๐Ÿ™‚๐Ÿ™ƒ๐Ÿ˜‰๐Ÿ˜Œ๐Ÿ˜๐Ÿฅฐ๐Ÿ˜˜๐Ÿ˜—๐Ÿ˜™๐Ÿ˜š๐Ÿ˜‹๐Ÿ˜›๐Ÿ˜๐Ÿ˜œ๐Ÿคช๐Ÿคจ๐Ÿง๐Ÿค“๐Ÿ˜Ž๐Ÿคฉ๐Ÿฅณ๐Ÿ˜๐Ÿ˜’๐Ÿ˜ž๐Ÿ˜”๐Ÿ˜Ÿ๐Ÿ˜•๐Ÿ™โ˜น๏ธ๐Ÿ˜ฃ๐Ÿ˜–๐Ÿ˜ซ๐Ÿ˜ฉ๐Ÿฅบ๐Ÿ˜ข๐Ÿ˜ญ๐Ÿ˜ค๐Ÿ˜ ๐Ÿ˜ก๐Ÿคฌ๐Ÿคฏ๐Ÿ˜ณ๐Ÿฅต๐Ÿฅถ๐Ÿ˜ฑ๐Ÿ˜จ๐Ÿ˜ฐ๐Ÿ˜ฅ๐Ÿ˜“๐Ÿค—๐Ÿค”๐Ÿคญ๐Ÿคซ๐Ÿคฅ๐Ÿ˜ถ๐Ÿ˜๐Ÿ˜‘๐Ÿ˜ฌ๐Ÿ˜ฆ๐Ÿ˜ง๐Ÿ˜ฎ๐Ÿ˜ฒ๐Ÿ˜ด๐Ÿคค๐Ÿ˜ช๐Ÿ˜ต๐Ÿค๐Ÿฅด๐Ÿคข๐Ÿคฎ๐Ÿคง๐Ÿ˜ท๐Ÿค’๐Ÿค•๐Ÿค‘๐Ÿค ๐Ÿ˜ˆ'
n_emojis_in_set = 10
n_sets = 1 + int((len(emojis)-1)/n_emojis_in_set)

tv.i_set = 0
tv.n_sets = n_sets
def nextSet(sender):
    name = str(ObjCClass('UIApplication').sharedApplication().keyWindow().firstResponder().name())
    tv = v[name]
    tv.i_set = tv.i_set + 1
    if tv.i_set == tv.n_sets:
        tv.i_set = 0
    #attach our accessory to the textfield, and textview
    ww = vv_array[tv.i_set]
    tvo = tv.objc_instance
    #print(dir(tvo))
    tvo.setInputAccessoryView_(ObjCInstance(ww))
    tvo.reloadInputViews()

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)
        b_action = 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
    device = ObjCClass('UIDevice').currentDevice().model()
    if str(device) == 'iPhone':
        bb_target = ui.Button()
        bb_target.title = 'next emojis'
        wb,hb = ui.measure_string(bb_target.title,font=bb_target.font)
        bb_target.action = nextSet
        bb_target.frame = (dd,h,wb+2,d)
        vv.add_subview(bb_target)
        h = h + d + dd
    vv.frame = (0,0,w,h)
    vv_array.append(vv)

#nextSet(vv_array[n_sets-1]['nextSet']) # display 1st set

device = ObjCClass('UIDevice').currentDevice().model()
if str(device) == 'iPad':
    # add a button at right of "typing suggestions", just above the keyboard
    bb_target = ui.Button()
    bb_target.action = nextSet

    UIBarButtonItem = ObjCClass('UIBarButtonItem').alloc().initWithTitle_style_target_action_('next emojis',0,bb_target,sel('invokeAction:')).autorelease()
    #UIBarButtonItem = ObjCClass('UIBarButtonItem').alloc().initWithImage_style_target_action_(ns(ui.Image.named('emj:Bicycle').with_rendering_mode(ui.RENDERING_MODE_ORIGINAL)),0,bb_target,sel('invokeAction:')).autorelease()

    UIBarButtonItemGroup = ObjCClass('UIBarButtonItemGroup').alloc().initWithBarButtonItems_representativeItem_([UIBarButtonItem],None)

for tv in v.subviews:
    if 'TextView' in str(type(tv)):
        tv.i_set = 0
        tv.n_sets = n_sets

        tvo = tv.objc_instance

        if str(device) == 'iPad':
            #tvo.inputAssistantItem().setTrailingBarButtonGroups([UIBarButtonItemGroup])
            tvo.inputAssistantItem().setLeadingBarButtonGroups([UIBarButtonItemGroup])
            #print(dir(tvo))
            #print(dir(tvo.inputAssistantItem()))

        ww = vv_array[tv.i_set]
        tvo.setInputAccessoryView_(ObjCInstance(ww))
        tvo.reloadInputViews()
v.present('sheet')
v['TextView'].selected_range = (0,0)
v['TextView'].begin_editing()
#nextSet(vv_array[n_sets-1]['nextSet']) # display 1st set
cvp

@shinya.ta I sincerely hope somebody will help you. I have a very old iPhone 5s and the script does not work on it...

bennr01

Hi, have you checked the physical mute switch on your phone? There should be a switch near the volume buttons, which, wenn activated, mutes specific sounds including most of pythonista sounds.

shinya.ta

@bennr01

It was nothing to do with the mute button.

In iPhone seven, this program is activated, and in the case of the current program, it is not responding to Xs Max.

cvp

@shinya.ta Just to test the speech function on your XS Max, please try this

import speech
t = 'hello'
speech.say(t)
shinya.ta

@cvp

Dear.

I tried the test.
I tried it with a new file for the test, but I didn't make a speech.

cvp

@shinya.ta Then we are sure that the reason of "no speech" is not my big script.
Perhaps the iPhone has a problem?

shinya.ta

@cvp

Even if my wife's iPhone and all the same programs are used, my wife makes speech, but I don't make speech on my iPhone.

I have a problem with my iPhone.