1

I am trying to use xmodmap to swap caps and escape. I put the xmodmap ~/.Xmodmap command in my .zshrc. But whenever I start a new shell, the xmod settings are swapped again. So I tried to wrap the xmodmap command in a condition that checks for a global variable, but I just can't get it to work.

if [ ! "$CAPS_MAPPED" = true ]; then     # check if CAPS_LOCKED is empty
    echo 'mapping'
    xmodmap ~/dotfiles/.xmodmap            # call xmodmap
    export readonly CAPS_MAPPED=true       # assign global var
fi

I tried different variations but just don't get what to do as I am fairly inexperienced with shell scripts.

Charles Duffy
  • 257,635
  • 38
  • 339
  • 400
Franz Skuffka
  • 384
  • 1
  • 11
  • so is this workaround at least printing "mapping"? Meaning, is the .zshrc getting into this `if` condition? – fedorqui Nov 03 '15 at 11:29
  • It prints 'mapping' when i remove `!`. – Franz Skuffka Nov 03 '15 at 11:38
  • From `man test`, `-z` option says `the length of STRING is zero`. I am not sure what is your intention here, but probably `-z` alone should be the way. Otherwise, what you are currently checking is the opposite, which is also `-n` --> `the length of STRING is nonzero`. – fedorqui Nov 03 '15 at 11:41
  • My intention here is to just check if the variable does NOT contain whatever value that may be assigned in line 4. I updated my question. – Franz Skuffka Nov 03 '15 at 11:47
  • 1
    Put your solution in an answer, not as part of the question. – chepner Nov 03 '15 at 15:17
  • @chepner I do not consider it a solution, that is why I put it in the question. But I guess you are right. – Franz Skuffka Nov 04 '15 at 16:19
  • If you are calling the `xmodmap` script every time you start a shell instead of every time you login, it becomes useful to make the `xmodmap` script itself indempotent. I don't believe this is too difficult. Rather than swapping around keysyms you should identify the keycodes that you want to assign to, and set them up instead. Then xmodmap will have the same effect every time and you can call it as often as you like. – NeilG Aug 22 '21 at 03:55
  • full disclosure: I switched back to MacOS because I can't waste days of my productivity on small but important things like this on a machine that is supposed to be "the thing" among linux users.. – Franz Skuffka Aug 22 '21 at 19:07

2 Answers2

2

The best way is to put the xmodmap call in an X init script rather than a shell init script.

Your per user X init script is ~/.xinitrc.

Create ~/.xinitrc if it doesn't exist and add your xmodmap command to the end.

The ~/.xinitrc file is documented in the startx manpage on Debian.

The xmodmap manpage, under the description of it's filename parameter, says it's "usually kept in a file like .xmodmaprc." It seems that might depend on how the system was setup by the distribution or locally.

RobertL
  • 365
  • 1
  • 9
  • Indeed -- no need to bother trying to prevent rerunning in this case. – Charles Duffy Nov 04 '15 at 04:24
  • Wasn't `.xmodmaprc` renamed to `.Xmodmap`? My `.Xmodmap` did not get executed automatically. I will try out if it works if I use this filename instead. – Franz Skuffka Nov 04 '15 at 16:21
  • I don't believe `xmodmap` has a default file name it looks for. The mapping file has to be supplied on the command line when `xmodmap` is called. So if you are calling `xmodmap` you can name the file whatever you want and put it where every you want. I use `~/.config/xmodmaprc`. If something else is calling it for you, find where it's being called and look to see what they called the file. – NeilG Aug 22 '21 at 03:51
1

May be better to set something like:

good_value="true"
if [[ ! "${CAPS_MAPPED}" = "$good_value" ]]; then     # check if CAPS_LOCKED does not have the required value
    echo 'mapping'
    xmodmap ~/dotfiles/.xmodmap                   # call xmodmap
    export readonly CAPS_MAPPED="$good_value"       # assign global var
fi

Note that I am using How to compare strings in Bash script, that is, [ "$var" == "$another_var" ]. [[ "$var1" = "$var2" ]] as way to compare strings in zsh, since == is not POSIX. See zsh - 12 Conditional Expressions.

Community
  • 1
  • 1
fedorqui
  • 252,262
  • 96
  • 511
  • 570
  • The `+xxx` expression is bollocks. I copied it from somewhere. I removed it in my question. However, now I get `/home/jan/.zshrc:103: = not found` which corresponds to the second line of the script you provided. Without the expression of course and both with and without curly braces. We are getting closer though. Thank you. – Franz Skuffka Nov 03 '15 at 12:05
  • @FranzSkuffka ah true you are in `zsh`. See my update! I had to change the `if` to `[[ "$var1" = "$var2" ]]`, that is, using just one `=`. – fedorqui Nov 03 '15 at 12:09
  • Nice, this cleared the error. But the condition still applies no matter which variable I insert. When I remove `!` it is always false, no matter which variable is used. – Franz Skuffka Nov 03 '15 at 12:17
  • The return value of `echo $CAPS_MAPPED` does not seem to make any difference. All I need is an idempotent piece of code. This was just what came to mind at first, but if you know a different solution, that's great. – Franz Skuffka Nov 03 '15 at 12:19
  • @FranzSkuffka `"${CAPS_MAPPED}" = "$good_value"` is checking if `$CAPS_MAPPED` is equal to the value in `$good_value`. You want to change it in case they are not, right? So doing `if [ not (condition) ]` change it, should do it. I guess I am missing some information here. Did you add the line `good_value="true"`? – fedorqui Nov 03 '15 at 12:20
  • I think the script works, but the environment variable is not updated in all shells. Which means, when I create a new shell (tmux pane) `CAPS_MAPPED` is not assigned, gets checked, and then assigned. It's value is not persistent. I think I need a different solution here, maybe store it in a file that gets cleared with every login on my system. Thank you though. Bad question, good answer but I am not sure if is the correct answer. I will vote you up but it did not solve the problem of achieving idempotency. – Franz Skuffka Nov 03 '15 at 12:28
  • @FranzSkuffka where are you placing this snippet? Note some files are loaded depending on the kind of login you start. See [config files zsh](http://zshwiki.org/home/config/files). I think I am missing some info. However, I suggest you to do a sample, basic case to isolate the issue: can you set env variables? is the `if` being processed? etc – fedorqui Nov 03 '15 at 12:35
  • As stated in my initial question, in my `.zshrc`. I can set env variables but they only apply to the current session. – Franz Skuffka Nov 03 '15 at 13:30
  • @FranzSkuffka adding them in `.zshenv` may solve the issue. See [2.5.10 Environment variables](http://zsh.sourceforge.net/Guide/zshguide02.html) – fedorqui Nov 03 '15 at 13:50