pqrs-org / KE-complex_modifications

Karabiner-Elements complex_modifications rules
https://ke-complex-modifications.pqrs.org/
The Unlicense
1.29k stars 1.09k forks source link

Adding unicode modifications #697

Closed erickrf closed 3 years ago

erickrf commented 4 years ago

Is it possible to modify a key's input to Unicode characters not in the default keyboard? For example, if I want to map left_option + a to πŸ’Ž

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

erickrf commented 4 years ago

Anything on this? I haven't figured out if there is an answer.

harmtemolder commented 4 years ago

I don't know of any native way Karabiner could do this, but you could take a look at setting your Input Source to Unicode Hex Input in your Keyboard Preferences. That allows you to type unicode characters by their number while holding option. And then map option+A to that series of numbers.

edit: that works, although you'll have to look up the code for that diamond:

{
  "title": "Print Unicode Characters",
  "maintainers": [
    "harmtemolder"
  ],
  "rules": [{
    "description": "Print Unicode Characters",
    "manipulators": [{
      "type": "basic",
      "from": {
        "key_code": "a"

      },
      "to": [{
          "key_code": "2",
          "modifiers": [
            "option"
          ]
        },
        {
          "key_code": "6",
          "modifiers": [
            "option"
          ]
        },
        {
          "key_code": "2",
          "modifiers": [
            "option"
          ]
        },
        {
          "key_code": "0",
          "modifiers": [
            "option"
          ]
        }
      ]
    }]
  }]
}

Maybe start and end with control+space to switch input methods so you're not in Unicode Hex Input at all times?

MuhammedZakir commented 4 years ago

Alternatively, use a shell script.

Karabiner config:

#!/usr/bin/env ruby

#######################################################################
# You can generate json by executing the following command on Terminal.
#     ruby ./insert_unicode.json.rb
#######################################################################

require 'json'

MODIFIER = 'fn'
KEY_CODES = ('a' .. 'z').to_a.freeze

def rules
  KEY_CODES.map do |key_code|
    {
      desscription: "Insert Character with Key '#{key_code}'",
      manipulators: [{
        type: "basic",
        from: {
          key_code: key_code,
          modifiers: {
            mandatory: [MODIFIER]
          }
        },
        to: [{
          'shell_command': "~/.config/karabiner/assets/complex_modifications/helpers/unicode " + key_code
        }],
        to_delayed_action: {
          to_if_invoked: [
            {
              key_code: "v",
              modifiers: "command"
            },
            {
              "shell_command": "pbpaste -pboard ruler | pbcopy" 
            }
          ]
        },
        parameters: {
          'basic.to_delayed_action_delay_milliseconds': 100
        }
      }]
    }
  end
end

def main
  {
    title: 'Insert Unicode Characters',
    rules: rules
  }
end

puts JSON.pretty_generate(main)

You can restrict this to only execute when caps_lock is enabled by adding 'caps_lock' to 'from.modifiers.mandatory' . Also, if you want to use more than 26 Unicode characters, use conditions - https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/.

Shell script (~/.config/karabiner/assets/complex_modifications/helpers/unicode):

#!/bin/zsh

typeset -A unicode_characters=( a 'πŸ’Ž'    b '1F4A0' c '1F4A1'
                                d '1F4A2' e '1F4A3' f '1F4A4'
                                g '1F4A5' h '1F4A6' i '1F4A7'
                                j '....'  k '....'  l '....'
                                m '....'  n '....'  o '....'
                                p '....'  q '....'  r '....'
                                s '....'  t '....'  u '....'
                                v '....'  w '....'  x '....'
                                y '....'  z '....'
                              )

key="$1"

# Copy current clipboard content to 'ruler' pboard
pbpaste | pbcopy -pboard ruler

printf "\\U${unicode_characters[$key]}" | pbcopy

For Bash, see https://stackoverflow.com/questions/602912/how-do-you-echo-a-4-digit-unicode-character-in-bash

realliyifei commented 4 years ago

@MuhammedZakir Hi, I have a similar problem here, which involves inputting the punctuations that are not on the keyboard.

I modify your script a bit but it doesn't work? Would you mind to help me check the reason? Thanks.

I have two files:

  1. ~/.config/karabiner/assets/complex_modifications/fn_halfwidth.json
{
  "title": "fnεŠθ§’η¬¦ε·εˆ‡ζ’  |  Map fn + chinese punctuations to their corresponding halfwidth forms",
  "rules": [
    {
      "description": "Map fn + punctuations to their corresponding halfwidth forms",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "a",
            "modifiers": {
              "mandatory": ["fn"]
            }
          },
          "to": [
            {
              "shell_command": "~/.config/karabiner/assets/complex_modifications/helpers/halfwidth_convert a"
            }
          ]
        }          
      ]
    }
  ]
}
  1. ~/.config/karabiner/assets/complex_modifications/helpers/halfwidth_convert
#!/bin/zsh

typeset -A halfwidth_chars= (   a 'πŸ’Ž'    b '1F4A0' c '1F4A1'
                                d '1F4A2' e '1F4A3' f '1F4A4'
                                g '1F4A5' h '1F4A6' i '1F4A7'
                                j '....'  k '....'  l '....'
                                m '....'  n '....'  o '....'
                                p '....'  q '....'  r '....'
                                s '....'  t '....'  u '....'
                                v '....'  w '....'  x '....'
                                y '....'  z '....'
                            )

key="$1"

printf "\\U${halfwidth_chars[$key]}" | pbcopy

Based on my understanding, when I press fn and a, it should input πŸ’Ž. But it shows nothing.

MuhammedZakir commented 4 years ago

Based on my understanding, when I press fn and a, it should input πŸ’Ž. But it shows nothing.

At the end of shell script, printf creates Unicode character and pbcopy copies it to clipboard. It does not paste it at the current cursor location. To do that, I added a delayed action command+v after a short delay (for executing shell script). I guess you forgot to include that part!

to_delayed_action: {
  to_if_invoked: [{
    key_code: "v",
    modifiers: "command"
  }]
},
parameters: {
  'basic.to_delayed_action_delay_milliseconds': 100
}

P.S. Recently, I came across espanso - https://espanso.org/. It maybe more suited to your and OP's needs.

realliyifei commented 4 years ago

I guess you forgot to include that part!

Actually I have tried it but failed. My scripts with this part are shown as below:

  1. ~/.config/karabiner/assets/complex_modifications/fn_halfwidth.json
{
  "title": "fnεŠθ§’η¬¦ε·εˆ‡ζ’  |  Map fn + chinese punctuations to their corresponding halfwidth forms",
  "rules": [
    {
      "description": "Map fn + punctuations to their corresponding halfwidth forms",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "a",
            "modifiers": {
              "mandatory": ["fn"]
            }
          },
          "to": [
            {
              "shell_command": "~/.config/karabiner/assets/complex_modifications/helpers/halfwidth_convert a"
            }
          ],
          "to_delayed_action": {
            "to_if_invoked": [{
              "key_code": "v",
              "modifiers": "command"
            }]
          },
          "parameters": {
            "basic.to_delayed_action_delay_milliseconds": 100
          }
        }          
      ]
    }
  ]
}
  1. ~/.config/karabiner/assets/complex_modifications/helpers/halfwidth_convert
#!/bin/zsh

typeset -A halfwidth_chars= (   a 'πŸ’Ž'    b '1F4A0' c '1F4A1'
                                d '1F4A2' e '1F4A3' f '1F4A4'
                                g '1F4A5' h '1F4A6' i '1F4A7'
                                j '....'  k '....'  l '....'
                                m '....'  n '....'  o '....'
                                p '....'  q '....'  r '....'
                                s '....'  t '....'  u '....'
                                v '....'  w '....'  x '....'
                                y '....'  z '....'
                            )

key="$1"

printf "\\U${halfwidth_chars[$key]}" | pbcopy

btw I have tried the shell script itself but fails, too. I'm not familiar with sh so am not sure whether the shell script has a problem.

I tried sh halfwidth_convert a or sh halfwidth_convert 'a' in terminal, and it turns out:

halfwidth_convert: line 3: syntax error near unexpected token `('
halfwidth_convert: line 3: `typeset -A halfwidth_chars= (   a 'πŸ’Ž'    b '1F4A0' c '1F4A1''

P.S. Recently, I came across espanso - https://espanso.org/. It maybe more suited to your and OP's needs.

Thanks for your recommendation. I have similar text-replacement stuff such as Mac built-in text replacement and Alfred 4 script. The reason I use karabiner here is that I prefer inputting the punctuations more quickly, and then they can be switched back automatically and immediately. Text replacement is not that efficient in this case.

MuhammedZakir commented 4 years ago
1. ~/.config/karabiner/assets/complex_modifications/helpers/halfwidth_convert> 
#!/bin/zsh

typeset -A halfwidth_chars= (   a 'πŸ’Ž'    b '1F4A0' c '1F4A1'
*--snip--*
  1. No space between = and ( -> typeset -A halfwidth_chars=( a 'πŸ’Ž'
  2. Make the script executable -> chmod ug+x ~/.config/karabiner/assets/complex_modifications/helpers/halfwidth_convert. I forgot to mention this! 😬

Thanks for your recommendation. I have similar text-replacement stuff such as Mac built-in text replacement and Alfred 4 script. The reason I use karabiner here is that I prefer inputting the punctuations more quickly, and then they can be switched back automatically and immediately. Text replacement is not that efficient in this case.

I see!

realliyifei commented 4 years ago

I ultimately finish my side-project based on your suggestions. Thanks a lot for your help!

Here is probably the last question:

  1. Make the script executable -> chmod ug+x ~/.config/karabiner/assets/complex_modifications/helpers/halfwidth_convert. I forgot to mention this! 😬

If others download my scripts, do they need to chmod ug+x .../halfwidth_convert in their terminal to activate the shell script file first, too?

Edit: ok, just figure out that it doesn't work as well as I thought πŸ˜‚. This mechanism copy the character to the clipboard so it's a bit inconvenient when you want to copy something but at the same time use this script. I'm trying to remove the first item in clipboard history (i.e. the copied character) each time or use another method. But anyway, thanks for your inspiration.

MuhammedZakir commented 4 years ago

I ultimately finish my side-project based on your suggestions. Thanks a lot for your help!

Congrats! πŸ˜„

Here is probably the last question:

  1. Make the script executable -> chmod ug+x ~/.config/karabiner/assets/complex_modifications/helpers/halfwidth_convert. I forgot to mention this! 😬

If others download my scripts, do they need to chmod ug+x .../halfwidth_convert in their terminal to activate the shell script file first, too?

Permissions can be preserved by downloading zip [1] file.

[1] https://github.com/yif-li/Mac-Karabiner-Chinese-Punctuations-to-Halfwidth-Forms/archive/master.zip

Edit: ok, just figure out that it doesn't work as well as I thought πŸ˜‚. This mechanism copy the character to the clipboard so it's a bit inconvenient when you want to copy something but at the same time use this script. I'm trying to remove the first item in clipboard history (i.e. the copied character) each time or use another method. But anyway, thanks for your inspiration.

You are welcome! And... this isn't the end! πŸ˜‰

Put this before printf function in shell script

# Copy current clipboard content to 'ruler' pboard
pbpaste | pbcopy -pboard ruler

and add one more command to delayed action.

to_delayed_action: {
  to_if_invoked: [
    {
      key_code: "v",
      modifiers: "command"
    },
    {
      "shell_command": "pbpaste -pboard ruler | pbcopy" 
    }
  ]
 }

This shell command will copy content inside ruler pboard to general pboard.

Note: There are four pboards -

  1. general - what we normally use
  2. ruler - I don't know what this is used for
  3. find - stores text entered in find(?) fields - command+f.
  4. font - don't know

See pbcopy or pbpaste manpage for more information.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

edmundseto commented 1 year ago

Thanks to harmtemolder's response above, I was able to get Karabiner-Elements to convert keystrokes to both 4-digit (e.g., math symbols) and 5-digit (e.g., emoji) unicode. I didn't have to resort to running a shell script or copy/paste. It's just a complex modification in karabiner.json.

Here's my code. The json file generally is structured this way...

{
   "global": {
            ... various stuff here...
    },
    "profiles": [
         {
         "complex_modifications": {
              "parameters": {
                      ... various stuff here...
              },
             "rules": [
             {
                    **...stick a complex modifications here...**
             },
             {
                   **...stick another complex modifications here...**
             }
             ],
           "type": "basic"
        }
     ]
     ... remaining stuff here....

And here is an example complex modification that is inserted into the section above for a 4-digit hex unicode (U+03BC for the mu symbol)...

"description": "Math symbol mu.",
"manipulators": [
{
"conditions": [
{
"identifiers": [
{
"description": "2.4G Keyboard Mouse (MOSART Semi.)",
"product_id": 16641,
"vendor_id": 1578
}
],
"type": "device_if"
}
],
"from": {
"key_code": "keypad_1"
},
"to": [
{
"key_code": "spacebar",
"modifiers": [
"left_control"
]
},
{
"key_code": "0",
"modifiers": [
"left_option"
]
},
{
"key_code": "3",
"modifiers": [
"left_option"
]
},
{
"key_code": "b",
"modifiers": [
"left_option"
]
},
{
"key_code": "c",
"modifiers": [
"left_option"
]
},
{
"key_code": "spacebar",
"modifiers": [
"left_control"
]
}
],
β€œtype”: β€œbasic”
}
]

For this to work, it requires that you first go into your Mac System Preferences - Keyboard settings, and add the Unicode Hex input mode.

You'll see that in the code above when keypad_1 is pressed, it converts it first to a Ctrl+Spacebar that will switch to the Unicode Hex input mode, and then it "types" Option(held down)+0 3 b c. Then finishes by typing Ctrl+Spacebar to return to your original Mac keyboard input mode.

Also note, that I've specified "product_id" and "vendor_id" in the code above to limit the modification to a specific device, a numeric keypad that I'm using. You'll want to either remove this part, or change it to refer the the IDs of the device you're using.

I've converted two numeric keypads to a math and an emoji keypads. There's a bit more detail on my website: https://www.edmundseto.com/edmundseto/creating-a-scientific-keypad-for-mac/

Again, thanks to harmtemolder for leading the way for me.