How to remap a key when it's pressed twice?

Some of my keyboard keys has gone, so I’m trying to program the other keys that are still working to press the damaged keys when I press them twice. Is that possible? Is there any program that can help me in doing that?

I want to remap the key J to give 'm' when I press it twice.

NB: My laptop is a MacBook Pro 13" Unibody Mid 2012


Solution 1:

Set aliases for characters, strings or complete lines

UNLESS you are using wayland (Ubuntu 17.10, tested on Ubuntu Budgie 18.04, but Ubuntu Gnome 18.04 should be fine too), the snippet below will help you out.

How it works in practice

  • Press Ctrl + J (or any other shortcut you set)
  • A box appears

    enter image description here

  • Type your "alias" (e.g. jj for m), the result shows (m), and the text will immediately be inserted at cursor position (or, if you prefer, after tapping Ctrl).

This script provides a single solution to set aliasses for a character, a string or even complete lines, just set the "alias" in the lines:

replacements = [
    ["jj", "m"],
    ["aa", "q"],
    ["zz", "e"],
    ["mb", "monkey eats banana"],
]

In the latter case, typing "mb" will paste "monkey eats banana":

enter image description here

Setting up

  1. You need to satisfy a few dependencies:

    • pyautogui:

      pip3 install pyautogui
      
    • pyperclip:

      sudo apt install python3-pyperclip xsel xclip
      
    • python3-xlib

      sudo apt install python3-xlib
      

    Log out and back in.

  2. Copy the script below into an empty file, save it as replace_keys.py

    #!/usr/bin/env python3
    import gi
    gi.require_version("Gtk", "3.0")
    gi.require_version("Wnck", "3.0")
    from gi.repository import Gtk, Gdk, Wnck
    import subprocess
    import pyperclip
    import pyautogui
    import time
    
    
    """
    depends on
    - pyautogui:
      pip3 install pyautogui
    - pyperclip:
      sudo apt install python3-pyperclip xsel xclip
    """
    
    
    act_on_firstmatch = False
    
    
    replacements = [
        ["jj", "m"],
        ["aa", "q"],
        ["zz", "e"],
        ["mb", "monkey eats banana"],
    ]
    
    
    class KeyWin(Gtk.Window):
    
        def __init__(self):
    
            self.screendata = Wnck.Screen.get_default()
            self.screendata.force_update()
            self.curr_subject = self.screendata.get_active_window().get_xid()
            self.currmatch = ""
            Gtk.Window.__init__(self)
            maingrid = Gtk.Grid()
            self.add(maingrid)
            self.set_decorated(False)
            self.set_position(Gtk.WindowPosition.CENTER)
            self.connect("key-release-event", self.check_key)
            self.keyentry = Gtk.Entry()
            self.keyentry.connect("changed", self.update_current)
            self.label = Gtk.Label("")
            self.label.set_width_chars(10)
            maingrid.attach(self.keyentry, 0, 0, 1, 1)
            maingrid.attach(self.label, 1, 0, 1, 1)
            self.show_all()
            self.connect("destroy", Gtk.main_quit)
            Gtk.main()
    
        def update_current(self, widget):
            curr = self.keyentry.get_text()
            self.currmatch = ""
            for s in replacements:
                if curr == s[0]:
                    self.currmatch = s[1]
                    if act_on_firstmatch:
                        self.replace()
            self.label.set_width_chars(len(self.currmatch) + 4)
            self.label.set_text(self.currmatch)
    
    
        def replace(self, *args):
            pyperclip.copy(self.currmatch)
    
            subprocess.call(["wmctrl", "-ia", str(self.curr_subject)])
            Gtk.main_quit()
    
        def check_key(self, button, val):
            typed = Gdk.keyval_name(val.keyval)
            if typed == "Control_L":
                self.replace()
    
    KeyWin()
    time.sleep(0.05)
    pyautogui.hotkey('ctrl', 'v')
    
  3. Set up your aliasses (KEEP THE INDENTATION!) in the section:

    replacements = [
        ["jj", "m"],
        ["aa", "q"],
        ["zz", "e"],
        ["mb", "monkey eats banana"],
    ]
    
  4. If you want, change

    act_on_firstmatch = False
    

    into

    act_on_firstmatch = True
    

    if you like to insert immediately without tapping Ctrl

  5. Set up a shortcut key with Ctrl as modifier. I used Ctrl + J in my test to run the script by the command:

    python3 /path/to/replace_keys.py
    

And you're done!