You are not logged in.

#1 2023-07-18 22:03:29

kes
Member
Registered: 2017-12-12
Posts: 35

Convert GUI text selections, in place, from UPPER to lower case, etc

Often I need to change the case of selected text that is the wrong case in applications such as
libreoffice writer, google docs or gedit, etc

eg I select the text "THE BRIGHT DAY" and wish to change it with some simple keybinding to "the bright day".

Below I have implemented very simple command line tools called by Openbox key bindings to change the case as desired.

These are stored in Openbox's keybindings/ set-up file `rc.xml` file as shown below.


Although these work when going from upper to lower case, by pressing Fn + Ctrl together followed by "l" (for lower case) on my Thinkpad T440s, it replaces "IT'S" with "itNs" because of a limitation in xdotool.

I'm wondering if this can be done more neatly with "xclip" or "xsel" or some another way.

It's very handy to have universal keybindings for changing the case of any selected text.


######################################   
########## c-fn - key chain ##########  
######################################   

# PRESS Fn + Ctrl then "l", or "u", or "i" on Thinkpad T440s

<keybind key="c-XF86WakeUp">

# change selected text to lowercase
     <keybind key="l"><action name="execute"><command>bash -c '
     clip_zz="$(echo $(xsel) | awk '\''{print tolower($0)}'\'')";
     xdotool type --clearmodifiers -- "$clip_zz"
     '</command></action></keybind>

# CHANGE SELECTED TEXT TO UPPERCASE 
     <keybind key="u"><action name="execute"><command>bash -c '
     clip_zz="$(echo $(xsel) | awk '\''{print toupper($0)}'\'')";
     xdotool type --clearmodifiers -- "$clip_zz"
     '</command></action></keybind>

# Change Selected Text To Sentence Case Like This With Each Words First Letter Being Capatalised
     <keybind key="i"><action name="execute"><command>bash -c '
     clip_zz="$(echo $(xsel) | awk '\''{print tolower($0)}'\'' | sed '\''s@\([[:lower:]]\)\([[:alnum:]]*\)@\u\1\2@g'\'')";
     xdotool type --clearmodifiers -- "$clip_zz"
     '</command></action></keybind>

</keybind>

Last edited by kes (2023-07-18 22:07:21)

Offline

#2 2023-07-19 07:36:20

brontosaurusrex
Middle Office
Registered: 2015-09-29
Posts: 2,744

Re: Convert GUI text selections, in place, from UPPER to lower case, etc

Thanks for sharing, trying to do upper, lower and first letter upper in bash (at least bash 4 is needed):

#!/bin/bash

string="abc def"

# lower
clip="${string,,}"; echo "lower: $clip"

# Upper
clip="${string^^}"; echo "upper: $clip"

# capital 1st letter
IFS=" " read -r -a array <<< "$string"; cliparr=( "${array[@]^*}" ); echo "capital: ${cliparr[*]}"

should return

lower: abc def
upper: ABC DEF
capital: Abc Def

About the missing ', maybe test 'xdotool key' instead of 'xdotool type' (untested by me).

Last edited by brontosaurusrex (2023-07-19 07:42:45)

Offline

#3 2023-07-19 10:05:22

kes
Member
Registered: 2017-12-12
Posts: 35

Re: Convert GUI text selections, in place, from UPPER to lower case, etc

Thanks,

if you try an Openbox keybinding for any of these with an appication like google docs the simple `echo` solution does not work. At least not with my set-up.

The selected text has first to be pulled onto the system clipboard using `xsel` or `xclip`, perhaps using

clip="$(echo $(xsel))"

Then the contents of the clipboard changed using eg

clip="${clip,,}";

Then possibly pasting the modified clipbord back in, though after extensive testing I couldn't work out how to do that yesterday, which is why I ended up using xdotool.
Using Xdotool `type` seems would be a convoluted solution.

Seems clipboards must be used.

Last edited by kes (2023-07-19 13:56:11)

Offline

#4 2023-07-19 10:45:38

brontosaurusrex
Middle Office
Registered: 2015-09-29
Posts: 2,744

Re: Convert GUI text selections, in place, from UPPER to lower case, etc

Just trying to write a lil subset that possibly replaces awk/sed, haven't tested anything at all in openbox/X. p.s. I do understand echo does nothing in that scenario.

Offline

#5 2023-07-19 13:50:33

kes
Member
Registered: 2017-12-12
Posts: 35

Re: Convert GUI text selections, in place, from UPPER to lower case, etc

Use of yad easily proves that "TEST'S" selected in google docs is converted to "test's".

The tricky bit I have observed here is getting the converted selection back into the doc after case conversion.
Picking up the text onto the clipboard seems to be easy.
 
I incorporated the display into the solution to see if that was the issue.
Seems it wasn't.

echo $DISPLAY

Tried a paste at some point by selecting the active window with

wmctrl -a :ACTIVE:

to make sure active window selected for paste, but that did not seemed to work either, though I hadn't though of selecting the display at that point.

Noticed have to reselect the google docs text sample after each reload of `rc.xml`
or it sometimes does not work which was very confusing.

Surprised there is a not a native, written in C, small GNU tool/ utility for this.
Perhaps there is. An initial google turned nothing up.
I'm not a programmer.

keybind key="r"><action name="execute"><command>bash -c '
   txt=$(xclip -o -display :0);
   txt=$(echo "$txt" | tr '[:upper:]' '[:lower:]');
   yad --text="$txt";
   echo -n "$txt" | xclip -display :0 -selection clipboard
'</command></action></keybind>

Last edited by kes (2023-07-19 13:57:55)

Offline

#6 2023-07-19 17:41:57

brontosaurusrex
Middle Office
Registered: 2015-09-29
Posts: 2,744

Re: Convert GUI text selections, in place, from UPPER to lower case, etc

I think the "a'b'c > A'B'C" issue is fixed on my end, the magic command is an empty "setxkbmap", here is little script that includes openbox rc.xml example.

edit: yeah, after some more testing this doesn't behave as expected at all.

Another try, this removes problematic xdotool completely, so user has to:

1. select text
2. press defined hotkey
3. ctrl+v back to 'document'

needs: awk, notify-send

Not battle tested at all.

Last edited by brontosaurusrex (2023-07-20 19:09:48)

Offline

#7 2023-07-21 11:59:57

kes
Member
Registered: 2017-12-12
Posts: 35

Re: Convert GUI text selections, in place, from UPPER to lower case, etc

Fully working on limited testing.

Involves python. Need to install pyhon3 and the python-pyperclip library/ module.

Unfortunately still uses xdotool.

Preserves the following when pasting back
- any line breaks in selected text
- multiple rows and columns paste in spreadsheets
- '
- "

Minimal testing and working on
- Libreoffice writer, google docs
- libreoffice calc,   google sheets

There are tools that do this out there, that Bard was telling me about, but I couldn't find any when I looked.

A "small" amount of help from AI in coding speeded this process up immeasurably.

I don't really know python.

There really needs to be a standard linux utility for in-line GUI text conversion.

There probably is, I'm sure there is, but I can't find it.

Script arguments are
- l lower case
- u upper case
- s sentence case 1
- t sentence case 2

Option "t" will convert
i am not a python programmer. nor likely will i ever be.
not soon anyway? no! not soon anyway.
to
I am not a python programmer. Nor likely will I ever be.
Not soon anyway? No! Not soon anyway.


eg python case-conversion.py l
to convert to lower case

#!/usr/bin/env python3


#    INSTRUCTIONS
# 
# make sure xdotool is installed
# make sure pyperclip is installed
# 
#      arch:   sudo pacman -S python-pyperclip xdotool
#      debian: sudo apt-get install python-pyperclip xdotool 
#

import sys
import time
import pyperclip
import subprocess

# re is regex module
import re

# copy out of gui application
def copy_selected_text():
    # ctrl+c shortcut to copy the selected text
    subprocess.run(["xdotool", "key", "ctrl+c"])
    time.sleep(0.1)  # wait for clipboard to update
    return pyperclip.paste()

# paste into gui application
def paste_text(text):
    # copy converted text to clipboard
    pyperclip.copy(text)
    # ctrl+v to paste the text
    subprocess.run(["xdotool", "key", "ctrl+v"])

# use argument "i" for sentence case 
def convert_sentence_case(selected_text):
    rows = selected_text.splitlines()
    sentence_case_rows = []
    
    for row in rows:
        cells = row.split("\t")  # replace "\t" with column separator used in spreadsheet
        sentence_case_cells = []
        
        for cell in cells:
            words = cell.split()
            sentence_case_cell = ' '.join(word.capitalize() for word in words)
        
            # new line below Kes Smith
            sentence_case_cell = re.sub(r'(\. \"|\? \"|\! \"|\. |\? |\! |\")([a-z])', lambda match: match.group(1) + match.group(2).upper(), sentence_case_cell)

            sentence_case_cells.append(sentence_case_cell)
        
        
        sentence_case_rows.append("\t".join(sentence_case_cells))  # replace "\t" with the column separator used in spreadsheet
    
       
    return '\n'.join(sentence_case_rows)

# use argument "t" for FULL sentence case
def convert_title_case(selected_text):
#	def capitalize_first_letter(line):
#        return line[0].upper() + line[1:]
    rows = selected_text.splitlines()
    title_case_rows = []
    
    for row in rows:
        cells = row.split("\t")  # replace "\t" with column separator used in spreadsheet
        title_case_cells = []
        
        for cell in cells:
			# the following line lower cases all the text of each cell then capatalises the first letter only
            #cell_title_case = cell.lower().capitalize()
            cell_title_case = cell.lower()
            # the following line upper cases the first letter only of each cell
            cell_title_case = cell.capitalize()
            #cell_title_case = cell_title_case.capitalize()
            cell_title_case = cell_title_case.replace(' i ', ' I ')
            cell_title_case = re.sub(r'(\. \"|\? \"|\! \"|\. |\? |\! )([a-z])', lambda match: match.group(1) + match.group(2).upper(), cell_title_case)
            #cell_title_case = capitalize_first_letter(line)
            title_case_cells.append(cell_title_case)
        
        title_case_rows.append("\t".join(title_case_cells))  # replace "\t" with the column separator used in spreadsheet
    
    return '\n'.join(title_case_rows)

def main():
    if len(sys.argv) != 2 or sys.argv[1] not in ['u', 'l', 's', 't']:
        print("Usage: python3 case_converter.py <case_option>")
        print("case_option: 'u' for uppercase, 'l' for lowercase, 's' for sentence case, 't' for title case")
        sys.exit(1)

    case_option = sys.argv[1]
    selected_text = copy_selected_text()

    if case_option == 'u':
        converted_text = selected_text.upper()
    elif case_option == 'l':
        converted_text = selected_text.lower()
    elif case_option == 's':
        converted_text = convert_sentence_case(selected_text)
    elif case_option == 't':
        converted_text = convert_title_case(selected_text)
    else:
        print("Invalid case option. Use 'u', 'l', 's', or 't'.")
        sys.exit(1)

    paste_text(converted_text)

if __name__ == "__main__":
    main()

Last edited by kes (2023-07-24 17:10:15)

Offline

Board footer

Powered by FluxBB