2011年07月03日
MacキーボードでIME操作を可能にする「Appkb」をリリースしました

諸事情により、リリースを延期させていた「Appkb」をリリースしました。詳細は、下記URLまで。今回はソースコードもアップしました。
2011年07月02日
org.eclipse.swt.internal.Callback を用いてウィンドウメッセージを処理する
ほとんど情報ないのでメモ。
import java.util.ArrayList; import org.eclipse.swt.internal.Callback; import org.eclipse.swt.internal.win32.OS; import org.eclipse.swt.internal.win32.TCHAR; import org.eclipse.swt.widgets.Control; public final class WndProc { public WndProc(Control control) { final Callback callback = new Callback(this, "wndProc", ARG_NUM); final int procAddress = callback.getAddress(); prevProcHandle = OS.SetWindowLongPtr(control.handle, OS.GWLP_WNDPROC, procAddress); listeners = new ArrayList<Listener>(); } public WndProc(Control control, Listener listener) { this(control); addSpiderListener(listener); } public void addSpiderListener(Listener listener) { if(listener == null) { throw new NullPointerException(); } listeners.add(listener); } @SuppressWarnings("unused") private int wndProc(int hWnd, int code, int wParam, int lParam) { if (OS.WM_SETTEXT == code) { // KEYCODE if (wParam == Hook.HOOKED_SCANCODE) { return 0; } // IME if (wParam == Hook.HOOKED_IME_RESULTSTR) { final int size = OS.wcslen(lParam); if (size <= 0) {return 0;} char[] buffer = new char[size]; OS.MoveMemory(buffer, lParam, size * TCHAR.sizeof); final String string = new String(buffer); // handler final Event event = new Event(string); for(Listener listener : listeners) { listener.spiderd(event); } return 0; } } return OS.CallWindowProc(prevProcHandle, hWnd, code, wParam, lParam); } private static final int ARG_NUM = 4; private int prevProcHandle; private ArrayList<Listener> listeners; }
勘所
以下のコードで、Javaのメモリ空間に文字列をコピーしてくる。
LPARAMが何を指すかは WM_SETTEXT を参照。
一言で言うと、WINAPI的にはpszを表す。
final int size = OS.wcslen(lParam); if (size <= 0) {return 0;} char[] buffer = new char[size]; OS.MoveMemory(buffer, lParam, size * TCHAR.sizeof);
OS.MoveMemory は注意しないと、アクセス違反が発生するので注意。
JNAを用いたdllの賢い呼び出し方
DLLがjarに入ってままだと、com.sun.jna.Native.loadLibrary から呼び出しできません。
それのうまい回避方法です。あと、わかりやすい呼び方にします。
まずは、必要なソースを3つ用意します。
tk/dmap/jna/AbstractImport.java
package tk.dmap.jna; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import com.sun.jna.Native; abstract class AbstractImport { protected static String getLibraryPath(Class<?> cls) { final String resourcePath = "/"+cls.getName().replace('.', '/').replace('$', '.'); final String[] libName = resourcePath.substring( resourcePath.lastIndexOf('/')+1 ).split("\\."); final URL url = Native.class.getResource(resourcePath); File libFile = null; if (url.getProtocol().toLowerCase().equals("file")) { try { libFile = new File(new URI(url.toString())); } catch (URISyntaxException e) { libFile = new File(url.getPath()); } if (!libFile.exists()) { throw new Error("File URL " + url + " could not be properly decoded"); } } else { InputStream is = Native.class.getResourceAsStream(resourcePath); if (is == null) { throw new Error("Can't obtain InputStream"); } FileOutputStream fos = null; try { libFile = File.createTempFile(libName[0], "." + libName[1]); libFile.deleteOnExit(); fos = new FileOutputStream(libFile); int count; byte[] buf = new byte[4096]; while ((count = is.read(buf, 0, buf.length)) > 0) { fos.write(buf, 0, count); } } catch (IOException e) { throw new Error("Failed to create temporary file for a library: " + e); } finally { try { is.close(); } catch (IOException e) {} if (fos != null) { try { fos.close(); } catch (IOException e) {} } } } return libFile.getAbsolutePath(); } }
tk/dmap/jna/Hook.java
package tk.dmap.jna; import com.sun.jna.Library; import com.sun.jna.Native; public final class Hook extends AbstractImport { public static dll dll = (dll)Native.loadLibrary(getLibraryPath(dll.class) , dll.class ); private Hook() {} public static final int HOOKED_SCANCODE = /*OS.WM_USER + */1; public static final int HOOKED_IME_RESULTSTR = /*OS.WM_USER + */2; public interface dll extends Library { public boolean begin(int hWnd); public void end(); } }
tk/dmap/jna/Main.java
package tk.dmap; import tk.dmap.jna.Hook; public class Main { public static void main(String[] args) { Hook.dll.begin(0); Hook.dll.end(); } }
その他タスク
- 「dll」とか妥当な名前で、ソース・フォルダを作成する
- tk/dmap/jna/Hook.dll となるようにdllを置く
以下のようになるはずです。
まとめ
「Hook.dll.関数名」でネイティブコードにアクセスできます!
※Hookクラスの「dll」というインターフェース名は変更しないように注意。
2011年05月18日
NetBeans 7.0のscala 2.9対応プラグイン
まだ http://plugins.netbeans.org/ には上がっていないのですが、2.8版の作者が2.9対応をはじめています。
https://github.com/dcaoyuan/nbscala からcloneしてきてビルドすれば、とりあえず動くプラグインが手に入ります。
READMEにもあるのですが、ビルドには以下の物が必要です。
- JDK 1.6以上 (OpenJDKでも可)
- maven 2系
- メモリ2GB以上
※NetBeansはビルド環境には必要ありません。ただ、READMEの「Setting nb.installation property for maven」だけはやってください。property がないと怒られます。NetBeansのパスは適当でいいです。
git clone https://github.com/dcaoyuan/nbscala.git
cd nbscala
mvn clean install nbm:autoupdate
とかすれば、nbscala/target/netbeans_site に*.nbmが生成されます。
あとは、以下のフローに沿ってnbmを追加して、NetBeans を最起動すればOKです。
[ツール]メニュー->[プラグイン]->[ダウンロード済み]タブ->[プラグインの追加...]ボタン->nbmを選択
こんな感じにドキュメントもちゃんと出て、宣言元にジャンプも出来ます!(画像はforeachだけどw)
※環境変数SCALA_HOMEは予め設定しておいてください。
2011年05月08日
scalaのIDEについて
scala始めました。
ゆくゆくはvimでやることになると思いますが、手っ取り早く使えるようになるためIDEを調べてみました。とりあえず、以下の3つが有名なようです。
何を使っているのか
検討の結果、NetBeansを使ってみてます。
世の中の動向
最近のマイコミジャーナルだとIntelliJ IDEAにすべきとあります。ですが、自分のニーズに合うか確認したかったので、IntelliJ IDEAとNetBeansを実際に使ってみてそれぞれのメリットを比較してみました。Eclipseはあのごちゃごちゃ感が個人的に好きでないので比較してないですが、ここをみると最近はちゃんと動いているとのことなので、以下に示すIntelliJ IDEAのメリットがびみょーと感じる方はScala IDE for Eclipse 3.5, 3.6を使ってみるといいかもしれません。
IntelliJ IDEAのメリット
- リファクタリング機能が使える*1
- 補完がワンテンポ早い
- そもそものIDEが高機能
- 依存ライブラリ一覧ができる
- 継承ウィザード
- 変数化ウィザード
- eclipseプロジェクト インポート
- などなど
NetBeansのメリット
- HTMLやCSS,JSについてもIDE内で完結して開発できる*2
- 新たにIDEのクセや、コマンドの差異を覚えなくて良い*3
- 無償なので、やりたいことに大抵プラグインが用意されている
- ねこびーんがかわいい
補足
デバッグや関数階層表示、定義先への移動などはどちらでも使えます。補完はワンテンポの違いはありますが、同じ内容でどちらも表示されます。
まとめ
で、個人的にはIntelliJ IDEAにはいらない機能が多く、そのくせに多言語が扱いづらいってことがキーとなって、NetBeansを使っています。もともと、NetBeansを使ってて詳しく知ってて、何かあったとき楽っていう物ぐさな理由もあります。
2010年06月20日
プライベート用名刺を作るよ!
プライベートな名刺が欲しかったので調べてみました。両面カラーで作りたかったので、その前提で調べたところ以下の2つがヨサゲでした!
フォレカ
テンプレートを使うか、Javaアプレットを使って自分でデザインできる 全て両面フルカラー印刷 送料・税込 50枚 500円 100枚 1,000円 220枚 1,600円
ブロガー名刺/前川企画印刷
デザイナさんにお願いしたり、自分で入稿できるみたい 料金は細かく設定されています。両面カラーならば、100 枚 1,800円です このエントリにトラックバックする必要があるそうです。
今回はデザイナさんに御願いしたかったので、前川企画印刷 さんにお願いしようと思います。




