Hatena::ブログ(Diary)

diaの備忘録

2012年12月10日

さようなら はてなダイアリー

かなり前から箱だけはつくっていたんですが、blog業する必要がでてきそうなんでOctopressに移行しました。 前職で使っていたConfluenceがない今、Markdownだけが生きがいです。

http://b.dmap.tk

2011年07月03日

MacキーボードでIME操作を可能にする「Appkb」をリリースしました

諸事情により、リリースを延期させていた「Appkb」をリリースしました。詳細は、下記URLまで。今回はソースコードもアップしました。

http://www.dmap.tk/software/appkb

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();
	}
}

その他タスク

  1. 「dll」とか妥当な名前で、ソース・フォルダを作成する
  2. tk/dmap/jna/Hook.dll となるようにdllを置く

以下のようになるはずです。

f:id:DianthuDia:20110703001534p:image

まとめ

「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)

f:id:DianthuDia:20110518040343p:image

※環境変数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を使ってて詳しく知ってて、何かあったとき楽っていう物ぐさな理由もあります。

*1:NetBeansはscalaにおいて現在使えない

*2:IntelliJ IDEA CEでは対応言語が少ない

*3:keymapの変更だけでは限界がある