If you use this script to switch the keyboard, the existing keyboard will be hidden.
How can I change the beta version to use with the existing keyboard?
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 = (0,10,380,250) tv.font = ('Arial Rounded MT Bold',20) tv.text = 'aé😢🇯🇵👨👨👧👧' v.add_subview(tv) def say_char(tv): # test speech character at cursor idxtopos = IndexToPos('') # list index to position i = tv.selected_range #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(i): tvo = ObjCInstance(tv) p1 = tvo.positionFromPosition_offset_(tvo.beginningOfDocument(), i) p2 = p1 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(type): tvo = ObjCInstance(tv) # build array index -> position in range idxtopos =  pre_x = -1 #print(tv.text) 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 # 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(i) return idxtopos b_top = ui.Button() b_top.frame = (285,302,94,41) b_top.title = '文頭' b_top.background_color = 'white' b_top.border_width = 1 def b_top_action(sender): tv = sender.superview['TextView'] tv.selected_range = (0,0) b_top.action = b_top_action v.add_subview(b_top) b_left = ui.Button() b_left.frame = (190,262,94,41) b_left.title = '⬅︎' b_left.background_color = 'white' b_left.border_width = 1 def b_left_action(sender): idxtopos = IndexToPos('left') # list index to position b_left.action = b_left_action v.add_subview(b_left) b_right = ui.Button() b_right.frame = (285,262,94,41) b_right.title = '➡︎' b_right.background_color = 'white' b_right.border_width = 1 def b_right_action(sender): idxtopos = IndexToPos('right') # list index to position b_right.action = b_right_action v.add_subview(b_right) b_bottom = ui.Button() b_bottom.frame = (190,302,94,41) b_bottom.title = '文末' b_bottom.background_color = 'white' b_bottom.border_width = 1 def b_bottom_action(sender): idxtopos = IndexToPos('end') # list index to position b_bottom.action = b_bottom_action v.add_subview(b_bottom) def get_xy(tv): idxtopos = IndexToPos('') # 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 = (0,262,94,41) b_up.title = '⬆︎' b_up.background_color = 'white' b_up.border_width = 1 def b_up_action(sender): tv = sender.superview['TextView'] x_y = get_xy(tv) c = tv.selected_range 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(i) return i = i - 1 b_up.action = b_up_action v.add_subview(b_up) b_down = ui.Button() b_down.frame = (95,262,94,41) b_down.title = '⬇︎' b_down.background_color = 'white' b_down.border_width = 1 def b_down_action(sender): tv = sender.superview['TextView'] idxtopos = IndexToPos('') # list index to position x_y = get_xy(tv) c = tv.selected_range #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(i) return else: if (i+1) < len(idxtopos): if x_y[i+1] > y: # i = last character of row under cursor selected_range(i) return else: pass # try next x else: # last character of last row selected_range(i) return i = i + 1 b_down.action = b_down_action v.add_subview(b_down) b_copy = ui.Button() b_copy.frame = (95,302,94,41) b_copy.title = 'copy' b_copy.background_color = 'white' b_copy.border_width = 1 def b_copy_action(sender): tv = sender.superview['TextView'] clipboard.set(tv.text) b_copy.action = b_copy_action v.add_subview(b_copy) b_clear = ui.Button() b_clear.frame = (0,302,94,41) b_clear.title = 'clear' b_clear.background_color = 'white' b_clear.border_width = 1 def b_clear_action(sender): tv = sender.superview['TextView'] 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) def nextSet(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 = vv_array[i_set] tvo = tv.objc_instance #print(dir(tvo)) tvo.setInputAccessoryView_(ObjCInstance(ww)) tvo.reloadInputViews() #create normal keys d = 32 dd = 4 emojis = '😊😜😱💦☔️(笑)☀️☁️☃️❄️🍙🍔🚗🌈⭐️😀😃😄😁😆😅😂🤣☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛😝😜🤪🤨🧐🤓😎🤩🥳😏😒😞😔😟😕🙁☹️😣😖😫😩🥺😢😭😤😠😡🤬🤯😳🥵🥶😨😰😥😓🤗🤔🤭🤫🤥😶😐😑😬😦😧😮😲😴' n_emojis_in_set = 10 n_sets = 1 + int((len(emojis)-1)/n_emojis_in_set) 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 = nextSet b.i_set = i_set b.n_sets = n_sets b.name = 'nextSet' else: 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 vv.frame = (0,0,w,h) vv_array.append(vv) i_set = 0 nextSet(vv_array[n_sets-1]['nextSet']) # display 1st setet) v.present('sheet') tv.selected_range = (0,0) tv.begin_editing()
I had a full access, but the copy button is invalid.
I can't paste it.
@shinya.ta Very strange. For me, all is ok.
Sure you had already "full access" before or you have just set it on?
If just set, please remove (NOT UNINSTALL) Pythonista from active apps and restart it.
Sure you select something in the text, try first with normal copy in popup menu of select.
Then, select something else and copy via our keyboard
You can't use it on email software or LINE that you often use.
I was able to use it in the text view of the previous cursor moving application.
@shinya.ta Are you sure that you have installed the last version?
If yes, the ⏩ key should work fine.
If it does not work, then you should have forgotten to install the last version.
If yes, I want to be sure that that you hope that the "copy" button copies TO the clipboard, and does not perform a paste FROM the clipboard.
I was able to use it in the text view of the previous cursor moving application.
The previous cursor moving application was a "full Pythonista" application and did not need this setting "full access" but this is a keyboard application and needs to be authorized to copy some selected text (from Email by example) to the Clopboard.
I'm not sure but it is possible that, if you modify a setting, you need to restart (NOT REINSTALL) Pythonista, that will say remove it from the active apps and recall it.
Did you do that?
new version with check full access
this is the same version but the title of the copy button will be "no full" if Pythonista setting "full access" is off
But it wasn't good.
It was the same as the previous cursor moving application, and it was the same as when I was using the Japanese voice. It was normal on my wife's iPhone.
But it wasn't good on my iPhone.
It is certain that it is slightly different depending on the device.
@shinya.ta I hope you have installed the new version.
And do you see the text "copy" or "no full"?
Is the new version "330015"?
@shinya.ta I speak of the new version of the Pythonista script...Emojis keyboard
And stay in 330014
@shinya.ta could you test this little script as keyboard and tell me if you
get "qwerty" if tap on "copy" and the tap paste key
import keyboard import clipboard import ui v = ui.View() b = ui.Button() b.frame = (2,2,60,32) b.title = 'copy' def b_action(sender): t = 'qwerty' clipboard.set(t) b.action = b_action v.add_subview(b) keyboard.set_view(v, 'expanded')
@shinya.ta Check your script, you forgot the first line "import keyboard" 😢
@shinya.ta Then the problem you have is not due to the device.
I think you did something wrong.
set setting/Pythonista/keyboards/authorize full access to OFF
close the keyboard app
choose Emojis Keyboard
The script should show the copy button with "no full" as title
Be careful, sometimes we need to close a keyboard, choose another one, close it and re-choose the tested one...
A keyboard seems to stay a little bit too long in memory
I don't understand the meaning of the Emoji keyboard.
@shinya.ta ok, sorry, that's the name I gave to this keyboard...
@shinya.ta Forget the last check that I have asked. If the little script for copy "QWERTY" works fine, that will say that the setting "full access" is ON thus my last request is useless.
Thus, the only reason I still see for the problem of copy is that you could have not installed the last version of my script. here
I installed the last version, but the result doesn't change.
I don't know why.
Could you install this little script as keyboard.
Then , you select a text where you want, tap the "copy" button and paste the clipboard to check if the action does work.
When you have tested the little script two days ago, it worked with "qwerty", now we check if it works with selected text, just to be sure that the get_selected_text works.
import keyboard import clipboard import ui v = ui.View() b = ui.Button() b.frame = (2,2,60,32) b.title = 'copy' def b_action(sender): t = keyboard.get_selected_text() clipboard.set(t) b.action = b_action v.add_subview(b) keyboard.set_view(v, 'expanded')
@shinya.ta I have exactly the same problem.
If I use my little keyboard script in Mail, it is not ok, it if I use it in Pythonista editor, it works.
It is like if Clipboard of Pythonista keyboard is not the same as another app's keyboard.
I don't know
I've created an issue in the bugs list of a Pythonista, hoping @omz would process it.