2010年 3月 31(水曜日)
watch_videos 形式のURL対応YouTubeにいつの間にか仕様が追加されています。URLに"watch_videos"が付くものがそれで、例えば、<<http://www.youtube.com/watch_videos?more_url=%2F&video_ids=BOjWxqFKA4g....>>の形式です。 YouTubeダウンローダとダウンロードスクリプトでこの対応をしました。このフォーマットのURLのページを開いてみた範囲では、"watch?v=xxx"のURLのページと見た目に違いはありません。このため動作上の違いは分りませんでしたが、いずれにせよ、動画が自動再生されますので、このビデオを取得することになります。 ところで、ソフトウェア的にもこのフォーマットには謎があります。このURLにアクセスすると、<<http://www.youtube.com/watch?v=BOjWxqFKA4g&...>>に転送(リダイレクト)されます。転送先は一見何の変哲もないいつものフォーマットのページのようなのですが、ここから取得した"fmt_url_map"を使うと、直接ダウンロードできないようなのです。取得できるビデオ識別子(watch?v=xxx)を使えばダウンロードできるのですが、実際、見比べてみますと、この2つの"fmt_url_map"は確かに違っているのですが、どう直すのが正解なのか今一不明です。 そこで、ビデオ識別子を使ってページを取得し、その中から"fmt_url_map"を取ることにしました。ビデオ識別子は、"video_ids"パラメタの最初のもののようです。しかし、このフォーマットのURLはサンプルが少ないため確証が持てなかったので、取得できなかった場合はリダイレクトページの中からビデオ識別子を捜すようにしました。 こんな感じです。 #--- YTPid from watch_videos type URL sub GetYtpidFromWatchVideos { my ($url) = @; my $ytid = ""; my $durl = urldecode($url); #--- like http://www.youtube.com/watch_videos?more_url=/ #--- &video_ids=BOjWxqFKA4g,yHeiXcg1M5c,Ki4dgped5d0,2D296Xi2FLY #--- &type=11&feature=featured&no_autoplay=1 if ($durl =~ m![?&]video_ids=([^&,;]+)!) { $ytid = "http://www.youtube.com/watch?v=${1}"; } else { $ytid = GetYtpidFromWatchVideosFromWeb($url); }
Dprint "GetYtpidFromWatchVideos($url)->($ytid)"; return $ytid; } sub GetYtpidFromWatchVideosFromWeb { my ($url) = @_; my $ytid = ""; my $opts = "-q -U \'$UAgent\'"; if ($url =~ m!(http://[^/]+/)!) { $opts .= " --referer=\"${1}\""; } my $cmd = "wget $Options -O - \'$url\'"; Dprint "COMMAND: $cmd"; my @pgcontents = `$cmd`; foreach (@pgcontents) { # Dprint "pgcontents: $_"; chomp(); if (m!<link rel=\"canonical\" href=\"([^\"]+)\">!) { $ytid = "http://www.youtube.com$1"; } elsif (m|\'VIDEO_ID\': \'([^\']+)\',|) { $ytid = "http://www.youtube.com/watch?v=${1}"; } } Dprint "GetYtpidFromWatchVideosFromWeb($url)->($ytid)"; return $ytid; }
これにて、取得に失敗していたビデオが所得できるようになったと思います。
2010年 3月 17(水曜日)
Linuxで使える世界時計
サーバのメンテナンスのために休止したり、データを入れ換えるのは、利用者になるべく不便を掛けないような時刻を選ぶようにしています。最近は海外からのアクセスが結構あるので、海外の時刻が何時なのか気になっていました。ヨーロッパとの時差は何となく実感としてあるのですが、アメリカは今何時なのだろう、と。 それで、良く証券会社の仕事場の映像に出ているような、壁に世界中の都市の時刻を表示する時計が一杯並んでいるようなものが欲しいなと思いました。
検索してみると、意外なことに、こういった世界時計は多くありません。なんだか平気で有料シェアウェアとかになっています。時差があるだけで簡単なものだと思うのですが。このため、時計を横に並べたようなものを自分で作ってみようかとemiclockのソースを取ってきたりしたのですが、残念ながらこれはGPLではないため改造して使うことはできないようです。 zdumpそうこうしている内に、zdumpというプログラムを見つけました。使い方は簡単で、 $ zdump Europe/Pais Europe/Paris Wed Mar 17 06:54:09 2010 CET
これで現在時刻の表示ができました。色々な場所を一度に表示したければ、 $ zdump Europe/London Australia/Sydney Asia/Tokyo Asia/Singapore Asia/Katmandu Europe/Paris \ Europe/Moscow America/New_York America/Los_Angeles Africa/Kinshasa Pacific/Honolulu Europe/London Wed Mar 17 05:55:57 2010 GMT Australia/Sydney Wed Mar 17 16:55:57 2010 EST Asia/Tokyo Wed Mar 17 14:55:57 2010 JST Asia/Singapore Wed Mar 17 13:55:57 2010 SGT Asia/Katmandu Wed Mar 17 11:40:57 2010 NPT Europe/Paris Wed Mar 17 06:55:57 2010 CET Europe/Moscow Wed Mar 17 08:55:57 2010 MSK America/New_York Wed Mar 17 01:55:57 2010 EDT America/Los_Angeles Tue Mar 16 22:55:57 2010 PDT Africa/Kinshasa Wed Mar 17 06:55:57 2010 WAT Pacific/Honolulu Tue Mar 16 19:55:57 2010 HST
というふうにできます。いつも一時に表示したければ、こんな感じで良いでしょう。 $ alias wclock='zdump Europe/London Australia/Sydney Asia/Tokyo Asia/Singapore Asia/Katmandu \ Europe/Paris Europe/Moscow America/New_York America/Los_Angeles \ Africa/Kinshasa Pacific/Honolulu'
worldclock.plさて、これで充分なのですが、ディストリビューションやバージョンによってはzdumpが動かないことがあるようです。何かのバージョン不整合があったのか、私のデスクトップマシンでは最初動きませんでした。いつも同じ時刻(グリニッジ標準時か東京時刻)を表示してしまいます。これは結局zoneinfoのインストールが上手くなかったようで、zoneinfoの少し新しいバージョンを入れたら動作するようになりました。元々はzoneinfo(/usr/share/zoneinfo)に.ics(中身はVCalendar)のファイルしかなかったのですが、追加したら拡張子が付かないバイナリファイル(TZif形式)が追加されてました。 それで、動かない間に、元々の.icsファイを読んでzdumpと同じ動作をするworldclock.pl(worldclock.pl.zip)を作成しました。こちらは少しおまけが付いていて、都市だけで、もしくは都市名に完全に一致しなくても、マッチするものを表示します。 $ worldclock.pl Par 03/17 Wed 03:19:47 2010 SRT America/Paramaribo 03/17 Wed 07:19:47 2010 CET Europe/Paris
こちらも、都市名(Aria/City)を複数指定して、上記のwclockのようにalias等を設定することができます。 #!/usr/bin/perl $Usage = "$0 [-h] [-verbose] [Aria/]city ...\n";
$ZoneinfoDir = "/usr/share/zoneinfo"; @WeekdayName = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); @MonthName = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); $Verbose = 0;
#--- interpret the command-line arguments while ($ARGV[0]) { # print STDERR "$ARGV[0]\n"; if ($ARGV[0] =~ /^-D.*/) { $Debug = 1; } elsif ($ARGV[0] =~ /^-v.*/) { $Verbose = 1; } elsif ($ARGV[0] =~ /^-.*/) { print STDERR "$Usage"; exit 0; } else { last; } shift(@ARGV); }
#--- checking to set the necessary variables. #--- DebugPrint function #$Debug = 1; sub Dprint { if (defined($Debug)) { printf STDERR "DBG @_"; } return 0; } Dprint "ARGS($#ARGV): @ARGV\n";
#--- Current time of Greenwich. $gm_time = time() - 9 * 60 * 60;
#--- Check zoneinfo dir if (!-d $ZoneinfoDir) { my @zdirs = `locate /zoneinfo/Asia/Tokyo.ics`; #-- Use the first one without reasons. if ($#zdirs < 0 || $zdirs[0] !~ m|^(.*)/[^/]+/[^/]+$/|) { printf STDERR "$0 zoneinfo directory is not found."; exit(-1); } $ZoneinfoDir = $1; Dprint "ZoneinfoDir ($ZoneinfoDir)\n"; }
#--- Create file list foreach my $arg (@ARGV) { my @matchs_complete = (); my @matchs_partial = (); my $sout = ""; if ($arg =~ m|/|) { #-- Asia/Katmandu if (-f "$ZoneinfoDir/$arg.ics") { push(@matchs_complete, "$ZoneinfoDir/$arg.ics"); } @matchs_partial = glob("$ZoneinfoDir/${arg}?*.ics"); } else { #-- Katmandu @matchs_complete = glob("$ZoneinfoDir/*/$arg.ics"); @matchs_partial = glob("$ZoneinfoDir/*/${arg}?*.ics"); } Dprint "Complete: (@matchs_complete)\n"; Dprint "Partial : (@matchs_partial)\n"; foreach my $zfile (@matchs_complete) { $sout = GetLocalTimeString($zfile); print "$sout\n"; } foreach my $zfile (@matchs_partial) { $sout = GetLocalTimeString($zfile); print "$sout\n"; } }
exit 0;
#--- sub GetLocalTimeString { my ($zf) = @_; my $srtn; open(IN, "<$zf") or return ""; my @czf = <IN>; close(IN); my ($tzsign, $tzhour, $tzmin, $tzname) = ("", "", ""); foreach (@czf) { if (m|TZOFFSETTO:([+-])([0-9]{2})([0-9]{2})|i) { ($tzsign, $tzhour, $tzmin) = ($1, $2, $3); } elsif (m|X-LIC-LOCATION:(.+)|i) { $tzlocation = $1; } elsif (m|TZNAME:([a-zA-Z]{3})|i) { $tzname = $1; } } Dprint "($tzsign, $tzhour, $tzmin, $tzname)\n"; if (length($tzhour) <= 0 || length($tzmin) <= 0 || length($tzsign) <= 0) { return ""; } my $lc_time; if ($tzsign eq "-") { $lc_time = $gm_time - ($tzhour * 60 + $tzmin) * 60; } else { $lc_time = $gm_time + ($tzhour * 60 + $tzmin) * 60; } Dprint "($gm_time, $lc_time)\n"; my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($lc_time); if ($isdst) { #-- The aria supports summer time. ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($lc_time + 60 * 60); $tzlocation .= " (ST)"; } $srtn = Fmt($mon + 1, 2) . "/" . Fmt($mday, 2) . " $WeekdayName[$wday] " . Fmt($hour, 2) . ":" . Fmt($min, 2) . ":" . Fmt($sec, 2) . " " . ($year + 1900) . " $tzname " . "$tzlocation";
return $srtn; }
#--- sub Fmt { my ($nbr, $kta) = @_; return sprintf("%0${kta}d", $nbr); }
因みにzoneinfoがあるディレクトリは/usr/share/zoneinfoだと思いますが、これがなかった場合、あるいはあってもVCalendar形式ファイルがなくTZifのバイナリファイルだけの場合には、システム中からlocateで捜します。evolutionの下にあったりするようです。
2010年 3月 16(火曜日)
Type-Map (var)の作成前回、ウェブページの国際化に関して書きました。結論としては、type-mapを使って、.varファイルを作成すれば良いということでした。このtype-mapファイル作成を手作業でやるのは面倒ですので、生成スクリプトmktypemap.pl.zipを作りました。 使い方は以下の通りです。 カレントディレクトリのhtmlファイルとjpgファイルに対してlvarファイルを作成します。 mktypemap.pl *.html カレントディレクトリのファイル全部を対象とし、既にvarファイルがあるときは上書きします。 mktypemap.pl -f .
ここでは、"foo.php"に対して国際化されたファイルが"foo.ja.php"もしくは"foo.php.ja"の形式に対応します。 中身は以下のようなものです。 基本的に各々のファイルに対して言語違いファイルを捜して、それらをまとめて".var"ファイルを作成します。 #!/usr/bin/perl $Usage = "$0 [-h] [-S[imulate]] [-force] [-quiet] [--] files_to_create_var\n";
$Simulate_Mode = 0; #-- all procedure is simulated without creating files. $Verbose = 1; #-- print out many messages. $ForceOverwrite = 0; #-- When not set, .var file isn't created if exist.
#--- interpret the command-line arguments while (defined($ARGV[0])) { # print STDERR "$ARGV[0]\n"; if ($ARGV[0] =~ /^-D.*/) { $Debug = 1; } elsif ($ARGV[0] =~ /^-q.*/) { $Verbose = 0; } elsif ($ARGV[0] =~ /^-f.*/) { $ForceOverwrite = 1; } elsif ($ARGV[0] =~ /^-S.*/) { $Simulate_Mode = 1; } elsif ($ARGV[0] =~ /^-.*/) { print STDERR "$Usage"; exit 0; } elsif ($ARGV[0] =~ /^--/) { shift(@ARGV); last; } else { last; } shift(@ARGV); }
#--- checking to set the necessary variables. #--- DebugPrint function #$Debug = 1; sub Dprint { if (defined($Debug)) { printf STDERR "DBG @_"; } return 0; } Dprint "ARGS($#ARGV): @ARGV\n";
#--- If there are no files in arguments, all files in the current directory should be checked. if ($#ARGV < 0 || $ARGV[0] eq ".") { @files = glob("*"); } else { @files = @ARGV; }
#--- Create file list %typemap_created = (); #--- type-map file created by the program. foreach my $fle (@files) { my ($bdy, $lng, $ext); if (!-f $fle || -d $fle || $fle =~ m|\.var$|i) { next; } elsif ($fle =~ m|~$|i) { next; } elsif ($fle =~ /\.(html|htm)$/i) { #--- at this moment, html is a dummy to transfer to php. next; } elsif ($fle =~ m|^(.*)\.([^.]{2})(\.[^.]+)$|i) { #--- like foo.de.html ($bdy, $lng, $ext) = ($1, $2, $3); Dprint "(FILE 1: ($fle)($bdy, $lng, $ext)\n"; } elsif ($fle =~ m|^(.*)(\.[^.]+)\.([^.]{2})$|i) { #--- like foo.html.de ($bdy, $lng, $ext) = ($1, $3, $2); Dprint "(FILE 2: ($fle)($bdy, $lng, $ext)\n"; } elsif ($fle =~ m|^(.*)\.([^.]{2})$|i) { #--- like foo.de ($bdy, $lng, $ext) = ($1, $2, ""); Dprint "(FILE 3: ($fle)($bdy, $lng, $ext)\n"; } elsif ($fle =~ m|^(.*)(\.[^.]+)$|i) { #--- like foo.html ($bdy, $lng, $ext) = ($1, "ja", $2); Dprint "(FILE 4: ($fle)($bdy, $lng, $ext)\n"; } else { next; }
if ($lng eq "js" || $ext eq ".js") { #-- should be a java script file. next; } if (!$ForceOverwrite && -f "$bdy.var") { next; } elsif (exists($typemap_created{"$bdy.var"})) { next; } my $str = CreateTypeMap($bdy, $ext); if (length($str) > 0) { my $fvar = "${bdy}.var"; if (!$Simulate_Mode) { open(FOUT, ">$fvar") or next; printf FOUT "$str"; close(FOUT); } $typemap_created{$fvar} = 1; } }
exit 0;
#--- Creating contents of type map file sub CreateTypeMap { my ($bdy, $ext) = @_; my @grpfiles = glob("${bdy}${ext} ${bdy}.*${ext} ${bdy}${ext}.??"); Dprint "CreateTypeMap: ($bdy, $ext)\n"; Dprint "@grpfiles\n"; my $s = ""; foreach (@grpfiles) { my ($b, $l, $e); Dprint "CreateTypeMap: ($_)\n"; if (!-f $ || -d $ || /\.var$/i) { next; } elsif (/~$/i) { next; } elsif (/\.(html|htm)$/i) { #--- at this moment, html is a dummy to transfer to php. next; } elsif (/^(.*)\.([^.]{2})(\.[^.]+)$/) { #--- like foo.de.php ($b, $l, $e) = ($1, $2, $3); } elsif (/^(.*)(\.[^.]+)\.([^.]{2})$/) { #--- like foo.php.de ($b, $l, $e) = ($1, $3, $2); } elsif (/^(.*)\.([^.]{2})$/i) { #--- like foo.de ($b, $l, $e) = ($1, $2, ""); } elsif (/^(.*)(\.[^.]+)$/) { #--- like foo.php ($b, $l, $e) = ($1, "ja", $2); } else { next; } if ($l eq "js" || $e eq ".js") { #-- should be a java script file. next; } Dprint "CreateTypeMap: ($b, $l, $e)\n"; my $hder = "URI: $_\nContent-Language: $l"; $cty = GetContenttype($e); if ($cty eq "text/html") { $chs = GetCharset($l); $ctyp = "Content-type: text/html; charset=$chs\n"; } else { $ctyp = "Content-type: $cty\n"; } if (length($s) > 0) { $s .= "\n"; } $s .= "$hder\n$ctyp"; } #if (length($s) > 0) { # $s = "URI: $bdy; vary=\"type,language\"\n\n" . $s; #} Dprint "$s\n"; return $s; }
#--- Get the charset sub GetCharset { my ($lg) = @_; my $c; if ($lg eq "ja") { $c = "UTF-8"; } else { $c = "ISO-8859-1"; } return $c; } #--- Get the content type sub GetContenttype { my ($e) = @_; my $c; if ($e =~ /(jpg|jpeg)$/i) { $c = "image/jpeg"; } elsif ($e =~ /gif$/i) { $c = "image/gif"; } elsif ($e =~ /png$/i) { $c = "image/png"; } elsif ($e =~ /(php|html|htm)$/i) { $c = "text/html"; } elsif ($e =~ /zip$/i) { $c = "application/zip"; } elsif ($e =~ /(tgz|tar)$/i) { $c = "application/x-tar"; } else { $c = "application/octet-stream"; } return $c; }
なお、このコードでは、"#--- at this moment, html is a dummy to transfer to
php."のところにあるように、".html"に対しては".var"ファイルを作成しません。これは私は".php"としてコンテンツを作成している
ためで、".html"は昔からあるコンテンツや外部からのリンクが切れないように転送ページを置いています。 このファイルは以下のようなものです。 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html lang="ja"> <head> <title>301 Moved Permanently</title> <meta http-equiv="refresh" CONTENT="0;URL=index.var"> <meta name="robots" content="NOINDEX,NOFOLLOW"> </head> <body> このページは、<a href="index.var">http://www.nikep.net/</a>に移転しました。 自動転送されない場合は、このアイコン<a href="index.var"><img src="home3.png"></a>を 押して下さい。<br/> Requested page was transfered to <a href="index.var">http://www.nikep.net/</a>. If you can see this text, please click the following icon <a href="index.var"> <img src="home3.png" alt="nikep"></a>. </body> </html>
2010年 3月 11(木曜日)
Apacheの多言語化壁紙サービス(アプリ)を国際化して、海外のサイトで配布しています。意外にも、国内よりも海外のほうで使ってくださる人が多く、サイト自体のアクセスも海外からが増えてきました。そのため、最近は少しずつ英訳を進めています。しかし、ページが増えてくると、色々と課題が出てきて手作業が増えてきましたので、システマチックな方法で対応することにしました。 ページの英訳ページを英訳するには、以下の作業を行います。 - 内部テキストを英語に翻訳します。
- ページに記載されたハイパーリンクで、既に翻訳済みページがある場合は、そちらを差すようにします。埋め込みのイメージファイルに関しても同様にします。
- 当該ページにアクセスする際の(別ページ等にある)リンクを、英語言語リーダ向けには英語のページに変更します。
この内、テキストの翻訳は手で行うしかありませんが、2)や3)は手作業でやるのが手間になってきたのと同時にバグったりしてきました。このため、2)に関してはPHPで関数を書いて対応していたのですが、3)の対応を行うに際し、Web Server (Apache)の機能を調べてみました。 国際化の方法apacheの国際化の方法は2種類あります。いずれの方法も、閲覧者から指定された"Accept-Languages"を参照して、適切な言語のファイルを自動的に返す仕組です。 | 方式 | 設定 | やり方 | 課題 | MultiViews | httpd.confに"Options MultiViews"を設定する。(通常デフォルト) | foo.htmlに対して、foo.html.en, foo.html.jaを配置する。foo.htmlは置かない。 foo.htmlにアクセスすることにより、言語に合わせたfoo.html.xxが返される。 | 直感的で簡単。 処理が遅いらしい。 foo.htmlを置けないのは気持ちが悪い(置くと直接アクセスでこちらが開かれてしまう) | Type-Map | httpd.confに "AddHandler type-map var"を設定する。(通常デフォルト) DirectoryIndex index.var index.php index.html 等と書く。 | foo.varを作成してfoo.en.html, foo.ja.htmlなどを配置する。foo.htmlは置かない。 foo.varにアクセスすることで、ファイル内に設定された適切な言語に合わせたファイルが返される。 | こちらの方法のほうが新しい。 処理が速いとのこと。 別ファイルを置かなくてはならないのはちょっと嫌。(もしくは、foo.htmlをvarファイルにすることも可能) |
特に理由がなければ、Type-Mapの方法を使うのが良さそうです。 実際の設定foo.htmlに対して、foo.varのファイルを作成して、URLをfoo.varでアクセスさせることになります。ファイルは以下のようなものです。 URI: foo.en.php Content-type: text/html Content-language: en
URI: foo.ja.php Content-type: text/html;charset=utf-8 Content-language: ja
そして、国際化したページ全てのページに対して xxx.var を作成し、リンクを全て xxx.var を差すように変更します。 なお、例えばindexファイルであれば、DirectoryIndex に index.varを追加しないとならなりません。(これは、httpd.confの設定を変更します。なお、phpのバージョンに依っては、php.confの設定も変更/削除しないとならないかもしれません) これでOKなのですが、実際に想定されている使い方とは少し違うようです。apacheのmanualディレクトリでType-Mapが使われているのですが、ここではindex.htmlをvarファイルにしています。動作させるためには、SetHandlerが必要になります。 <Directory "/var/www/manual"> <Files *.html> SetHandler type-map </Files> </Directory>
このようにすると、外部からのURLを変更する必要がありませんので、透過的に設定することができて便利です。要するに、htmlファイルと思ってアクセスすると実体はtype-mapファイルで、その設定に従って適切なファイルが実際には返されることになります。 但し、この設定をしてしまうと、単なるhtmlファイルとして扱うこと(中身がtype-mapでないtext/htmlであればそのまま返すなどということ)はできなくなります。これはサブディレクトリにも伝播してしまいますので、取り扱いには注意が必要です。
2010年 3月 11(木曜日)
Happy Hacking Keyboardの設定
キーボードが壊れかけているのか押し難いキー出てきたので、中古のHappy Hacking Keyboard Lite (HHK Lite)を購入しました。一番安価なやつですが、それでもキータッチはかなりよく思います。(安物ばかり使ってきたせいもありますが)。このキーボードは昔のSUNのワークステーションと同じキー配列とのことで、backquote/asciitildaとBSの配置が少し変っています。またHHK Liteには独立の方向キーがないためにWindowsではちょっと使い難そうですので、UNIXがメインのマシンに付けることにしました。
若干のカスタマイズを施しました。OSはLinuxとWindowsXPです。 キーボードはディップスイッチの設定があり、若干のカスタマイズができます。私は使いませんが、日本語変換用のHenkan, Muhenkanのキーコードも出せるようです。さて、Fnキーの位置も特殊なので左下に設定したかったのですが、オリジナルのFnキーは動かすことができず、あきらめました。只でさえキーが少ないのに、これ以上減らすわけには行かないからです。 結局、DIPスイッチ、"1101"として、ここからはソフトウェア的にカスタマイズすることにします。スペースの横列は左から、Win_L, Alt_L, Space, Alt_R, Win_Rです。方法は、こちらに記載した方法を取ります。
個人的には右のキー(Alt_R, Win_R)は使わないので、足りないキーである Application (LinuxではMulti)キーと、BSにしてしまったために独立キーがなくなっているDeleteキーに割当てます。(Alt_R→Application、Win_L→Delete)。因みに 元々存在していないCaps_Lockは、ソフト的には設定することができないようです(?)ハードウェアでShift+TABでCaps_Lockトグルになります。
Linux/Xでは Xmodmapで設定します。
remove mod4 = Super_R
keycode 113 = Multi_key
keycode 116 = Delete
また、Windowsではレジストリをいじります。レジストリファイルはus_WinrDel_AltrApl.regです。これで快適になりました。
と思ったのですが、上で追加したDelete(元々の右Win/刻印は右Alt)はキーリピートが入らないようです。これはモディファイア系のキーはリピートしないというハード的な仕様なのでしょうね。仕方ないです。Xmodeを上記にしたらできました。
|