GNOME键盘快捷键存储在哪里?

我通常在每次发布时加载新版本,以保持我的操作系统更新,同时将上一个版本保存在另一个分区作为备份。我还使用了很多自定义键映射。
到目前为止,我已经找出了如何在不同系统之间传输大部分配置,但是我无法弄清楚自定义键盘快捷键映射存储在哪里。
有人知道gnome把它们放在哪里吗?是否有单独的用户配置文件(即~/)和系统配置文件(即/etc)?

2你是怎么改变设置的?使用GConf编辑器吗?我猜你想要gconftool-2 --dump /apps/metacity或类似的命令。 - Mikel
1@Mikel 非常感谢你的评论。根据我在gconf-editor中的观察,大部分的键绑定都存储在/apps/metacity下,而其余的则分散在其他地方。我目前正在编写导入/导出的Python脚本,以便将备份和恢复键绑定变成一键操作。 - Evan Plaice
5个回答

Ubuntu自其他回答此问题的时间以来发生了变化。
键绑定已从gconf移至dconf。Gconf将其数据存储在XML文件中,并通过"gconf-editor"和"gconf-tool2"进行访问。Dconf将其数据存储在二进制格式中,并通过"dconf-editor"和"gsettings"进行访问。
存储键绑定的位置数量减少了。现在有一个集中的dconf路径来存储窗口管理器的键绑定("org.gnome.desktop.wm.keybindings")。在目录"/usr/share/gnome-control-center/keybindings/"中有映射文件,根据实际使用的窗口管理器(compiz或metacity)显示如何应用这些键绑定。
第二组与窗口管理器无关的键绑定存储在dconf路径"org.gnome.settings-daemon.plugins.media-keys"中。

关于电源按钮的键绑定,还有一个与之相关的第三组键绑定存储在dconf路径org.gnome.settings-daemon.plugins.power中。目前GUI中存在一个错误,它不知道这些设置,因此无法让您配置键绑定。我的键盘上有一个“睡眠”按钮。如果我想重新分配它到其他功能,我必须手动禁用org.gnome.settings-daemon.plugins.power中的设置。GUI不会为我完成这个操作(尽管它可以很好地分配新的功能)。

另一个问题是自定义键绑定。这些使用可重定位模式存储在dconf中。之所以这样做,是因为它们的数量是任意的。这是一种合理的方法,但这使得通过命令行列出或修改它们比本应更困难。

我还发现允许您分配键绑定的GUI有一个限制,令我感到恼火。该GUI只允许为每个操作分配一个键绑定。而在dconf中,您可以为单个操作设置一系列绑定。对我来说,这非常有用。例如,我喜欢将“关闭窗口”操作同时分配给传统的Alt-F4和键盘上更容易按到的单个按钮。

我已经编写了一个Perl脚本,用于将所有的按键绑定导出到一个csv文件中,或者从csv文件中恢复它们。例如,要导出按键绑定,你可以使用以下命令:
./keybindings.pl -e /tmp/keys.csv
要恢复按键绑定,你可以使用以下命令:
./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);
}

这包括了user2589537修复的功能,允许在自定义命令中使用引号。

2我对Ubuntu Gnome-Control-Center键盘快捷方式提交了两个错误报告。在编写这个脚本时,我发现了它们。错误报告链接如下:https://bugs.launchpad.net/ubuntu/+source/gnome-control-center/+bug/1079190 和 https://bugs.launchpad.net/ubuntu/+source/gnome-control-center/+bug/1079198 - Stephen Ostermiller
1感谢脚本,@Stephen。我刚在Ubuntu 13.10上尝试了一下,结果完美运行!为了方便分享,我创建了一个gist:https://gist.github.com/elgalu/8511861#file-keybindings-pl - Leo Gallucci
干得好,记录细节做得不错。 - Evan Plaice
2仍然适用于Ubuntu GNOME 3.2 - 谢谢! - klequis
以导出模式运行 - 输出看起来不像CSV。 - nhed
1对我来说,"works" 在技术上是可行的,但可能需要观察不同的 dconf 部分以适应 Ubuntu-MATE(例如 [org/mate/marco/global-keybindings][org/mate/marco/window-keybindings],...)。 - Frank N
另一个问题是自定义按键绑定。这些按键绑定存储在dconf中,使用可重定位模式。我该如何通过命令行界面访问它们?上述的Perl脚本没有考虑到这一点。 - n0tis
@n0tis 那个脚本中有一堆代码来处理自定义按键绑定。它使用gsettings list-recursively来查找它们。 - Stephen Ostermiller
然后显然在ubuntu 20.04gnome 3.36.8上找不到任何我自定义的快捷方式。它们在导出的CSV文件中也不存在。 (我的意思是新自定义命令的快捷方式) - n0tis

如何备份dconf设置,例如键盘快捷键。
  1. 将它们全部转储到一个文件中:

    dconf dump / > ~/.config/dconf/user.conf
    
  2. 在文本编辑器中打开该文件,并选择您关心的设置:

    editor ~/.config/dconf/user.conf
    

    如果您使用Vim,您会想要启用语法高亮

    很快您会问自己<Primary>是什么意思

  3. 如果您不知道设置的名称,但知道如何从类似unity-control-center的图形界面进行修改,请运行:

    dconf watch /
    

    然后进行修改。确切的设置将出现在终端上。

  4. 当您想要恢复这些设置时,请运行:

    dconf load / < ~/.config/dconf/user.conf
    
  5. 使用Git跟踪配置文件,以免丢失它。Homeshick是我目前最喜欢的方法。

在Ubuntu 15.10上进行了测试。提示来源于这里
很不幸,Gnome终端对此类编辑由于不可预测的配置文件ID有所抵抗。
相关文章:如何恢复默认的键盘快捷键?

2dconf watch /点赞 - 真是省时利器! - benzkji
1唯一真正有效的解决方案,节省时间。适用于Ubuntu 18.04。如果您在快捷方式中有复杂的命令,可能会去除空格。请仔细检查,并根据需要添加。 - Mijo

保存自定义键盘快捷方式

您可以使用dconfsed来保存/备份/导出自定义快捷方式/键绑定。

导出

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

与通常的答案不同之处在于,这将在文件中保存dconf设置的路径,使导入变得更加容易,只需使用dconf load / < file命令即可。

导入

dconf load / < custom-shortcuts.conf # Import

注意事项

  • 基于Ciro的回答(也可以在这里找到)

  • 仅适用于添加的自定义快捷方式

  • 请注意,dconf只会转储非默认值

  • 为了备份,您可能想使用custom-shortcuts-$(date -I).conf

  • 在导入之前,通过重置为默认值来测试是否有效

    gsettings reset-recursively org.gnome.settings-daemon.plugins.media-keys
    

在运行Gnome经典版的11.10中,我发现了一组目录(Custom0,Custom1...)在下面。
$HOME/.gconf/desktop/gnome/keybindings

我将这些目录复制到一个干净的12.04安装中的同一文件夹中(再次运行Gnome fallback),退出登录后重新登录。在过渡中,快捷键有点混乱(SUPER修饰符发生了一些有趣的事情),但除此之外,它们都还在。

有一个小问题是,接受的答案无法处理带引号的自定义命令。我只是改变了自定义命令的处理方式,以生成正确的输出。
#!/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);
}

在AskUbuntu上的出色第一个回答!恭喜! - Fabby
我已将您的更改合并到被接受的答案中。 - Stephen Ostermiller