トップ 最新 追記

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-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-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-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をロードしているか否かを判断基準にしました。

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

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