77

I usually load a new version for every release to keep my OS fresh while preserving the last version on another partition as backup. I also employ a lot of custom key mappings.

I've figured out how to transfer the majority of my configuration across systems so far but I can't figure out where the custom keyboard shortcut mappings are stored.

Does anybody know where gnome puts these? Are there separate user config (i.e., ~/) and system config (i.e. /etc) files?

Artur Meinild
  • 26,018
Evan Plaice
  • 1,916
  • 2
    How did you change the settings? Using GConf Editor? I'm guessing you want gconftool-2 --dump /apps/metacity or something like that. – Mikel Feb 13 '11 at 06:51
  • 1
    @Mikel Thanks a bunch for that comment. From what I can tell in gconf-editor, most of the keybindings are stored under /apps/metacity while the rest are spread around. I'm currently writing Import/Export python scripts to make backup/restore keybindings a one-click operation. – Evan Plaice Feb 16 '11 at 05:09

5 Answers5

64

Ubuntu has changed since other answers to this question were written.

Keybindings have moved from gconf to dconf. Gconf stores its data in xml files and was accessed by gconf-editor and gconf-tool2. Dconf stores its data in a binary format and is accessed by dconf-editor and gsettings.

The number of places that keybindings are stored is reduced. There is now a centralized dconf path to store window manager keybindings (org.gnome.desktop.wm.keybindings). There are mapping files in the directory /usr/share/gnome-control-center/keybindings/that show how these are applied based on the window manager you are actually using (compiz or metacity).

A second set of non-window-manager related key bindings is stored in the dconf path org.gnome.settings-daemon.plugins.media-keys

There is a third set of keybindings related to power buttons that is stored in the dconf path org.gnome.settings-daemon.plugins.power. There is currently a bug in the GUI that lets you configure keybindings. It doesn't know about these settings. I have a "sleep" button on my keyboard. If I want to reassign it to other functionality, I have to disable the setting in org.gnome.settings-daemon.plugins.power manually. The GUI doesn't do it for me (although it assigns the new functionality just fine).

The other wrinkle is custom key bindings. These are stored in dconf using relocatable schema. Its done this way because there are an arbitrary number of them. A reasonable approach, but it makes listing or modifying them via the command line harder than it should be.

I also found out that the GUI that allows you to assign keybindings is limited in a way that annoys me. The GUI allows exactly ONE keybinding to be assigned to each action. In dconf, you can set an array of bindings for a single action. This is useful to me. For example, I like to have the "close-window" action assigned to the traditonal Alt-F4 as well as to an easier to hit single button on my keybord.

I have written a Perl script to dump all the keybindings to a csv file, or restore them from the csv file. For example to dump the keybindings you might use:

./keybindings.pl -e /tmp/keys.csv

and to restore them you might use:

./keybindings.pl -i /tmp/keys.csv

#!/usr/bin/perl

use strict;

my $action = '';
my $filename = '-';

for my $arg (@ARGV){
    if ($arg eq "-e" or $arg eq "--export"){
        $action = 'export';
    } elsif ($arg eq "-i" or $arg eq "--import"){
        $action = 'import';
    } elsif ($arg eq "-h" or $arg eq "--help"){
        print "Import and export keybindings\n";
        print " -e, --export <filename>\n";
        print " -i, --import <filename>\n";
        print " -h, --help\n";
        exit;
    } elsif ($arg =~ /^\-/){
        die "Unknown argument $arg";
    } else {
        $filename = $arg;
        if (!$action){
            if ( -e $filename){
                $action='import';
            } else {
                $action='export';
            }
        }
    }
}

$action='export' if (!$action);
if ($action eq 'export'){
    &export();
} else {
    &import();
}

sub export(){
    my $gsettingsFolders = [
        ['org.gnome.desktop.wm.keybindings','.'],
        ['org.gnome.settings-daemon.plugins.power','button'],
        ['org.gnome.settings-daemon.plugins.media-keys','.'],
    ];

    my $customBindings = [
    ];

    $filename = ">$filename";
    open (my $fh, $filename) || die "Can't open file $filename: $!";

    for my $folder (@$gsettingsFolders){
        my @keylist = split(/\n/, `gsettings list-recursively $folder->[0]`);
        foreach my $line (@keylist){
            if ($line =~ /^([^ ]+) ([^ ]+)(?: \@[a-z]+)? (.*)/){
                my ($path, $name, $value) = ($1,$2,$3);
                if ($name eq "custom-keybindings"){
                    $value =~ s/[\[\]\' ]//g;
                    my @c = split(/,/, $value);
                    $customBindings = \@c;
                } elsif ($name =~ /$folder->[1]/){
                    if ($value =~ /^\[|\'/){
                        if ($value =~ /^\[\'(?:disabled)?\'\]$/){
                            $value = '[]';
                        } 
                        print $fh "$path\t$name\t$value\n";
                    }
                }        
            } else {
                die "Could note parse $line";
            }
        }
    }   

    for my $folder (@$customBindings){
        my $gs = `gsettings list-recursively org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:$folder`;
        my ($binding) = $gs =~ /org.gnome.settings-daemon.plugins.media-keys.custom-keybinding binding (\'[^\n]+\')/g;
        my ($command) = $gs =~ /org.gnome.settings-daemon.plugins.media-keys.custom-keybinding command (\'[^\n]+\')/g;
        my ($name) = $gs =~ /org.gnome.settings-daemon.plugins.media-keys.custom-keybinding name (\'[^\n]+\')/g;
        $command =~ s/\"/\\\"/g;
        $command =~ s/^'(.*)'$/$1/g;
        $command =~ s/\'/\'\\\'\'/g;
        $command = "\'$command\'";
        print $fh "custom\t$name\t$command\t$binding\n"    
    }

    close($fh);
}

sub import(){

    $filename = "<$filename";
    open (my $fh, $filename) || die "Can't open file $filename: $!";

    my $customcount=0;

    while (my $line = <$fh>){
        chomp $line;
        if ($line){
            my @v = split(/\t/, $line);
            if (@v[0] eq 'custom'){
                my ($custom, $name, $command, $binding) = @v;
                print "Installing custom keybinding: $name\n";
                    print `gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom$customcount/ name \"$name\"`;
                print `gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom$customcount/ command \"$command\"`;
                print `gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom$customcount/ binding \"$binding\"`;
                $customcount++;
            } else {
                my ($path, $name, $value) = @v;
                print "Importing $path $name\n";
                print `gsettings set \"$path\" \"$name\" \"$value\"`;
            }
        }       
    }
    if ($customcount > 0){
        my $customlist = "";
        for (my $i=0; $i<$customcount; $i++){
            $customlist .= "," if ($customlist);
            $customlist .= "'/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom$i/'";            
        }
        $customlist = "[$customlist]";
        print "Importing list of custom keybindings.\n";
        print `gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings \"$customlist\"`;
    }

    close($fh);
}

This includes the fix by user2589537 to allow custom commands with quotes in them.

Pablo Bianchi
  • 15,657
  • 2
    I filed two bugs against ubuntu gnome-control-center keyboard shortcuts. I found them while creating this script. https://bugs.launchpad.net/ubuntu/+source/gnome-control-center/+bug/1079190 and https://bugs.launchpad.net/ubuntu/+source/gnome-control-center/+bug/1079198 – Stephen Ostermiller Nov 15 '12 at 13:57
  • 1
    Thanks for the script @Stephen, just tried on Ubuntu 13.10 and it just worked! Created a gist for easy sharing: https://gist.github.com/elgalu/8511861#file-keybindings-pl – Leo Gallucci Jan 19 '14 at 22:28
  • Awesome work and good job documenting the specifics. – Evan Plaice May 06 '15 at 19:00
  • 2
    Still works on Ubuntu GNOME 3.2 - Thank you! – klequis May 16 '16 at 01:55
  • Ran it in export mode - output does not look like CSV – nhed Sep 03 '16 at 00:08
  • 1
    "works" technically for me, but would probably need to watch different dconf sections for Ubuntu-MATE (i.e. [org/mate/marco/global-keybindings], [org/mate/marco/window-keybindings], ...) – Frank N Sep 03 '17 at 10:13
  • "The other wrinkle is custom key bindings. These are stored in dconf using relocatable schema" How can I access them via CLI ? the above perl script does not take them into account. – n0tis Apr 27 '23 at 12:11
  • @n0tis There is a bunch of code in that script to deal with custom key bindings. It uses gsettings list-recursively to find them. – Stephen Ostermiller Apr 27 '23 at 12:36
  • Then apparently can't find any of my custom shortcut on ubuntu 20.04, gnome 3.36.8. They are not present in the dumped CSV file (what I mean by custom shortcut is shortcut for new custom commands ) – n0tis Apr 27 '23 at 13:26
32

How to backup dconf settings like keyboard shortcuts

  1. Dump them all to a file:

    dconf dump / > ~/.config/dconf/user.conf
    
  2. Open that file on a text editor and select the settings that you care about:

    editor ~/.config/dconf/user.conf
    

    If you use Vim, you will want this syntax highlight.

    You will soon ask yourself what is <Primary>.

  3. If you don't know the name of the setting, but know how to modify it from a GUI like unity-control-center, run:

    dconf watch /
    

    and then modify them. The exact setting will then appear on the terminal.

  4. When you want to restore those settings, run:

    dconf load / < ~/.config/dconf/user.conf
    
  5. Git track the config file to never lose it. Homeshick is my current favorite method.

Tested on Ubuntu 15.10. Tip adapted from here.

Gnome terminal is unfortunately resistant to such edits because of the unpredictable profile IDs.

Related: How can I restore default keyboard shortcuts?

  • 2
    upvoting for dconf watch / - a time saver! – benzkji May 13 '20 at 14:58
  • 1
    The only solution that really works, Time saver. Works with Ubuntu 18.04. If you have complex commands in the shortcuts, spaces might be stripped. Just review, and add if necessary. – Mijo Feb 09 '21 at 05:16
7

Save custom keyboard shortcuts

You can save/backup/export custom shortcuts/keybindings using just dconf and sed

Export

dconf dump / | sed -n '/\[org.gnome.settings-daemon.plugins.media-keys/,/^$/p' > custom-shortcuts.conf # Export

The difference with the usual answer is that this will hold on the file the path to the dconf settings, making easier to import, just dconf load / < file.

Import

dconf load / < custom-shortcuts.conf # Import

Notes

  • Based on Ciro's answer (also here)

  • Only for the added custom shortcuts

  • Note that dconf only dumps non-default values

  • To backup you may want to use custom-shortcuts-$(date -I).conf

  • Test if it works by resetting to defaults before the import

    gsettings reset-recursively org.gnome.settings-daemon.plugins.media-keys
    
Pablo Bianchi
  • 15,657
3

In 11.10 running Gnome classic I found a set of directories (Custom0, Custom1...) under

$HOME/.gconf/desktop/gnome/keybindings

I copied those directories to the same folder in a clean 12.04 installation (again running with Gnome fallback), logged out and logged in again. The keybindings got a bit messed up in transition (something funny happened to the SUPER modifier) but otherwise they were there.

3

There is a slight problem with the accepted answer, in that it cannot handle custom commands with quotes in them. I only changed the processing of custom commands to generate correct output.

#!/usr/bin/perl

use strict;

my $action = '';
my $filename = '-';

for my $arg (@ARGV){
    if ($arg eq "-e" or $arg eq "--export"){
        $action = 'export';
    } elsif ($arg eq "-i" or $arg eq "--import"){
        $action = 'import';
    } elsif ($arg eq "-h" or $arg eq "--help"){
        print "Import and export keybindings\n";
        print " -e, --export <filename>\n";
        print " -i, --import <filename>\n";
        print " -h, --help\n";
        exit;
    } elsif ($arg =~ /^\-/){
        die "Unknown argument $arg";
    } else {
        $filename = $arg;
        if (!$action){
            if ( -e $filename){
                $action='import';
            } else {
                $action='export';
            }
        }
    }
}

$action='export' if (!$action);
if ($action eq 'export'){
    &export();
} else {
    &import();
}

sub export(){
    my $gsettingsFolders = [
        ['org.gnome.desktop.wm.keybindings','.'],
        ['org.gnome.settings-daemon.plugins.power','button'],
        ['org.gnome.settings-daemon.plugins.media-keys','.'],
    ];

    my $customBindings = [
    ];

    $filename = ">$filename";
    open (my $fh, $filename) || die "Can't open file $filename: $!";

    for my $folder (@$gsettingsFolders){
        my @keylist = split(/\n/, `gsettings list-recursively $folder->[0]`);
        foreach my $line (@keylist){
            if ($line =~ /^([^ ]+) ([^ ]+)(?: \@[a-z]+)? (.*)/){
                my ($path, $name, $value) = ($1,$2,$3);
                if ($name eq "custom-keybindings"){
                    $value =~ s/[\[\]\' ]//g;
                    my @c = split(/,/, $value);
                    $customBindings = \@c;
                } elsif ($name =~ /$folder->[1]/){
                    if ($value =~ /^\[|\'/){
                        if ($value =~ /^\[\'(?:disabled)?\'\]$/){
                            $value = '[]';
                        } 
                        print $fh "$path\t$name\t$value\n";
                    }
                }        
            } else {
                die "Could note parse $line";
            }
        }
    }   

    for my $folder (@$customBindings){
        my $gs = `gsettings list-recursively org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:$folder`;
        my ($binding) = $gs =~ /org.gnome.settings-daemon.plugins.media-keys.custom-keybinding binding (\'[^\n]+\')/g;
        my ($command) = $gs =~ /org.gnome.settings-daemon.plugins.media-keys.custom-keybinding command (\'[^\n]+\')/g;
        my ($name) = $gs =~ /org.gnome.settings-daemon.plugins.media-keys.custom-keybinding name (\'[^\n]+\')/g;
        $command =~ s/\"/\\\"/g;
        $command =~ s/^'(.*)'$/$1/g;
        $command =~ s/\'/\'\\\'\'/g;
        $command = "\'$command\'";
        print $fh "custom\t$name\t$command\t$binding\n"    
    }

    close($fh);
}

sub import(){

    $filename = "<$filename";
    open (my $fh, $filename) || die "Can't open file $filename: $!";

    my $customcount=0;

    while (my $line = <$fh>){
        chomp $line;
        if ($line){
            my @v = split(/\t/, $line);
            if (@v[0] eq 'custom'){
                my ($custom, $name, $command, $binding) = @v;
                print "Installing custom keybinding: $name\n";
                print `gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom$customcount/ name \"$name\"`;
                print `gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom$customcount/ command \"$command\"`;
                print `gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom$customcount/ binding \"$binding\"`;
                $customcount++;
            } else {
                my ($path, $name, $value) = @v;
                print "Importing $path $name\n";
                print `gsettings set \"$path\" \"$name\" \"$value\"`;
            }
        }       
    }
    if ($customcount > 0){
        my $customlist = "";
        for (my $i=0; $i<$customcount; $i++){
            $customlist .= "," if ($customlist);
            $customlist .= "'/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom$i/'";            
        }
        $customlist = "[$customlist]";
        print "Importing list of custom keybindings.\n";
        print `gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings \"$customlist\"`;
    }

    close($fh);
}
Pablo Bianchi
  • 15,657