星期六, 5月 03, 2008

讓你的JPanel能取得VK_TAB

問: 怎麼讓一個java.awt.Component的子類別(e.g., javax.swing.JPanel)能抓到KeyEvent.VK_TAB呢?

答: 以實例來說,

JPanel panel = new JPanel();
panel.addKeyListener(your_keylistener);
panel.setFocusTraversalKeysEnabled(false);

但, 這問題還沒完全解決, 如VK_PRINTSCREEN還是抓不到, VK_WINDOWS即使Java Application抓到了, 卻無法阻止(e.g., consum())這個event到OS...

still looking for solution...

星期一, 4月 21, 2008

Bits Ordering is Matter

Java2D真是奇怪的東西...沒想到RGB mask居然對效能影響這麼大.
原本, A這組mask需要200ms才能完成redraw...沒想到換成B mask只需要30ms...這實在太奇妙了.
也許有時間再來post一篇研究一下為什麼差這麼多.

星期日, 4月 13, 2008

最近在空閒的時候...

買雷斯林傳奇1也一段時間了, 一直到最近才有時間看, 雖然每次時間都很短. 先來抱怨一下...幾乎每一章都有錯別字...多 到 離 譜! ! ! 但是, 的確很好看, 每一章的開頭都有書中一名角色的一句話...印象最深刻的是:

我一定要做到。
這是我生命中唯一有意義的事情,唯一有意義的一刻。
我是為此而生,如果失敗,
那我就會在這一刻死亡。

雷斯林‧馬哲理

這段話看起來就像是電影、戲劇、漫畫、動畫中才會出現的對白,我想現實生活中是不會有人這樣講話的吧!?有人跟我說,龍槍系列中最好看的就是龍槍傳奇2。看完,龍槍編年史3,龍槍傳奇2,靈魂之戰4之後,我深有同感,但我說不出原因。但在看了雷斯林傳奇以後(儘管我現在還沒看完)我知道為什麼了。因為,雷斯林這令人茅盾的角色。雖然我看的書不多,但,最近也感覺出東/西方文學的差距了。不成材的我都是看小說,最近也在想是不是應該看些不一樣的書,例如,勵志之類的書。

從某些角度來看,我們是不是能【借鏡】,用雷斯林哪樣的態度看待人生,找到自己生命中有意義的一刻,我很敢說我現在沒有找到。以前看書/電影從來沒有想到這些,就只是單純的在看書/電影而已。但,有危機意識是好的,現在開始找也不嫌晚。

工作也一段時間了,雖然能從工作中得到樂趣,但,工作中也有我【十分】不喜歡的事情,又要小抱怨一下了,接下來這件事目前並沒有發生在我身上但,我在旁邊看著這件事發事,讓我想到這件事有一天也會發生在我身上,Project天經地義就是要meet schedule,沒錯。但,當schedule排得很不合理時,是不是還要強迫自己去meet schedule?我想,現在我會儘力,但以後難講。工作在過去不是我的全部,現在不是,未來也不會是。

還有人與人之間的關係太複雜,我努力試著將他簡單化,即使有人在我面前【睜著眼睛說瞎話,說著自以為高超的謊話】。有五感和腦袋的人,睜開眼睛仔細看,動動腦袋仔細想,誰在說謊是很明顯的。

最近也對自己多了一點認識,我真的是處女座,就像有人曾經這樣說過我一樣。我有潔僻,精神上的潔僻,有些事極難忍受。同時,我也很討厭【等】,例如:有著長長的人龍隊伍在等著吃某家店的東西,我打死不去,除非,不用排隊。我的朋友們,這兩個地雷不要來踩,除非,有把握踩下去以後炸不死(這時候我就會喪失冷靜的想,炸不死再補一顆),不然,千萬不要踩。哈。

1. 雷斯林傳奇(上 )靈魂熔爐 和 雷斯林傳奇(下) 烽火試煉

2. 龍槍傳奇(時空之卷+烽火之卷+試煉之卷)

3. 龍槍編年史(秋暮之巨龍+春曉之巨龍+冬夜之巨龍)

4. 靈魂之戰(落日之巨龍+隕星之巨龍+逝月之巨龍)

星期六, 3月 29, 2008

Java Native Interface - Accessing Array

之前提到JNI在存取陣列時很跛腳, 所以, 這篇就是要記錄JNI怎麼存取陣列. 這邊所指的JNI是指C/C++所寫的source code.

直接切入正題, JNI要怎麼存取從Java傳遞過來的陣列? 以byte為例, 在Java端某個class MyCls有這樣一個method,
private native void passByteArray(byte byteArray[]);
然後在MyCls的某個method裡面
byte buffer[] = new byte[1024 * 1024 * 4]; // 4Mb的陣列
passByteArray(buffer);
然後在JNI是這樣存取陣列的
jsize len = (*jenv)->GetArrayLength(jenv, byteArray);
jbyte *buffer = (*jenv)->GetByteArrayElements(jenv, byteArray, NULL);
// do something
(*jenv)->ReleaseByteArrayElements(jenv, byteArray, buffer, JNI_COMMIT);
跛腳的地方在如果要讓JNI修改的值反映回Java裡的話Get和Release這兩個動作少不了...整個慢慢慢掉...因為Get回傳的指標是指到另一塊一樣大小的記憶體空間副本而不是原本的哪一塊空間, 所以想當然, Release則是把Get回傳的空間再覆寫回去, 順便把空間free掉.

不過, 事實上有另兩種做法...一種用另一組Get和Release函式...另一種是利用java.nio.ByteBuffer
另一組Get和Release函式的寫法如下(用剛才的例子重寫一次):
jsize len = (*jenv)->GetArrayLength(jenv, byteArray);
jbyte *buffer = (*jenv)->GetPrimitiveArrayCritical(jenv, byteArray, NULL);
// do something
(*jenv)->ReleasePrimitiveArrayCritical(jenv, byteArray, buffer, JNI_COMMIT);
為什麼這比較快呢? 因為Critical的Get會儘量, 但不是一定, 回傳原本哪一塊記憶體空間的位置, 所以修改即使不Release還是會反映回Java. 但, 要怎麼知道回傳的是否為另一份copy呢? 答案是利用最後一個引數其型態為*jboolean. 再修改範例一次,
jboolean isCopy = JNI_FALSE;
jsize len = (*jenv)->GetArrayLength(jenv, byteArray);
jbyte *buffer = (*jenv)->GetPrimitiveArrayCritical(jenv, byteArray, &isCopy);
// do something
if (JNI_TRUE == isCopy)
 (*jenv)->ReleasePrimitiveArrayCritical(jenv, byteArray, buffer, JNI_COMMIT);
但根據Java Performance Tuning, Second Edition一書表示, 只要Get就要Release不管是不是取得原本的記憶體空間...無言...不過, 根據我自己寫程式測試結果, Critical的函式還是比較快...但有一個很恐怖的限制, 就是在Critical的Get和Release之間, 因為Java Garbage Collection的關係, 行程不能變成BLOCK狀態...不然...

最後是java.nio.ByteBuffer, 事實上只是利用ByteBuffer.allocateDirect(size)配置記憶體, 然後在JNI的存取是這樣寫的,
jbyte *directBuffer = (*jenv)->GetDirectBufferAddress(jenv, byteBuffer);
jlong directBufferLength = (*jenv)->GetDirectBufferCapacity(jenv, byteBuffer);
// do something
嗯, 這樣就可以了...但, 在Java端就沒辦法把ByteBuffer轉成byte[]存取, 因為一些限制, 不過這倒還OK...這做法可以讓Java和JNI共享一塊記憶體空間, 即然共享就要處理同步問題...

打了一堆, 沒CODE沒真相...最後是附檔包含java source code和c/c++ source code...這檔案是我用來測試效能的....很意外, CRITICAL GET/RELEASE最好..., 快在assignment operation時, TIME(CRITICAL GET的空間) < TIME(java.nio.ByteBuffer)

附檔: JNIDemo.zip

星期日, 3月 16, 2008

最近在?

最近好像也沒做什麼...就是看一看USB 2.0 spec.然後寫了簡單的USB Keyboard/Mouse的程式. 然後稍微看了Java Native Interface (JNI)的做法, 覺得JNI還滿坡腳的. 能不用還是不要用的好. 當然還有一些是不知道能不能公開的寫在blog上, 所以也就不寫了.

為什麼說JNI坡腳? 其實只為了一個理由, 我想在Java或Native Code其中一邊配置出一塊記憶體, 然後供Java和Native Code共同使用. 我如果在Java裡配置憶體空間A並傳遞到Native Code, 在Native Code則很可能必需先產生一份一樣大的記憶體空間B, 然後對這個空間做修改的動作, 最後將B覆寫回A. 這樣做完全失去共享記憶體空間的目的.

下一次寫一篇來介紹JNI吧.