You are not logged in.
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
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
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
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
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
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
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