トップ 追記

parkの雑記帳

2007|12|
2008|01|02|03|04|05|06|07|08|09|10|11|
2009|03|04|05|08|09|11|12|

2009-12-26 [Sat]

[ハードウェア] 新型トラックポイントキーボード届いた

Twitterでとある人にそそのかされてLenovoのUSBトラックポイントキーボード (ThinkPad USB Keyboard with TrackPoint) を買ってしまいました。 これまでもその前身であるところnトラベルキーボードを愛用していたのですが、 最近マウス操作の中ボタンが壊れたりキーの印字が消えたりとかなりボロボロになっていたので ついポチってしまったわけです。

トラックポイントキーボードとゆかいななかまたち
トラックポイントキーボードとゆかいななかまたち

以下感想などをすこし。

ハードウェア面

キータッチは良い感じです。前身のトラベルキーボードは値段に対してかなり安っぽい感じでしたが 今度のはしっかりした感じがします。ただ、キーの形状が変わったため、人によっては 誤って隣のキーを押してしまうことが増えるかもしれません。

キー配列はT400sと同じです。Escと間違えてF1をおしてしまう事故がなくなったのはすばらしいです。 ただ、その関係でF1-F12キーの位置が変わっているので押し間違いがあるかも。

特殊キーはThinkPad専用っぽいのは使えませんでした。 使えるのは音量キー・スタンバイ・ブラウザ戻る進む・メディアプレーヤー操作でした。あと、ブラウザ戻る進むがAlt-左、Alt-右を送出する困った仕様はトラベルキーボードと同じでした。

ソフトウェア面

いつものSynapticsのやつじゃありません。 分解してみた人のレポートによると、 ThinkPadのキーボードユニットをLITEONのチップで変換しているとのことです。 トラベルキーボードではトラックポイントとキー部分とで別々に接続された基板が使われていたので、 内部的には全くちがうものになっているのでしょう。 それで、PCにインストールするプログラムもLITEONの作ったものっぽかったです。

使ってみた感じ、非常に残念。一部のプログラムにはスクロール開始時にCtrl-Kを送ったり、 Tweenをはじめとした.NET Frameworkのプログラムでスクロールできなかったり、なんかもう別物。 トラベルキーボードに戻そうかと本気で考えるぐらいのできでした。

まとめ

トラックポイントの使えるキーボードが今までよりはるかに安く入手できるというのは 非常に喜ばしいことなんですが、ソフトウェアが残念でなりません。 でもまあ、キータッチとかは良いので、6,000円ぐらいだしポチってしまっても 大損はしないんじゃないかなと思います。

[ハードウェア][ソフトウェア] 新型トラックポイントキーボードのスクロール改善

前のエントリでも書いた、Tweenをはじめとした.NET Frameworkのプログラムでスクロールできない問題。 これをアドホックな解決策でスクロールできるようにする方法を見つけてプログラム書きました。

FixSkmz.zip ※無保証、自己責任でお願いします。

原理とか

Spy++ (Visual Studio に付いてくる、ウィンドウメッセージとかを監視したりするツール) で ウィンドウメッセージを見てみると、WM_VSCROLL, WM_HSCROLL をPostしているようでした。 しかしながら、スクロールがされません。 試しに任意のウィンドウにPostMessage()するプログラムを作ってWM_VSCROLLをPostすると なんとスクロールされます。 この違いが何であるかをよく見てみると、トラックポイントの操作ではlParamが非NULLなのに対して 自分のPostMessage()ではNULLでした。 だったら、メッセージを細工してlParamをNULLにしてしまえば良い、という発想です。

実際にやるとなると、SetWindowHookEx()でWH_GETMESSAGEフックを仕込むことになりました。 ここでWM_VSCROLL, WM_HSCROLLが来た場合lParamをNULLにしてしまいます。 でもなんか怖いので.NET Frameworkのプログラムだけを対象にすることにしました。 どうやって判断するかは手抜きで、mscoree.dllをロードしているか否かを判断基準にしました。

実際に作ってみて動かす段階になっていざ試してみると完全に期待通りの動作。 なんかもう拍子抜けでした。

話は変わりますが、トラックポイントのスクロール、ちょっと感度が高すぎる気がします。縦方向だけにスクロールとか横方向だけにスクロールとかがやりづらい。まあそのうち改善されるといいんですが...


2009-12-14 [Mon]

[ソフトウェア] Tween改造 -Replyをちゃんとたどろう

前回のエントリで偉そうに書いていたのは初期設定でしか動きませんでした...

というのも、発言リストのソート順とかに依存していたみたいで、ちょっといじるとアラマうごかないわ。となってしまいましたとさ。

ということで GoInReplyToPost() メソッドを修正。

    Private Sub GoInReplyToPost()
        If _curPost IsNot Nothing AndAlso _curPost.InReplyToUser IsNot Nothing AndAlso _curPost.InReplyToId > 0 Then
            If _statuses.ContainsKey(_curPost.InReplyToId) Then
                Dim idx As Integer = _statuses.Tabs(_curTab.Text).IndexOf(_curPost.InReplyToId)
                If idx = -1 Then
                    Dim repPost As PostClass = _statuses.Item(_curPost.InReplyToId)
                    MessageBox.Show(repPost.Name + " / " + repPost.Nickname + "   (" + repPost.PDate.ToString() + ")" + Environment.NewLine + repPost.Data)
                Else
                    SelectListItem(_curList, idx)
                    _curList.EnsureVisible(idx)
                End If
            Else
                OpenUriAsync("http://twitter.com/" + _curPost.InReplyToUser + "/statuses/" + _curPost.InReplyToId.ToString())
            End If
        End If
    End Sub

[ソフトウェア] Tween改造 -ビルドエラーを無視しない

なんかシリーズみたいになってきました。

Tweenを改造して遊ぶにはソースコードをダウンロードして、手元のVisual Studio (2005以降) で適当にいじってビルドします。

しかし、環境によってはビルドしたときに "c:\Program Files\Microsoft.NET\SDK\v2.0\Bin\sgen.exe" が見つからない旨のエラーが表示されると思います。これはおそらくメイン制作者さんの.NET Framework SDKのインストールディレクトリをプロジェクトに直打ちしているから悪いのでしょう。私の環境にはこんなディレクトリありませんし。

実は、Visual Studioのプロジェクトでは $(FrameworkSDKDir) というマクロを使うことでこの問題を回避できます。まあマクロ名通りな内容なんですが。プロジェクトのプロパティからビルドイベントでこのへんを適当に編集するとエラーが無くなるはずです。

[ソフトウェア] Tween改造 -Replyをたどって戻ろう、タブをまたいで

in_reply_to をたどる機能を付けた私家版を使っていて思いました。元発言の方向にたどるのも良いけど時系列順でもたどりたい。

ということで、in_reply_to をたどった場合に、たどったのを戻れるようにしてみました。ついでに違うタブに発言があってもたどれるようにしました。スタックにIDとtabを積んでいるだけなんですけどね。

    Private Structure ReplyChain
        Public OriginalId As Long
        Public InReplyToId As Long
        Public OriginalTab As TabPage
 
        Sub New(ByVal originalId As Long, ByVal inReplyToId As Long, ByVal originalTab As TabPage)
            Me.OriginalId = originalId
            Me.InReplyToId = inReplyToId
            Me.OriginalTab = originalTab
        End Sub
    End Structure
 
    Private replyChains As Stack(Of ReplyChain)
 
    Private Sub GoInReplyToPost()
        If _curPost IsNot Nothing AndAlso _curPost.InReplyToUser IsNot Nothing AndAlso _curPost.InReplyToId > 0 Then
            If _statuses.ContainsKey(_curPost.InReplyToId) Then
                Dim tab As TabPage = _curTab
                Dim idx As Integer = _statuses.Tabs(tab.Text).IndexOf(_curPost.InReplyToId)
                If idx = -1 Then
                    For Each tab In ListTab.TabPages
                        idx = _statuses.Tabs(tab.Text).IndexOf(_curPost.InReplyToId)
                        If idx <> -1 Then
                            Exit For
                        End If
                    Next
                End If
 
                If idx = -1 Then
                    Dim repPost As PostClass = _statuses.Item(_curPost.InReplyToId)
                    MessageBox.Show(repPost.Name + " / " + repPost.Nickname + "   (" + repPost.PDate.ToString() + ")" + Environment.NewLine + repPost.Data)
                    Exit Sub
                End If
 
                If replyChains Is Nothing OrElse (replyChains.Count > 0 AndAlso replyChains.Peek().InReplyToId <> _curPost.Id) Then
                    replyChains = New Stack(Of ReplyChain)
                End If
                replyChains.Push(New ReplyChain(_curPost.Id, _curPost.InReplyToId, _curTab))
 
                If tab IsNot _curTab Then
                    ListTab.SelectTab(tab)
                End If
                SelectListItem(_curList, idx)
                _curList.EnsureVisible(idx)
            Else
                OpenUriAsync("http://twitter.com/" + _curPost.InReplyToUser + "/statuses/" + _curPost.InReplyToId.ToString())
            End If
        End If
    End Sub
 
    Private Sub GoBackInReplyToPost()
        If replyChains Is Nothing OrElse replyChains.Count < 1 Then
            Exit Sub
        End If
 
        Dim chainHead As ReplyChain = replyChains.Pop()
        If chainHead.InReplyToId = _curPost.Id Then
            Dim idx As Integer = _statuses.Tabs(chainHead.OriginalTab.Text).IndexOf(chainHead.OriginalId)
            If idx = -1 Then
                replyChains = Nothing
            Else
                Try
                    ListTab.SelectTab(chainHead.OriginalTab)
                Catch ex As Exception
                    replyChains = Nothing
                End Try
                SelectListItem(_curList, idx)
                _curList.EnsureVisible(idx)
            End If
        Else
            replyChains = Nothing
        End If
    End Sub

そろそろコメント無しだとつらいレベルのコード片になってきましたw

手元の私家版では GoInReplyToPost() を I キーで、GoBackInReplyToPost() を Shift-I キーで呼び出すようにしています。なかなか快適。

本当はコード片ではなくそのまま使える形にしたいんですがいろいろ面倒なので...


2009-12-12 [Sat]

[プログラミング] Tween改造 -Replyをたどろう

[追記] 以下のコードにはバグがあるかもしれません。必要なら後で修正します。

[追記] 修正版を書きました。

Twitterのtweetには in_reply_to というものがあって、これで「どの発言に対するreplyか」というのが分かるようになっています。Webで見たときの __park宛(英語だと in reply to __park)ってやつですね。

で、TweenではこれをCtrl+Iで見ることができるんですが、これだとメッセージボックスで元発言が出てくるのでたどることができません。発言をたどるものとして左右キーがありますが、これでは in_reply_to と関係ないものまでたどってしまい分からなくなってしまいます。

ということで、I キーを押すことで in_reply_to のみをたどる機能をつけてみようとおもいました。

とりあえず実際に動かしたらうまくいったんですがよく見ると古いバージョン(0.7.5.0)のソースコードだった!ということで最新の物をチェックアウトしようとしたらでてこない。リポジトリ変わってたのね。ということで取ってきたらビルドができない。ファイル追加忘れがあったようで…

ということで、Tween.vbに新しく加えたメソッドを書いておきます。これを I キーが押されたときに呼び出せば動くはず…

    Private Sub GoInReplyToPost()
        If _curPost IsNot Nothing AndAlso _curPost.InReplyToUser IsNot Nothing AndAlso _curPost.InReplyToId > 0 Then
            If _statuses.ContainsKey(_curPost.InReplyToId) Then
                Dim i As Integer = _curList.SelectedIndices(0)
                While True
                    Dim post As PostClass = _statuses.Item(_curTab.Text, i)
                    If post.Id < _curPost.InReplyToId Then
                        Dim repPost As PostClass = _statuses.Item(_curPost.InReplyToId)
                        MessageBox.Show(repPost.Name + " / " + repPost.Nickname + "   (" + repPost.PDate.ToString() + ")" + Environment.NewLine + repPost.Data)
                        Exit While
                    End If
                    If post.Id = _curPost.InReplyToId Then
                        SelectListItem(_curList, i)
                        _curList.EnsureVisible(i)
                        Exit While
                    End If
                    i = i - 1
                End While
            Else
                OpenUriAsync("http://twitter.com/" + _curPost.InReplyToUser + "/statuses/" + _curPost.InReplyToId.ToString())
            End If
        End If
    End Sub

2009-11-01 [Sun]

[プログラミング] Tween改造

最近Twitterのサーバで画像を縮小してくれなくなりました。そのためアップロードされた画像のサイズそのままを取得することになってしまいます。

そこで問題になるのが縮小の際のリサイズの処理です。

Tweenでは System.Windows.Forms.PictureBox にそのまま任せているのですが、PictureBox のデフォルトの処理が画質重視ではなく、そのため画像によってはジャギーが出てしまいます。

そこで、以下のようなコード断片を Tween.vb に追加し、UserPicture コントロールの Paint イベントのハンドラとして追加しました。

    Private Sub UserPicture_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles UserPicture.Paint
        If e.Graphics.InterpolationMode <> Drawing2D.InterpolationMode.HighQualityBicubic Then
            e.Graphics.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
            UserPicture.GetType().GetMethod("OnPaint", BindingFlags.NonPublic Or BindingFlags.Instance).Invoke(UserPicture, New Object() {e})
        End If
    End Sub

結果はこの通り。

Tween PictureBox Diff

手法がすごく汚いとは自覚してます。本当は PictureBox のサブクラスを作って OnPaint メソッドを override するべきなんでしょうが。

[プログラミング] Tween改造のちゃんとしたやりかた

ユーザーコントロール作ったときに既存クラスのサブクラスであればスーパークラスの属性とかをそのままフォームエディタで使えたということに今更気付いた。

ということで、PictureBox を継承したやつを作ってユーザーコントロールとして追加してやればいいようで。

    public partial class MyPictureBox : PictureBox
    {
        public MyPictureBox()
        {
            InitializeComponent();
        }
        protected override void OnPaint(PaintEventArgs pe)
        {
            pe.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            base.OnPaint(pe);
        }
    }

こんな感じで。

ユーザーコントロールをフォームエディタで使うときには、コントロールを選ぶツールボックスの所で右クリックして「アイテムの追加」から探すんだけれど、このときにコントロールの入ったアセンブリ (.dll, .exe) を参照ボタンから追加してやらないといけないらしい。


2009-09-17 [Thu]

[プログラミング] C#でTwitterライブラリ (OAuth対応)

タイトルのとおり、C#でTwitterライブラリのような物を書いてみた。OAuthにもいちおう対応させてみたり。

ろくにテストをしていないです。

  • Account Methods
  • Notification Methods
  • Block Methods
  • Saved Searches Methods

このへんはまだ書いていない。


TwitterOAuth oAuth = new TwitterOAuth(consumerKey, consumerSecret);
string authUrl = oAuth.GetAuthLink();
string code = "hoge";// (本当はユーザに authUrl にアクセスしてもらって、認証コードを入れてもらう);
oAuth.VerifyOAuthByPinCode(authUrl, code);
// oAuth.Token, oAuth.TokenSecret を保存。
// 次回は new TwitterOAuth(consumerKey, consumerSecret, token, tokenSecret)
 
TwitterApi api = new TwitterApi(oAuth);

とかやればTwitter APIが使えるようになって、


TwitterStatus[] timeline = api.GetFriendsTimeLine();
foreach (TwitterStatus tweet in timeline)
    System.Console.WriteLine(tweet);

みたいに使えるんじゃないだろうか。

これを使うような危篤、じゃない奇特な人はいないだろうけれど、無保証なので注意。あと英語が間違っていても笑って赦して。

IronTweet-0.2.0.0.zip


2009-09-07 [Mon]

[大学] 大学院合格

受かった。それだけ。

[プログラミング] LEDClock

Twitterで信頼できないexeファイル開くなとかたいそうなことを言ってしまったので貼ったexeファイルをソースコード付きで公開してみる。

ledclock.zip MD5: 3097c35a1e5067cdee61c09fdcaf73c5

まあどうせHTTPSじゃないからMD5書いてもあまり意味はないんだけれど。信頼するか否かの判断は慎重にどうぞ。


2009-09-04 [Fri]

[プログラミング] Mono 2.4.2.3 にバグ?

C#には ?? 演算子という便利な物があって、こいつは前者が左辺を評価し、nullでなければ左辺を値とし、nullであれば右辺を評価して値とする。

元々はC# 2.0でNullable型が導入された際に追加された演算子で、Nullable型を非Nullable型に代入する際にデフォルト値を与えるために使うものだけれど、何かと他の場所でも使える。

例えば


string var = SomeFunction() ?? "failed";

みたいな使い方ができたりする。

プログラミングをしているときにこれを使おうとしていたんだが、「左辺が非nullなら右辺は評価されないんだっけ?」と疑問を持った。ちなみに正解は「評価されない」であっていた。そこで、試すのにFreeBSDのmonoを使おうとしたのが間違いの始まりだった。


using System;
 
public class NullCoalescing
{
    public static void SuppressWarnings(params object[] o) { }
 
    public static void Main()
    {
        string a, b;
 
        a = "not changed";
        b = null ?? (a = "changed");
        Console.WriteLine("a = \"not changed\";");
        Console.WriteLine("b = null ?? (a = \"changed\");");
        Console.WriteLine("result: a == \"" + a + "\"");
 
        Console.WriteLine();
 
        a = "not changed";
        b = "" ?? (a = "changed");
        Console.WriteLine("a = \"not changed\";");
        Console.WriteLine("b = \"\" ?? (a = \"changed\");");
        Console.WriteLine("result: a == \"" + a + "\"");
 
        SuppressWarnings(a, b);
    }
}

試しにこんなコードを書いてみたらとんでもないことが起こった。


$ gmcs NullCoalescing.cs
$ ./NullCoalescing.exe
a = "not changed";
b = null ?? (a = "changed");
result: a == "changed"
 
a = "not changed";
b = "" ?? (a = "changed");
result: a == "changed"

え?右辺評価されてる!?

おかしいなと思ってVisual C#で確認してみる


>csc NullCoalescing.cs
>NullCoalescing.exe
a = "not changed";
b = null ?? (a = "changed");
result: a == "changed"
 
a = "not changed";
b = "" ?? (a = "changed");
result: a == "not changed"

え?評価されてない!?

あまりにもおかしいので別の型で試したら右辺は評価されないし、a, bをobject型として宣言したら右辺評価されなくなるし。

結局、string型かつ左辺が定数の場合には再現したけれどそれ以外では再現しなかったという。最適化関係でバグってるのかしら。

ちなみにおかしかったのはgmcsで、cscでコンパイルしたバイナリは.NET Frameworkでもmonoでも正常に動いた。


2009-08-16 [Sun]

[東方][TSG] ネタバレ注意

まさかこんな日記を読んでいる方はいないとは思いますが、新作のネタバレを含みます。

(続きを読むにはここをクリック(JavaScriptが必要)


2009-08-08 [Sat]

[TSG] 諏訪詣で 再び

TSGの夏合宿でまたしても諏訪に詣でてきた。

いろいろ感動したがここにはとても書ききれないんで興味ある方はご自身で足を運んでください。

本日のツッコミ(全1件) [ツッコミを入れる]

mitty [おつー。 参加したかったけれど、掛かっている先生から遠出は避けた方が良い、とのお達しがあったので涙を飲みました。 ..]


2009-05-29 [Fri]

[雑記] 生きてます

1ヶ月以上空いてましたが生きています。といってもこんな日記誰も読んでいないでしょうから問題ありませんね。

[雑記] 規制規制また規制

性暴力ゲーム規制強化へ、与党が流通歯止め検討チーム

だから現実と相関関係のないものをなぜ規制するんだ。科学的な証拠を持ってこいよ。それとも嫌いだからなのか?

規制規制。なんでも規制。だったら人間は犯罪を犯す危険があるから規制しないといけないね。

とりあえず、理系の基礎のない政治家は規制されるべき。統計の「と」ぐらいは囓れよ。世襲がうんぬんとか言っている場合ではない。