Windows8.1用にxkeymacsをビルド

追記 2015/8/14
たぶん、画面のサイズを125%とか150%にするとまたボタンが隠れてしまいます。根本的な解決にはならないのでご注意ください。


Surface3にxkeymacsをセットアップして立ち上げたけど、プロパティダイアログで、ボタンが隠れる問題に直面(^^;

xkeymacs-8.1

ダイアログリソースをいじればいいや、と思いxkeymacs-snap-110830のソースをダウンロードしてVisual C++ 2010 Express Edition + WDKでビルドしたんですが、以下のエラーでストップ。

Utils.cpp(461): error C2039: 'GetString' : 'CString' のメンバーではありません。

ふむふむ、GetStringがないんだったら、強引にキャストしてまえ!ってことで、

//修正前
memcpy(pMem, text.GetString(), nLength);

//修正後
memcpy(pMem, (LPCSTR)text, nLength);

で切り抜け。

xkeymacs.rcだけVisual Studio Communityで適当にサイズ修正。
プロパティーシートで使用されるフォントがメイリオになってしまうのが原因?
ソース追えるほどMFCに精通していないため、ダイアログリソースだけ場当たり的に修正してビルド。

今度はちゃんとボタンが表示されました。

xkeymacs-8.1-2

めでたし!

ファイルの置き場に置いてます (xkeymacs-only-win8.1) 無保証

最後にリリースされてから4年と久しくバージョンアップされていないようですが、
Windows10も出ることですし、ダイアログ関連のメンテナンスリリースしてほしい<m(__)m>

「Surface3買ったらやること」リスト

かなり楽しみだったSurface3。 買いました。大きさは、古いiPadと比べてちょっと大きいぐらい。Surface Pro 3ほど大きすぎず、僕にはちょーどいい大きさです。ただ、もうちょっと薄ければな・・・というのが、正直な感想です(^.^;

ディスプレイもかなりキレイで、いい感じの発色具合です。関係ないけど・・・ネットによくあるレビューで、「Macよりは劣るけど」とか「iPadには負けるけど」とか、書いてる記事は正直あまり信用できません。 そういう記事は、少なからずマイクロソフトに変なバイアスがかかってたり、アップルに対して(故ジョブズに対して)相当アンカリングされているので(笑) ま、そういう僕も、超偏見ですがね(^_^;;;

期待通りのバランスの良さで、買って良かったです。USB充電ですので、これまでのクソ重いアダプターを持ち運ぶ必要もなく、MicroUSBなケーブル持っとけばどこでも充電できそう。

問題は、US配列のタイプカバーをどこから調達すればいいのか・・・? だったんですが、結局 Amazon.co.jpから素直に並行輸入業者さんが出品しているものを買いました(^^;;; 高っかいけど、探す手間や手続きとか考えると、まぁ、いいかな。

IMG_1382 CIGah5rUkAA4Ij4_orig

US配列のタイプカバーのバックライトがカッコいい & 暗い場所で威力発揮(^.^)

正直ストレージが128GBだと、Windows本体とか除くと残り94GB程度。 ちょっと速めの128GBのMicroSDカードが1万弱で売ってたので買い足し。

ってなわけで、前置きが長くなりましたが、新しいパソコン買ったら、使えるまでには、やることはいっぱいあります。

  1. IMEトグル問題。ALT+` なんて打ってられない。即、右ALTキーに割り当て
  2. CAPS LOCK ⇔CTRL の入替。これはレジストリ編集で完了。
  3. xkeymacsでキーバインド変更。  ← イマココ
  4.  WAMP環境セットアップ
  5. TortoiseSVN セットアップ

後は、動画プレーヤーとか、iTunesとか、入れるとガンガンディスク容量が減っていきますね。。。

肝心の動作ですが、いくら新しい目とはいえ、しょせんAtomプロセッサなんで期待はしていなかったですが、印象としては、かなり「サクサク感」・「ヌルヌル動く感」があります。

2日ほど色々使ってますが、今のところ、動作が引っかかる、とか重い! とか感じたことはなく、まぁ、重い処理を意識してしないようしてますが(笑)、ストアアプリを結構いっぱい開いて、Chromeでガンガンタブを開いても、4GBのメモリ容量のせいか、今のところメモリ不足でストレスを感じることはないです。

あとは・・・1ヶ月後リリース予定のWindows10にバージョンアップしたときに・・・まともに動くのかどうかですねぇ~。

amazonの商品ページから画像一覧を取得するブックマークレット

2017年1月18日 追記
アマゾンの画像を置いているサーバーのドメインが変わったみたい?
ドメイン名のところを修正しています(m´・ω・`)m ゴメン…


ひさしぶりにブックマークレット・ネタ。

会社でたまに、商品紹介の版下データをIllustratorで作成することがあるのですが・・・商品画像を集める作業は一苦労してました。あるときは、紙のカタログからスキャンしたり、PDFのページをリーダーで表示させた状態をスクリーンショット撮ったり(笑)、まぁ結構なんぎしてました。
でも最近は違います! アマゾンのサイトに行くと、ほぼ全ての画像が!!!(^^;;; ま、当たり前だけど、amazonに載ってある画像を勝手に版下データに流用するのはチョシャッケンを侵害!!! ってのは理解しているんですが、商品メーカーの販売会社の営業さんとかに問い合わせもらっても、いちいち対応がメンドクサイのか、アマゾンの画像を使えと(笑) 末端の下っ端なんてそんなもんですよ。

ってなわけで、ブラウザでいちいち右クリック・画像保存・・・とかいうルーチンは、パソコンが得意。

商品ページのHTMLコードをザラッと解析して(< オーバーだよ・・・)、ブックマークレットを作った。
だいたい、↓ こんな感じ。

/* 
amazonの任意の商品ページでF12キーでDevツールを出し、
コンソールにて以下をコピペして実行して試せます。
2017/1/18 画像サーバーのドメイン名をマッチするための正規表現を修正してます。
*/
(function($,undefined)
{
  var multi = {};
  var m = $.each($('body').html().match(/https?:\/\/images\-\w+\.ssl\-images\-amazon\.com\/images\/I\/(?:[\w%\-]+)(?:\._S[A-Z]\d+_)?\.jpg/g),
                function(i,v)
                {
                  var url = v.replace(/\._S[A-Z]\d+_/,'');
                  if(url in multi)
                    return;
                  multi[url] = null;
                });

  var urls = [];
  $.each(multi,
         function(url,v)
         {
           urls.push(url);
         });

  var len = urls.length;
  var doc = window.open("","image").document;
  doc.open("text/html");
  doc.writeln("<html><head><title>Imaging</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head><body><p><a href=\"javascript:window.close();\">ウィンドウを閉じる。</a></p><p>");
  for(var i=0;i<len;i++)
    {
      doc.writeln("<a target=\"_blank\" href=\"",urls[i],"\"><img width=\"100\" border=\"0\" src=\"",urls[i],"\"></a>");
    }
  doc.writeln("</p></body></html>");
  doc.close();

})(jQuery);

ただ、これだと、window.openメソッドを使っているので、ブラウザの設定によってはポップアップブロックされるかも。amazon.co.jpだけ例外設定してやればヨシ。

上のコードをコピペしてブラウザのデベロッパーツール>console にて確認してみてください。
ポップアップされたウィンドウまたはタブに画像がデデデと列挙されるはず・・・されなかったらごめんなさい。
画像は幅100ピクセルに縮小して表示されてますが、画像をクリックしてやると大きくなるはず・・・されなかったらごめんなさい。

wordpress.comでは javascript: なリンクは貼れないので、ミニファイしたコードを↓に書いときますので、適当なブックマークを作って、編集して、URLに、↓のコードをコピペして保存してください。

javascript:(function($,undefined){var multi={};var m=$.each($('body').html().match(/https?:\/\/images\-\w+\.ssl\-images\-amazon\.com\/images\/I\/(?:[\w%\-]+)(?:\._S[A-Z]\d+_)?\.jpg/g),function(i,v){var url=v.replace(/\._S[A-Z]\d+_/,'');if(url in multi)return;multi[url]=null});var urls=[];$.each(multi,function(url,v){urls.push(url)});var len=urls.length;var doc=window.open("","image").document;doc.open("text/html");doc.writeln("<html><head><title>Imaging</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head><body><p><a href=\"javascript:window.close();\">ウィンドウを閉じる。</a></p><p>");for(var i=0;i<len;i++){doc.writeln("<a target=\"_blank\" href=\"",urls[i],"\"><img width=\"100\" border=\"0\" src=\"",urls[i],"\"></a>")}doc.writeln("</p></body></html>");doc.close()})(jQuery);

使い方は・・・分かりますよね? amazonって、頻繁に表示方法を変えているので、たぶんそのうち使えなくなるかもですね。
あ、エッチな商品の画像を取っちゃだめですよ(笑) あくまでお仕事の一助に(^^;;;

ブックマークレットって何? どうやって登録するの? どうやって使うの? おいしいの? とかいうメンドクサイ人は・・・適当にググってください(_ _)

twitterのお気に入りの画像を一括ダウンロード

追記 2017/07/15
C#に書き直した修正版 → https://ptsv.jp/2016/04/20/tweet-image-download-agent/


追記 2015/11/10
修正版 → スクリプトを修正したものを投稿していますm(_ _)m


ツイッターで、検索したりタイムラインに流れる画像で気になったのは片っ端から「お気に入り」に入れてました。で、とある日曜の夜中にふと、「ファボッったツイートの画像を全部ダウンロードしたい!」欲求に駆られ、ググってみたら下記ブログ記事を見つけた。

dyama.org/2014/10/berryjack-simple-twitter-media-downloader-by-shellscript/

ここで書かれていたtimelineに直接リクエストを投げる方法を、ブラウザで確認しながら調べてみると、できそうだったので、シェルスクリプトを流用させてもらいました。(m_m)
・・・Windowsなので、perlに書き直して完了。Win32版のwget.exeが必要ですが・・・。

ただ、「お気に入り」の画像を一括ダウンロードするにはログインが必要なんで、その部分を調べて書くのが面倒だったんで、Internet Explorerでログインした後、クッキーをエクスポートし、twitter.comドメインの部分だけ抜き出し cookies.txt と保存し、それをwgetに食わせることで強引に解決(^^;;; とりあえずなんで目をつむる。

Twitter APIとか使わないといけないのかなー、と思ってたんですが、上記ブログ記事のシェルスクリプトのおかげで随分簡単にゲトできました。ありがとうございました(^.^)

探せば便利なソフトがあると思うんですが・・・簡単にできたんで別にいいか(^^;
また、時間があれば、C#に書き直してGUIつくろー。

#!/usr/bin/perl
# 使い方
#
# > perl twitter.pl 画像タイムラインのURL(下記参照)
#
# 【任意のTwitterIDの画像の場合】
# https://twitter.com/i/profiles/show/(TwitterID)/media_timeline

# 【自分のお気に入りの場合】
# https://twitter.com/(自分のTwitterID)/favorites/timeline
# 別途ログイン後のクッキーが必要。IEなどでログインしてエクスポート。
# twitter.comドメインだけ抜き出して 同じディレクトリにcookies.txt として保存する必要あり。
#
# tmpというディレクトリがカレントディレクトリに作成され、画像がダウンロードされます。
# ダウンロードエージェントに GNU Wgetを利用しています。
# おいらのようにwindowsな人は別途 Win32版 GUN WGETが必要。

# 【追記】 wgetを使用せず、LWP::UserAgentを使用するように加筆したものを一番下に追加

use bigint;
mkdir 'tmp' unless(-e './tmp');
$param = '';
$timeline = $ARGV[0] || die "input timeline url...\n";

@options = ('--no-check-certificate',
            '-O -',
            "-a ./tmp/wget_$$.log");
push @options,'--load-cookies=cookies.txt' if(-e 'cookies.txt');

$options = join(' ',@options);
do
{
  $wget = sprintf('wget %s "%s%s"',$options,$timeline,$param);
  print $wget,"\n";
  $result = `$wget`;
  $result =~ s/\\\//\//g;

  @result = $result =~ m!https://pbs\.twimg\.com/media/\w+\.\w{3,4}\:large!g;
  foreach(@result)
    {
      $out = '';
      if(m/(\w+\.\w{3,4})\:large$/)
        {
          $filename = "tmp/$1";
          $out = "-O $filename";

          unless(-e $filename)
            {
              system("wget --no-check-certificate -a ./tmp/wget_$$.log -P tmp -nd $out $_");
              print "saved $1\n";
            }
        }
    }

  @result = $result =~ m/data-tweet-id=\\\"([0-9]+)/g;
  @result = sort @result;

  $cxt_id = shift @result;
  $max_id = $cxt_id - 1;

  $param = "?contextual_tweet_id=$cxt_id&max_id=$max_id";
} while( $cxt_id );

【追記】

wget を使う代わりに、LWP::UserAgent を使用するように改変。使い方は上と一緒。
・・・なんか無駄にコードが増えた(ーー;;;

#!/usr/bin/perl

# 使い方は上記wgetを使用するものと一緒

use strict;
use warnings;
use bigint;
use LWP::UserAgent;
use HTTP::Cookies;
use Time::Piece;

#クッキーファイル名
my $COOKIE = 'cookies.txt';

#作業用クッキーファイルパス
my $TMP_COOKIE = './tmp/libwww.'.$COOKIE;

#エージェント
my $UserAgent = LWP::UserAgent->new;

&{sub
{
  #arguments
  my @argv = @_;
  mkdir 'tmp' unless(-e './tmp');

  my $tmp = "./tmp/$$.media";
  my $param = '';
  my $timeline = $argv[0] || die "input timeline url...\n";
  my ($cxt_id,$max_id);

  #cookies.txtがカレントディレクトリにあればフォーマット変換して作業用ファイルに保存
  if(-e $COOKIE)
    {
      &convert_cookie;
      $UserAgent->cookie_jar(HTTP::Cookies->new(file => $TMP_COOKIE,autosave => 1));
    }

  do
    {
      $timeline = $argv[0].$param;

      print "---- getting and parsing\n$timeline ...\n----\n";
      my $result = &lwp_agent($timeline,'-') || die "can not get timeline. may be wrong url.\n";
      $result =~ s/\\\//\//g;

      foreach my $url_($result =~ m!https://pbs\.twimg\.com/media/\w+\.\w{3,4}\:large!g)
        {
          my $out = '';
          if($url_ =~ m/(\w+\.\w{3,4})\:large$/)
            {
              my $filename = "tmp/$1";
              unless(-e $filename)
                {
                  &lwp_agent($url_,$filename);
                  print "saved $1\n";
                }
            }
        }

      my @result = $result =~ m/data-tweet-id=\\\"([0-9]+)/g;
      @result = sort @result;

      $cxt_id = shift @result;
      $max_id = $cxt_id - 1;

      $param = "?contextual_tweet_id=$cxt_id&max_id=$max_id" if(defined $cxt_id);

    } while( $cxt_id );

  print "done!\n";

  #作業用のクッキー削除
  unlink $TMP_COOKIE if(-e $TMP_COOKIE);

}}(@ARGV);

sub lwp_agent
{
  my ($url,$ofile) = @_;
  my %options = ();

  if($ofile ne '-')
    {
      return $UserAgent->get($url,':content_file' => $ofile);
    }
  else
    {
      if(my $response = $UserAgent->get($url))
        {
          return $response->decoded_content;
        }
    }
  0;
}

sub convert_cookie
{
  my $fin = IO::File->new($COOKIE);
  my $fout = IO::File->new('>'.$TMP_COOKIE);

  $fout->print("#LWP-Cookies-1.0\n");
  foreach my $line_($fin->getlines)
    {
      chomp $line_;
      next if($line_ =~ /^$/ || $line_ =~ /^\#/);
      my ($domain,$flag,$path,$secure,$expires,$name,$value) = split(/\s+/,$line_);
      my $t = gmtime($expires);
      $expires = sprintf('%s, %d-%s-%04d %02d:%02d:%02d GMT',
                         $t->day,
                         $t->mday,
                         $t->month,
                         $t->year,
                         $t->hour,
                         $t->min,
                         $t->sec);
      $secure = $secure eq 'TRUE' ? 'secure' : '';

      $fout->print(qq(Set-Cookie3: $name=$value; path="$path"; domain=$domain; path_spec; expires="$expires"; $secure\n));
    }

  $fin->close;
  $fout->close;
}
__END__

1年間無償でアップグレード提供!

今年はWindows8の後継バージョン、Windows10がリリース予定。
Appleに対抗したかったのか、Windows7以降のOSであれば、リリース日から1年間は無償でバージョンアップできる、とのこと。なぜ1年間なのかはさておき、どーせ、1年縛りは撤廃されるんじゃないかなあ。

Windows7もすでにセキュリティフィックスのみの更新になってしまったし、かつてのWindowsXPと同じ扱い。
僕的にWindows8/8.1はパソコンのOSとしては完全に失敗だと思う。SurfaceのOSとしては良いと思うんだけど。マウスとキーボードを使う、いわゆるパソコン(PC)のOSでは無かった、という意見の方が多いと思う(根拠無し・妄想)。

スタートメニューの善し悪しはともかく、スタートメニューの無いWindowsなんて、牛肉が入っていない、すき焼きと同じですよ! Windowsを名乗っちゃダメよ~ダメダメ!ですよ!(笑)