2009/12/23

2009 微軟多點觸控大賽亞軍




2009/12/11

chrome 與 自家產品 相衝

雖然之前就試用過 chrome, 不過當初因為沒半個 extensions 所以就放棄了,今天又用起來 chrome, 剛開始一切還算順利,所以就想要來寫一篇心的,沒想到 chrome 竟然跟 blogger 相衝!最上面的登入不見了,在貼文章時也沒有發佈,這什麼啊!

後來又用回 firefox 貼了一篇文章,現在則是在用 gmail 來發佈,可憐。

--1224--
最近發現用 chrome 連 gmail 都會一直出現問題,只好放棄 chrome 用回 firefox。之前想用 chrome 的最大原因是,它的界面簡潔,而且,不會像 firefox 大吃記憶體之後變的很 lag...

唉,有一好沒兩好....

Best Regards
--
自由的精靈, 狂想的空間
Free Spirit, Fantasy Space
Mike Ditka - "If God had wanted man to play soccer, he wouldn't have given us arms."

員工的心聲 -22-都不幫我加薪

.為何都不幫我加薪

這個問題並非我本身的問題,但是卻是普遍存在的現象,公司為資深人員加的薪都太少了,因此很多人總是處於一種困境中,到底我該不該換工作以求取更多的薪水?

前面提到外來的和尚會念經,這現象也困擾著現有的人員,也就是公司的資深人員,大家總是會抱怨從外面請來的人都給那麼高薪,難道我們都這麼沒用?

公司內部的人才培訓總是缺乏全面的考量,對現有人員總是希望發揮他們最大的績效,因此每天忙不完,而他們也被主管定型化,每當公司需要什麼人才時,總是先向外搜尋,而在加薪時,卻又忽略了這些資深人員。

舉例來說,國內每年調薪的公司比例恐怕不多,而那些願意每年幫員工加薪的公司,調薪比例能有3%就偷笑了。我們就拿3%來講好了,做個10年才調整 34%,若以三萬起薪來說,十年後才調整到 4萬元。請所有老闆想想看,這樣合不合理。就算拿同一行的技術人員來說,新進的十年的員工,你願意給多少薪水?

不過話說回來,現在換工作愈來愈難找到新工作,公司寧願從新手訓練起,又有幹勁給薪又少。到底,公司的人力計畫是什麼?我想,這是老闆應該去好好想想的,不要讓員工老是感嘆為何都不幫我加薪!

2009/12/07

員工的心聲 -21-我也是有優點

.我也是有優點

本來要寫我也是有貢獻。絕大多數情況下,每個員工都有貢獻,但是難免會面臨是不是要裁員的情況,而大多數主管都不知道該怎樣面對,最簡單的說詞就是「上面交待的」,不然就是「按照考績制度」。問題是考績怎麼來的,老實講我到現在還沒遇到任何主管好好跟我講他是怎麼打我的考績的。相信那些被裁的員工心裡也很幹,明明做的要死,卻最不得上司疼愛。

前面的心得裡面也提到過,訂定目標,達不達到就很容易知道。就這一點來說,我也不反對某些大公司的做法,就是直接講,今年的成績比去年高三成。問題是工程師很難明訂這樣的目標,因此主管有責任去定義出每個員工的角色與核心價值,然後給與適當而明確的目標。這邊我就不特別提。

找出員工的優點並且最大化,最後讓每位員工的優點變成團隊向上成長的動力來源。前面提到的保持活力就很重要,要讓團隊是一個整體,而不是各自為政的散沙。讓每個人各安其職,各盡所能,各展其才。其實我很多篇都在講這樣的概念,可見這真的深深植入在我的腦海中,深怕自己像我遇到的絕大多數主管那樣。

雖然我寫了這麼多,每位主管也都對我很好,他們也都有不錯的人格特質,我寫這些心得不是要抱怨抱怨再抱怨,我知道我自己是要求多了點,有誰能完美?我寫這些心聲要講的是,我一直在反省,盡量去學,努力去做,不敢說我做的很好,但是這些主管都將成為我明日成長的養分。

員工的心聲 -20-保持活力

.保持活力

常見到的現象就是,整個辦公室死氣沉沉。前面也探討了諸多原因,想要有產業競爭力,持續創新與不斷學習是非常重要的,而這,無非就是要一個有活力的辦公環境。

保持活力並非老闆三不五時找員工哈拉就夠了,也不是請大家吃吃喝喝就算了,破除本位主義與保護主義也是相當重要的課題。我有遇到一個工作環境,我找別的 team 的員工討論或是尋問某些問題,有時會要些資料,我想,大家都相同部門,應該沒什麼秘密可言吧,可是對方主管竟然警告他的成員說,以後 Wade 找你們談什麼,一定要讓我知道。

成員的位置不明,就容易讓人推卸責任,分工明確外,還要加強員工的專業。常常見到就是號稱以專案導向的主管,看誰有空就找誰做事,看似每個人都能獨當一面,事實卻是大家都做著類似的工作,很難精益求精,互相間學習的力道也少了,反正就是「上網查」。每個人忙著自己的事,也無法互相照應,新的案子一來又是從頭忙到尾。

我遇到不少工程師,他們只想當工程師,這原本是應該的,但是彼此間的互動幾乎是零,只想做好自己的事,若遇到放任(好聽叫信任)的主管,那整個就是不思進取,難有寸進。之前一直強調要分工,要顧流程,要精益求精,清楚一個開發流程有哪些分工要顧好是很重要的,天才型的工程師可以軟硬兼施,可以美工與品質並重,問題是這種人很少。為了精減人事,在分工不明的情況下,案子一多,誰該做什麼反而都亂了,人再多都不夠用。

忙,就沒有活力。我一直強調要正常生活,家庭顧好一方面也會讓工程師沒有後顧之憂,另一方面頭腦清醒有活力,正是公司不斷向上提升的基本要求。有朋友說,Wade,你又要第一,又要正常生活,又要核心價值,又要這又要那,幾乎是不可能的。我們只要想著一件事就好,為何古人常常有大師?既是物理大師又是數學大師又是心理大師又是藝術大師什麼的,古老數百年才出一個這樣的人物,而現在呢?正因為分工日益細日益精,才使得科學突飛猛晉,難道要回到古時候一個人要做所有事?

常常主管很怕降格與員工談話,這當然也是一種帝王術,我也知道我的毛病是凡事都與員工分享與討論,我從自己是員工來看,我寧可要主管在工作上有什麼事都要講出來,不管是好的壞的。有時主管會說,我正是怕你們擔心,一切苦悶我自己承擔。業績掉了,被大老闆罵了,進度落後了,又怕員工壓力大,又怕員工跑掉,怕東怕西的,反而事情做不好。我也看過主管只會一味的要求員工,動不動就罵人的,這樣不叫溝通,無法有效找出解決之道。兩種到最後就是死氣沉沉。

我還遇到一種主管,對上唯唯諾諾,對下也就變成可有可無,一切都是上面講的算。說的好聽點,這種主管怕員工犯錯,說的難聽點,這種主管只怕做錯事。主管要有所為有所不為,要有個人的風格,因為到現在,我還不曉得那位主管有何特長。最後變成有什麼事跟他講也沒用,反應又怕上頭怪罪,於是大家沒事少論是非。也許很多主管喜歡這樣,但是這就是我要說的缺少活力。

活力的來源很多,常常都是主管把它堵住了,培養敢言敢做勇於擔當的員工,創造活力十足的工作環境,這對公司的未來是相當重要的課題。

2009/12/05

員工的心聲 -19-外來的和尚會唸經

.外來的和尚會唸經

工作久了,自然就會遇到外來的和尚會唸經這件事。這事要分兩個面向來看,一個是我自己就是外來的和尚,一個是看到外來會唸經的和尚。

其實不管哪一種,這種事難免會發生,常常會讓人見到搞圈圈的事,圈圈還有大有小,而依我的個性極度不願打破人家的圈圈,因此老是在圈圈外。

其實並非我不想打破別人的圈圈,而是長官授權不夠,前面我也曾提過我的一個特性是,主管叫我做的事我一定努力做好,但是主管沒叫我做的事我會儘量不去碰。通常圈圈都不是我權責內的事,否則我怎麼會讓它發生!

我很愛看故事,超特愛看歷史故事,史記不敢說從頭看到尾,但也看了不少,有名的書能拿到的大概也都看了。其中常見到的一種情節叫「拜將」,古代會設拜將台,比較出名的就是韓信。拜將的功用是昭告天下,本王要重用的將軍是你。可是現代人對新進的人員或主管沒這些動作,除非發生大事。所以,這邊特別要講的心聲就是,一個好的老闆,應該要對你要重用的人進行登壇拜將動作!將權力範圍好好說明清楚。其實前面也提到主管有責任幫員工找到位置,這其實在說的就是權責畫分要明確。大家分工清楚,權責相符,然後自然就能相安無事。

很可惜的,我常常遇到的是,大家在開會時,都說這不是我的事,可是在搶功勞時卻常常搶在前頭。沒錯,有人會質疑我前面說的置身圈外也是一樣沒什麼比較好,這又一言難盡,我在講的是圈內的人也互相推諉塞責,冷眼旁觀。我敢說,該我負責的我不會逃避,我力所不及的,我會辭職以示負責。但是,很可惜我還沒遇到跟我一樣做法的人,有幾次在我離職時,同事或是朋友會告訴我,「wade, 你想太多了」,也有時候有人會說「wade, 退一步海闊天空」,也有人會說「你就算不會自己想,也要為家人想」。

前面講了幾篇,請主管要下凡到人間就是一個好例子,在事發後,主管也常常息事寧人,更令人無奈的是遇到那種明顯有自己人非自己人之分的主管。其實若非為了家人著想,我幹嘛坐視不理,幹嘛置身事外,幹嘛不去打破圈圈?世事常有無奈之處,老闆不應坐視圈圈的形成,更不應主動去建立圈圈,而對新進員工要明確賦與授權,而且要公開行之。

簡單講就是,請有權責的老闆們,對新進的人員,公開其權責,明確賦與,這才是讓整個部門甚至是公司相安無事的唯一之道。

2009/12/04

員工的心聲 -18-如果還有明天

.如果還有明天

寫到這邊,腦袋一片空白,剛剛還出去透透氣,可是大概已經寫完了吧,所以最後就以這個標題暫時做為今天心情的結束。如果還有明天。

有一首歌是我少數會唱的歌裡面的一首,當然我一貫只會唱其中幾句,歌詞是這樣的:

如果還有明天
你想怎樣裝扮你的臉
如果沒有明天
要怎麼說再見

每次換工作,都會遇到要怎麼說再見的痛苦。我不想傷害任何人,我會離職一定有我表現不好的地方,當然前面的心聲裡面,也占了很大的篇幅希望我的主管能做的更好,既然是心聲,也是希望如果還有明天,我可以表現的更好。而我相信往後我也會一直是主管,那當然不能讓自己走別人帶給我痛苦的老路。

如果還有明天,我希望我能成長的肩負更多的責任,如果沒有明天,我希望我會好好跟每個人說再見。

肩負更大責任就代表我不得不面對更多問題,雖然這一直是我的追求,事實上這很難,但是也是我願意花更多時間去做的事。要好好跟每個人說再見更難,因為,這邊畢竟養了我很久,而我也跟一部份人養成了感情,當然,我也得到某些人的信任。要揮別這些關係很難,當再見之後還要能保持朋友關係時常聯絡更難。

幸好,我一直能遇到好的朋友,也還有再見後的前同事前老闆肯賞識我。所以,就讓這篇做為我希望再出發的註解吧。

員工的心聲 -17-請不要師心自用

.請不要師心自用

前面提到過,長官要有長官的威嚴,但是我只是一個小小的員工,我哪管你什麼威嚴,我只希望讓長官知道事情的真相而已。可是,偏偏,你一定會遇到那種師心自用的長官。嗯,這個詞有人可能看不懂,也可能有人會以為我寫錯字,我是說,請不要太固執自以為是,甚至是驕傲自大。

俗話說,人有兩面,牆有八方,誰能事事兼顧呢?偶而聽聽小井市民的聲音是非常重要的。前面講到請下凡到人間,這跟這篇的主題是兩回事。高高在上是連聽都聽不到,若員工肯找長官講心裡話,請長官不要帶著有色的眼鏡看事情。

當然這不是鼓勵做報馬仔。有的長官遇到某些人,總是會有成見,說到底有成見這件事幾乎人人都會,我也不敢說我不會發生。但是把敢說真話當成破壞群體和諧的人看待,那又有誰敢講真話?

尤其有些主管會自動把屬下畫分成自己人與非自己人,遇到這種主管真的是頭痛的很。要嘛就努力把自己打入主管的圈圈,要嘛就置身事外,從此斷了溝通的管道。試問,既然是你的下屬,為何要把他們排除在外呢?

我一直很努力很小心的避免這件事。老實講,平常講話總有活潑的員工特別容易回答我的問題,私下聊天也一定有的人可以聊的愉快,也一定有人像木頭一樣。但是這不能拿來當親疏的理由。若有主管因為親疏的理由來決定要不要聽一個人的話,或是因此而打考績,那真的是自我毀滅的開始。

員工的心聲 -16-減薪裁員沒關係,我只要合理就好

.減薪裁員沒關係,我只要合理就好

這個主題要說的內容很令人感嘆,若光從題目減薪裁員的字面來看其實我不算有遇到。我真正想說的不是減薪或裁員,而是一種合理的要求。

有一種狀況是,大環境不好,所以一直要求員工加班加班,可是明明大環境不好,加班做東西也賣不出去。有一種狀況是,明明公司狀況不好,可是老闆硬是不裁員不減薪,最後搞到整個解散了。兩種情況都很糟糕。

其中第二種狀況裡,前面提到老闆有責任要帶領大家前進,要找到公司的核心價值,要把產品賣出去,但是,有時大環境就那麼糟,公司就是入不敷出,可是老闆基於大家都那麼辛苦的情況下始終不肯談裁員。好老闆不見得能為員工帶來幸福。其實明明白白把困境跟員工分享是很重要的,不見得是要同舟共濟,至少讓員工有心裡準備,至少讓員工能為前途早早打算。

當然,遇到那種把加班當有趣的老闆,賺錢要加班,不賺錢更要加班來讓大老闆高興,減薪減的十分高興,裁員裁的不知所謂,底下的人只會心冷而已。我知道這種公司的老闆會成功都是因為有他的一套管理方法,甚至出書什麼的,大家爭相訪問,問題是,現行做法到底合不合理?

以前當兵時,每次要大集會時,明明主持的長官是說十點開始,排長的我就得四點起床,行前準備加上一遍又一遍的演練。上面一句話,下面做牛做馬。前面也提到請主管要下到凡間來,那是另一個主題,這個主題要講的是一切要合理。兩種情況裡面,一種是因為主管自我要求太高連帶高條件地要求部屬,一種是主管太體貼部屬,結果拖垮整個公司或部門。

兩種我都遇過,其實員工要的只是坦誠與合理而已。

員工的心聲 -15-請下凡到人間

.請下凡到人間

長官要有長官的威嚴,這件事我知道,這是我當兵時就學到的。但是若長官一直不食人間煙火,底下已經雞飛狗跳了,身為主管還一副老神在在的樣子,員工講的話又聽不進去,那員工只會心灰意冷。

遇到那種一副老神在在的樣子也真的令人頭痛,會叫我不要太急,會叫要我融入團體中,會告訴我一切都在掌控中。可是實際上已經走了不少人了,難道都真的活在古墓中?

我自從當了真正的主管,明確賦與我生殺大權之後,我一直很小心翼翼的注意不能活在古墓中。當然我也在反省著,是不是我把太多心聲與他們分享,反而打亂了他們的心?但是至少目前沒人來打亂我的心,所以這至少還不是我的心聲。

要下凡到人間,很主要一部份要看主管的心態。有時候忙是一個很好的藉口,有時候充份授權也是不錯的講法,更多的時候是尊重每個員工。這些都是實情也是很重要的管理原則沒錯,但是身為員工的我,只希望我的主管能更貼近民意一點。至於要怎樣做才能做到?我想很多書上會寫,不見得要站在平等的地位跟員工相處,但是一定要用心。

員工的心聲 -14-請帶動我前進

.請帶動我前進

這個議題似乎前面有談到,我現在是腦袋停頓了,想到什麼就寫什麼。

前面提到要讓員工有學習的機會,這個很大一部份是老闆的責任,不是讓他上上網就好了,何況很多公司還東擋西擋的,唯恐員工不專心工作。也提到要讓員工做有創意的工作,這個就是員工與主管都有責任,老闆常常是扼殺員工創意的最大殺手,而員工不思進取的也大有人在。當然訂定目標也是前進的重要因素,沒目標光盲忙茫也沒用。

這篇要講的是一種往前進的動力,帶動員工前進的氛圍,很難講清楚。像有一篇提到請不要完全相信我,若老闆完全相信我,放任我,也許我會像脫韁的野馬一樣,何況有時我根本就做不到。

公司要前進,部門要前進,團隊要前進,個人要前進,總要有目標,總要有動力,還要有人掌握方向盤。很多時候,主管都沒盡到責任,當然員工也有責任就是了。我遇到三次部門解散的,其中只有一次領到資遣費,其中一次我的責任最大。所以我是有資格說這個議題。

帶動員工前進,首先要幫自己的團隊找到價值與做出貢獻。做死做活若還是沒辦法賺錢,那境況真的很慘。上面提到的三次裡面,有一次還更慘,什麼都還沒做就解散了。

所以老闆真的要好好思考,做什麼產品才能為公司帶來長治久安的前進動力。不要連老闆都跟員工一樣盲忙茫。老闆,拜託,請找出你的核心價值,我們會幫你實現。也不要就下達「今年成長三成」這樣的目標,當然若是過去年年實現我也沒話講,能帶動員工一起達成的話,員工會相當感激你的。

找出公司或部門的核心價值,做出能賣錢的產品,帶領員工有目的地的往前進吧。

每次要換工作時,我總是會認為,這次的工作有前途,有幾次有幸也真的遇到有前途的工作,可是最後最後我還是選擇換工作,原因已經寫在前面了,所以這篇就到此吧。

員工的心聲 -13-請告訴我做的好不好

.請告訴我做的好不好

我常常遇到一種狀況,老闆對屬下都很好,可是打考績時卻沒辦法給很好,獎金股票也就發的少。這不代表員工表現不好,明明知道他很優秀,可是因為公司沒賺錢,或是他的產出不如預期,所以考績就無法往上調。

當然我不是純粹在說考績,我也常常遇到所謂「自己人」這件事。但是這不是這篇文章的主題,這種事我也不想講。

前面說過,幫員工找到好位置,幫員工訂定明確的目標,若員工表現好,他自然應該有好的考績。我說過,案子的成敗,最大的責任在主管。所以不要用產出來幫員工打考績。

當員工表現不好時,要明確告訴他,同樣當員工表現的好,那就明明白白告訴他。光這項就很少有主管能做的很好。主管只想表現成一個好主管,對每個員工表面上都很好,當然主管心中自有一把尺,可是在員工表現不如自己預期時,並不會主動告之。更慘的是,常常有主管當著所有人的面誇讚他認定的好員工。

我不是說對表現好的員工不應該稱讚。首先要一視同仁,要讓大家知道,每個人的辛苦在哪,表現好的地方是什麼,什麼狀況是表現不好。否則有些人永遠就該死,永遠都在幕後,永遠都是沒事幹。

我前面說過,要成為世界第一,這並不是專指個人,團隊的成長是很重要的,團隊的整體優良表現才有辦法與外面競爭。所以,請主管先把這項基本的要求做好,在我表現不好時,明白告訴我。

員工的心聲 -12-請尊重專業

.請尊重專業

專業分工顯然是重要的必修課題。我也有遇到專長不符的主管,他個人的能力暫且不論,但是當你要帶領一個與自己專長不符的團隊時,請保持謙虛的心,請擁有一顆尊重的心,看是要與部屬好好學習,還是尊重他。這一點不是在說我(而已),官階愈大,這種主管發生的機率就愈高。當我升官了,管的事情多了,哪有可能樣樣都是我的專業。因此我在說的不是不夠專業就不該當主管,而是一種尊重自己的權責的心。

在講尊重專業時,分工就很重要,若團隊夠大,把不同專業領域的人分辨出來,然後讓大家能協調相處,努力提升團隊的能力不斷往前進。有時,責任是賦與了,員工也協調了,只是協調不成時,員工也反應了,此時主管有責任跨部門溝通,而不要讓底下的人單打獨鬥。

這是兩個不同的議題。一個是部門內,一個是跨部門。我其實常常自問,部門內的我做好了嗎?跨部門溝通時我有沒有讓員工自己去面對?我知道我還可以做的更好,也希望主管們都能做好。

員工的心聲 -11-不要讓我單打獨鬥

.不要讓我單打獨鬥

說真的,很不想寫這一段,因為這是我現在正面臨的痛苦。

要融入一個既有的團隊很難,就像前面提到的那個好老闆讓我用三個月時間了解公司,但是,這裡面缺少了一個主動的因素,老闆總是認為好的員工應該能很快融入群體。事實上能做到的人是很多,但是也有很多做不到。而我,常常自己設限,總認為老闆交待我做的事,我努力做好,沒交待我的事,我盡量少碰。

我定義中的老闆有時就是指一級主管,有時是指能負責的較高決策者,而主管就是一級主管,而那些階級高的非直屬的主管我會特別講。經歷過這麼多工作,不同的環境,不同的主管,不同的老闆,我很少遇到壞主管或壞老闆。當然所謂的壞我有我自己的定義。我講一個實例,我當兵是在成功嶺,當時還有兩個師,每個師還有三個旅,也在我退伍前正在進行精實案,那是後話。我下部隊的旅長,罵人真的是可以用狗血淋頭來形容,我常常自問,要是我是被罵的那個人,也許我會自殺。當然他是老資格的,他都對那些掛校級的大罵特罵,可是老實說,他也是我遇到的少數自我要求很高的軍官之一,而且,對待部屬真的是很用心。好像有點矛盾?沒錯,我要說的是他是好個長官,缺點只是太會罵人了。

帶人有很多方法,我之前也有過跟現在很像的狀況,我在單打獨鬥。有幸我跟了之前講的那個旅長,我見到很多大部隊的行動,我知道團隊作戰的方式,所以我對單打獨鬥很無力。說真的不是我不想融入大團隊,而是大家不是沒能力搞清楚狀況,就是保護自己保護的太好。沒錯,我被排除在外。我努力過,所以我心中坦然。

請主管一定要注意,你帶的都是你的子弟兵,要盡責的做好溝通協調的工作。不止是像前面說的幫員工找到位置,要讓團隊是整體的。人要無私很難,但是對大是大非面前,主管應該做好帶動團隊的責任。我也常見到互推責任的狀況,或是資深或是高階職位的人不肯負責任的情況。我也常自問到底是否我就是這種不肯多負責任的人?還是主管不肯給與更多責任?還是本來該別人負的責任他卻不知道?

這個不要讓我單打獨鬥也跟前面的議題有關。舉例來說也跟明確目標有關,也跟後面還沒特別提的專業分工有關。同儕之間都會怕互相得罪,所以身為主管協調不同團隊間的合作非常重要,這一點沒做好的話,沒資格當多團隊的主管。

員工的心聲 -10-請給我明確目標

.請給我明確目標

我有一份工作,主管人很好,我進去三個月了竟然都沒叫我做什麼,有一次我實在受不了跑去問主管的主管,主管的主管是總經理,官夠大了吧,總經理說,哦,我只是想讓你有充分的時間瞭解這間公司。我現在的這份工作,老闆人對我很是非常的好。

但是,上面說的兩份工作裡,前一份工作我跟總經理談辭職談了一年,目前這份工作也談過一次。當然會辭職不是因為沒明確目標,只是在說,這樣的好老闆,我還是一樣面臨換工作的痛苦。請相信我,當員工在跟你談「老闆,我想辭職」時,他的內心是很痛苦的。

我想,非常多人在遇到好工作時,都想在該份工作裡退休。至少我就有很多次起過這樣的念頭,可是最後最後我都選擇離職。我也很無奈,前面說了九個心聲,這個肯定也很重要。

很多有制度的公司,每年都會打考績,也常常有個步驟是要員工自評。其實,在我看來這都只是做表面的工夫。我到現在還沒遇到有哪個主管好好的跟我訂定年度目標,就更別說半年或是季度的目標。拜託,若主管都不知道我的目標在哪,我自己怎麼可能會知道?我若不知道我的目標在哪,每天每天就只是不停的把案子做完,我也會問,這樣就夠了嗎?

我相信,若真正有與員工談過目標的話,會發現所謂的目標並不是專案數或是能為公司帶來多少錢。當然很多主管就只會看錢。主管有責任為你的屬下訂定明確的目標,而專案,是主管的責任。

不懂的還是不懂,所以我多說一些好了。我會給我的屬下明確的說,請你負責把我們團隊的開發流程顧好。或是我會跟屬下說,我希望我們在丟給客戶的產品裡,都會要出現任何 bug。從這些目標,他會知道他的方向,當然,不是每個員工都能做好,那是他的責任。

我會遇到一個問題是,老闆老是談些虛幻的東西。給與正確的位置,賦與明確的責任,然後幫員工訂定明確的目標,這是很多主管做不到的。當然,我也正在努力而已,畢竟我真正當主管才一年多。

員工的心聲 -9-讓員工成為第一

.讓員工成為第一

我一直追求成為第一,成為世界第一。人貴自知,這四個字意義重大。我一直在反省自己,檢討自己。我也知道自己的短處,有些,是我不願意改的,有些是見仁見智的問題,改了不見得就比較好。當然,成為第一這件事不是指成就個人。讓員工學有專精,讓每個人都是頂尖人物,而且要不斷的學習。

成為第一,這件事也很難一言以蔽之。個人要如何成為第一?團隊要如何成為第一?不是努力付出就行。包含團隊是否和樂融融,包含互相間是否能無私奉獻,包含是不是能互相提攜。

很多人整天出差加班,已經加班到天怒人怨了,真的很多我認識的人都在抱怨,也有不少例子是因為加班到女友跑了,甚至,離婚的我也見識過。可是這樣的付出,他還是一臉茫然,當他停下來時,還是會發出「所為何求」的感嘆。更不要說成為第一了。

成為第一不是一項口號,喊喊就好。身為主管,一定要不斷的反省,不是只會要屬下反省。常常老闆就會出一張嘴,然後要屬下反省,要屬下付出。我說過了,不是付出更多就能成為第一。深切的反省是全面的,包含是不是人太少了?是不是用錯人了?是不是產品或是公司策略有問題?該反省的太多,實際上有反省,或是往正確方向反省的老闆少之又少。

我,常常遇到想做而做不到的狀況。我是個衝動的人,常常不顧自己的前途,可是換來的是沒有任何變化的可能。我通常選擇離開,也許我更該堅持。誰也不知道怎樣做才是最好的,所以我不後悔,只希望下次能更好。

員工的心聲 -8-讓員工有貢獻

.讓員工有貢獻

老實講,每個員工都應該是有貢獻的,要讓他明白,至少他在你心裡有著什麼貢獻。就算員工找到了自己的位置,不見得是有貢獻的。一個測試員對團隊有什麼貢獻?日復一日做著機械化的工作,到底他有什麼貢獻?我相信很多測試員會發出這樣的心聲。我舉一個最近的案例來說。

我的團隊參加一項比賽,當中只有一部份人有參與,隨著案子的進行,有的人是後來加入的,有的人提早離開,有的人是默默的進行,而總是會有人活躍於整個案子。誰的貢獻大些?那些沒參與的就沒貢獻?錯!常常的情況是沒在案子裡的,績效就差,有獎金制度的公司,這些人就很少有機會領到獎金。實情是,那些不活躍的或是沒參與的,都做些沒人要做的工作,才使得有人可以表現活躍,才使得整個案子成功。

任何情況下,要感謝每一個人,更要明白讓他們知道,你是知道他們的辛苦的。

事實上很多人都做著沒人要做的辛苦工,又覺得不受老闆重視,因此鬱鬱寡歡而選擇換工作。我常常自問,我的工作值得我領那麼多薪水嗎?事實上,很抱歉,我覺得不值。所以我都兢兢業業的,至少不要做破壞一鍋粥的老鼠屎。

老闆能不能幫員工找到最佳位置通常是個很大的挑戰,包括是不是有時間,也包括是不是有魄力排除人情因素。多方嚐試是必須的,但是也不能像無頭蒼蠅一樣讓員工盲忙茫,因盲目瞎忙而感到迷茫。我一直堅信工作是做不完的,我也相信只要肯用心,就能幫員工找到他適合的位置,因為我始終相信只有無用之將,沒有無用之兵。

員工的心聲 -7-請不要完全相信我,但是請尊重我

.請不要完全相信我,但是請尊重我

這個題目很奇怪,只是因為我遇到非常非常多的主管,都太相信我了。我的能力有限,真的。我也需要幫助,我也需要傾聽。當我碰到這種狀況時,我會選擇逃避,因為我會覺得愧對老闆。

負責任的員工常常內責,有時自己給的壓力太大而受不了。所以,請主管一定一定要去了解,要去問員工,為何進度落後,為何要加班,並且協助尋求解決的方法。在這邊我對那些被我拋棄的老闆們深深感到抱歉。

站在主管的立場來說,相信員工是應該的,站在員工的立場來說,獲得主管的信任是一種榮幸。但是,要了解員工不是神。就像我前面說的,要幫員工找到位置,若是賦與不適當的工作,常常是壓垮員工的最主要因素。

我沒什麼好方法去了解員工,也常常因為跟主管的距離感而不敢跟主管講我的處境,也常常因為自我要求而畫地自限。但是我本來就不是要提供方法,只是在講我的心聲而已。所以,主管請不要完全相信員工一定能做到你賦與的任務,也不要說什麼,我不管你怎麼做,就是一定要做到。

是的,我努力做到,但是請與我一起努力。

員工的心聲 -6-給我核心價值

.給我核心價值

前面提到要幫員工找到位置,那段文並沒特別強調核心價值,核心價值與貢獻並不保持正比例的相關。

常常有工程師,寫了很多的程式,也生產了很多產品,也每天加班了,股票也領了,獎金也拿了,可是還是不知道自己的核心價值。有一天,他突然失去工作了,下一份工作卻遲遲找不到。我週圍有些退休的人還想找到工作,也許只是為了肯定自己,也許只是為了讓生活不會太無聊,可是很多人能做的,就是警衛,甚至還找不到。

我以前在寫履歷時,上面會寫我會多少程式語言,會寫我生產多少產品。是的,這些都是工作累積的資本,但是,我也常常問我的核心價值是什麼?常常我面試時,看到的履歷上面會寫一段話,希望為公司帶來更大的利益,這,無法讓我看到核心價值。每個人每份工作,都有他的與它的核心價值。要去找出來,要大聲說出來。

要成為世界第一,首重的就是核心價值。我們常常看到別人的產品成功了,卻不知道它為何成功,或是自認為找到了,卻無法做到。當然我也會有這毛病。很多成功的背後,是要付出非常大的代價的。找到每個人的核心價值,找到團隊的核心價值,找到公司的核心價值,然後不斷的加強,不斷的累積,才有可能成為第一。

核心價值並不是一味的與眾不同,有些人的與眾不同只是嘩眾取寵而已。有些人的角色是讓產品更美,有些人的角色是讓產品更穩,有些人的角色是讓人使用起來很順暢,有些人的角色只是讓團隊能走好。必須肯定每個人的工作,並且,幫他找到核心價值。

我一直希望我能像老子說的,無為而治。無為而治是一種很高的境界,不是什麼都不做就算做到。其實我也曾遇到無為而治的主管,而我講的話又不被接受,所以我只好換工作。我真的希望每個員工都能找到自己的好位置,並且從中求得其核心價值,然後安心充實自我,並且提升團隊的能力與價值。

講這麼多還是沒講什麼叫核心價值。想想看,當你在找工作時,你如何說服老闆,用我就對了。這不用我說,每個人有他的角色該扮演,不同的角色會有不同的核心價值。

我老婆買菜,不同的菜色(肉、魚、蔬菜)會到不同的攤位去買,原因是什麼?因為,那些老闆會用最公正的價錢賣最好的貨。那,你呢?喔哦,我是指,那,我呢?

員工的心聲 -5-給我正常的生活

.給我正常的生活

我不想定義什麼叫正常的生活,有些人很自虐的,每天加班叫正常。涉入員工的生活當然不是好事,但是適度關心員工的需求是必要的,而不只是關心員工的苦悶而已。

正常的生活若純粹就加班來說,我不常加班,當然這意味著我也曾經加班。常見的工程師的生活型態是,加班到很晚,然後隔天很晚到公司,然後繼續加班到很晚。試問,這有意義嗎?當然還有的公司更糟,就算員工前天加班到凌晨,還是要求當天準時上班。

我在講創意時就說過,創意來自健康的身心,這就意味著要有正常的生活。一日三餐,早睡早起。我相信絕大多數的人都會同意在正常的生活下,人才有辦法保持長久的活力與靈活的腦力。可是身為主管卻常常為了要趕案子而讓員工加班,案子又永遠趕不完,所以加班加班再加班就變成常態。

是誰讓員工沒有正常的生活的?我也知道有些人私生活不正常,排除這種私人因素,若普遍存在員工一直加班,那只有一種可能,這個主管需要檢討,甚至可以說他不適任。

我知道不少人為了賺更多錢而努力加班,有些公司發獎金是看他累積多少加班時數。在我看來,加班時間愈多的人,代表他的績效愈差。

不過,有一種無奈的情形是,有能力的員工,主管就賦與他更重的責任,然後就天天加不完的班。常常主管也很無奈,不是找不到人,就是請不起更多人。我卻認為主管有責任全面提升每個員工的能力,也有責任平均分配員工的責任。當然安排適當的工作外,給予更多的責任也是必要的,但是常常是有能力的做的要死,沒能力的也閒的慌。

所以,給與員工正常的的生活,責任主要在於主管。對政府我們常有一種說法是,錯誤的政策比貪污還可怕。同樣的,主管下決策要小心。為公司帶來最大的利益有時不是一直接案子。

員工的心聲 -4-讓我停下來

.讓我停下來

我也曾加班過,也曾日夜顛倒過,當然做逃兵的次數更多。先不要說員工常常要應付鎖事,就說不斷的加班出差開會與簡報,對了,開會或是簡報也很煩人,員工每天要做這些事當然是應該的,但是身為主管,不能只一味的要求,而是要去思考,或是幫員工著想,有什麼辦法讓員工停下來。

我曾經在某高中同學的畢業紀念冊上寫著一句話,看,前面是休息再出發的好地方。就像一般人在說的,休息是為了走更長的路。但是工作中常常是不斷的加班,不斷的出差,不斷的開會,不斷的簡報,為了趕案子,然後,就把人折磨到死。

主管給員工好位置,給員工好薪水,給員工不斷學習充實自我的環境,給員工開放的環境,但是若從來不讓員工停下來,那還是死路一條。要讓員工停下來也不必花多少錢,也不必花多少心思,也許只是吃飯時間多一點,開會時間少一點,聊天時間多一點。也許偶而邀員工下盤棋,也許拉出去唱個歌,也許拍拍他的肩多看他一眼多問他一句話,也許只是對他說辛苦了。

讓員工能有時間停下來思考工作上的徵結出在哪,讓員工能有時間停下來看看下一步該怎麼走才最好,讓員工能有時間停下來好好照顧他的家庭。

我一直認為,若員工需要不斷的加班,不斷的出差,不斷的開會,不斷的簡報,那一定是主管有問題。把事情做好不是只有員工需要負責,事情做不好不是只有主管才會心急。主管自己也要停下來,也許只是讓心情平靜,我知道有些主管一直在生氣中,一直在自我要求也要求員工,但是,停下來不會讓事情停頓,而會讓大家能喘口氣,也會讓大家把事情看的更清楚。

員工的心聲 -3-要做有創意的事

.要做有創意的事

創意這件事常常讓人誤會,以為披頭散髮,或是每天醉茫茫的,或是煙燻繚繞,或是每天通宵熬夜等等就比較有創意。也常常有人以為創意是個人天分。也常常有人以為創意是一瞬間的靈感。也常常有人以為創意是學不來的。

創意不是藝術。事實上創意本身是身心健康的人才有的,正常的生活,健康的身體,然後一點一點累積,慢慢修改,與他人互補長短,才能成就創意。我這樣說不是說藝術就是要披頭散髮,或是每天醉茫茫的,或是煙燻繚繞,或是每天通宵熬夜等等才能有藝術。但是我不否認有些天才,有些外人看來是瘋子,他們是天才橫溢,但這不是我要講的內容。

我常常舉測試員,這次先還是舉測試員來說。測試員或是工廠作業員,一定是常常日復一日做著相同的事,如果,他能想出如何縮短工時,或提升產品良率,或是減少人員的方法,那他會很有成就感。

鼓勵員工發揮創意。有時鼓勵員工發揮創意也很簡單,傾聽與關心。常常與員工討論他們的工作,這一點我還做的不夠好,但是每個員工若都沒時間了,哪還會有創意?

創意常常是一點一點累積而來的,常常是很多人共同討論得來的,常常是要左顧右盼,參考非常多的其他事物而得的。不要認為創意來自天才,不要認為創意來自靈感。

我曾經工作在非常沉悶的環境中,當然沒多久我就逃離了。我換工作的一個因素是,工作太沈悶,我怕我會被扼殺在裡面。輕鬆的環境,自由的環境都是非常重要的因素。環境的塑造是主管的責任,當然要這個主管知道該做肯做,也要主管知道該怎麼做。還是那句話,反省是全面的。

員工的心聲 -2-讓員工能學到點什麼

.讓員工能學到點什麼

我換工作還有一項因素,常常我會覺得「我在這邊學不到任何東西」。到底有什麼好學的?不要以為舉辦一些課程就可以滿足每個人的學習欲,不要以為放開心胸讓員工上網不受限就算讓他們有充份的學習空間。何況常常公司因為沒經費無法舉辦教授活動,也常常因為資安或是什麼要讓員工專心工作而把很多網站鎖死。

有些話可以表達什麼地方可以讓人學到東西。譬如做中學,常常忙半天,卻不知道自己在做些什麼,這些人如何從工作中學到東西?做,但是要讓他知道自己在做什麼,知不足然後學之。

譬如身教重於言教。常常是上身不正,如何讓員工學到東西?至於什麼叫正,這一點不在我寫文章的目的中。身教不是指要當個聖人,但是一言一行要能當員工的表率。更多的是主管常常只會出一張嘴,平時嘻嘻哈哈的,出事時總是拿員工出氣。身教也不是要主管十八般武藝俱全,是有人能全才,但是那不是重點,不懂的地方,要從懂的人身上學。若主管都肯學了,還有哪個員工不認真學的話,該怎麼做不就很明顯了?

譬如不恥下問。常常主管總是官大學問大,自認為自己想的都是對的,不對一定是員工出錯,出錯也不去深明究裡只會大罵一通。去問清楚,去搞清楚,好好解決問題。若主管能保持這樣的心態,事情怎麼還會做不好?當然,事情若本身是錯的是另一回事,我只是想說,眾志成城。

譬如一枝草一點露。這句話用在學習或許是錯的。老天爺會給每個東西恩澤,但是也可以這樣想,就算只是一枝草,也可以生出一點露來,我舉這句不太洽當的話只是想說「到處都是可以學習的」。認真做事,把事做好,這就是不得了的工作,裡面的學問就非常大了。有人說,如果有一件事,可以讓你天天做,就算只是那麼一次那麼一瞬間,也是件大事。同樣的,既然會出現的事,若是那種每個案子都會遇到的,那就不會是小事。

主管如何分派工作,如何盯緊工作,如何解決瓶頸,如何分享喜悅,這些雖然不必言宣於外,但是不要以為沒人知道,你的員工都身在其中感受著你的一言一行。為員工創造學習的氣氛,把好的當模範,把壞的當教材,讓員工勇於改進。

就像我前面說的我會換工作的一個因素就是「我在這邊學不到任何東西」,事實上最多的情形是主管造成的。

員工的心聲 -1-幫員工找到位置

又到了年底,是換工作的好時機,我想,我是有資格來說說這個議題,員工的心聲,當然我是站在我的過去來談的,一個爬到經理的工程師的心聲。

.幫員工找到位置

這不是說沒辦公桌,不太可能,那什麼叫位置?很多時候工程師都很忙,忙東忙西,若問他到底在忙什麼,他會說一大堆。若問他為什麼要忙這些東西,絕大多數都是因為,要趕案子。這個議題要說的,其實是很多主管都沒考慮到的,每一個工程師在專案中所站的位置。我這樣說肯定也有很多人否認,但是,若細細把所有專案攤開來看,應該會發現,怪了,怎麼每個人在不同的專案中的位置不一樣了。

不是說不能換位置,老實講,我最近的工作一年半內換了七次辦公座位,但是我工作的角色始終沒變。始終沒變比較好呢,還是變來變去比較好?當然各有優缺,始終沒變也許正是始終處在一個不適合的位置,變來變去也許正是找不到適合的位置。

要幫你的屬下考慮,他的位置適當嗎?什麼時候該換位置了?

2009/12/02

網頁上的廣告?

前面貼了一篇關於 chrome os 的個人看法,而對 google 這家公司,相當相當多人在探討,這篇要說的也正是 google 最賺錢的產業,網頁廣告。

怎麼擴大廣告的收益,相信相當傷 google 的腦筋,這邊提供一個點子,我覺得也是大有商機。

在內嵌的廣告,不能是單向的根據關鍵字顯現,若能雙向的讓廣告根據網頁內容來「美化」網頁,相信非常有商機。

這話是怎麼說的呢?一般的廣告雖然跟關鍵字有關,但是有些則是太多文字,有些則是不相關的圖片,放在網頁上總感覺有那麼點突兀,若是廣告即網頁的一部份,甚至是不可或缺的一部份,是不是更能吸引人收看與刊登廣告呢?

Chrome OS 之我見

有幾個趨勢是大家都可以感受到的,
智慧手機....與筆電....小筆電成長率驚人
電子紙.....軟性顯示器.....微投影機....暫成顯學
這些裝置再搭配先前 Android 一推出,現在狀況是幾乎什麼裝置都在用 Android。相信有一堆人出現既生瑜何生亮之慨?Google 為什麼已經有了 Android 之後還要推 Chrome OS? Android 與 Chrome OS 孰優孰劣?

在今年七月時回答某友人的疑問時是這麼寫的:

----------------------
不管是 google 放出的訊息,我也相信一般人目前都認定 Chrome OS 與 Android 的市場區隔明顯是前者適合大尺寸,後者適合小尺寸。

不過,若讓我們看他們的本質,都是 based on internet, based on Cloud, 事實上兩者互相影響是必然的。我相信 Android 是比較高 performance, 應用程式也會發展的比較迅速。不過 Chrome OS 擅長在 Web Application 上,整合的難度非常少,所需要的技術相對也較低。

但是 Chrome OS 有一個致命的缺點,就是離線的應用程式必須搭配 google 本身在推的 Gears, 似乎推展的不是那麼順利。也就是說,Chrome OS 要離真正的大尺寸應用,關鍵點不在應用程式數量與品質,不在整合難易,而在離線應用程式的推廣面。

我一直非常看好 google, 若你要我選擇投靠哪一邊的話,我會說短期 Android, 長期 Chrome OS。一來是 Android 成熟,二來是 Android 需要用到的技術是很多人熟悉的 Eclipse + Java。而長期來看,google 要打敗微軟,勢必是在大尺寸上決勝負,因此目前有兩條路,一個是把 Android 作成適用於大尺寸,一個是把 Chrome OS 弄成熟。前者也勢必會發生,只是那樣還是離不開 Linux, Java, 而後者最大的優勢就是可以真正跟微軟開戰,因為它開發的所有應用,都可以拿到「微軟」的平台上執行,應該說,在 Chrome OS 上開發的應用程式,都可以真正的跨平台。

所以,若想跟隨 Google 的腳步,選擇 Chrome OS 絕對對未來是有利的。
-------------------------------

半年過去了,Chrome OS 也正式推出,雖然讓很多人失望,我的看法卻沒變。純就 Google 本身來說,多種選擇多管齊下是需要的,Google 也一直這麼做。google 在多種蒐購行動中,都有一個共同點,那就是致力於本務,網路搜尋與廣告。可以想像,一家公司大到世界第一之後,剩下要做的就是不斷的擴充與創造新的商機。踏入 OS 是已經現在進行式,那麼把 OS 的版圖持續擴大也是必然的。

Android 能取代微軟嗎?我覺得不是行不行的問題。如果說 Google 能打敗微軟的利器,就是在雲端運算上把眾多的網路應用帶入人間的話,Chrome OS 有一個最大最大的優勢,那就是硬體成本可以比 Android 還便宜。

經歷過多次的金融風暴之後,成本將會是繼熱消耗之後的最大考量。其實成本一直是消費者購物的最大考量,問題是現有的 OS 若要美觀與功能夠多,就算是 embedded linux 也做不到真正便宜。而我,相信 Chrome OS 能比 Android 生產出更便宜的裝置。我相信不久的將來,使用者將會把整個網路運算帶在身邊,那時候一個 chrome OS 可能是你的手錶,可能在眼鏡上,也可能在搖控器上,更別說 1000 元手機上。

2009/11/24

引用文件時的版權比較 CC / FDL

請見FDL 與創用 CC 授權條款之細部差異比較一文。下面僅列出原文中提到的幾條差異,文中有對兩項版權聲明的進一步說明。

一、FDL 明文規定,授權條款可視需要產生翻譯版本,但當兩者不一致時,以英文原文版本為準。而 CC 的 International 計畫,推動創用 CC 六種核心授權條款在各司法管轄領域的本地化,以我國情形為例,即是將尚未本地化 (unported) 創用 CC 授權條款翻譯成華文外,並配合我國著作權及相關法規作最小範圍的必要調整(註四)。

二、FDL 原是補足適用於自由軟體的 GNU General Public License 而來,使自由軟體相關的說明文件有「文件」適用的授權條款,但並不限於此,任何文字性作品都可適用,但是建議使用於操作說明或參考目的之作品。創用 CC 授權條款的適用客體則相對較 FDL 廣泛,任何文學或藝術創作都可適用,書籍、小手冊、甚至繪畫、攝影著作、戲劇或舞蹈著作都可依據創用 CC 授權條款提供大眾利用。

三、FDL 允許被授權人重製、散佈、改作、再授權、為商業目的使用採 FDL 授權的文件(以下簡稱本文件),另外也允許出租和公開展示(publicly display)本文件的重製物(註五)。創用 CC 「姓名標示-相同方式分享」授權條款,允許被授權人重製、散佈、修改、為商業目的使用採創用 CC 授權的著作(以下簡稱本著作)外,還允許公開演播 (publicly perform) 本著作或基於本著作而來的改用作品 (Adaptation),但禁止對本著作再授權(註六)。

此外,FDL 與創用 CC 授權條款都是全球性、免授權金、非專屬及在著作權存續期間內永久地授權。

四、FDL 規定本文件得包含免責聲明,且當有此免責聲明,該聲明將被視為FDL之一部,除此之外,FDL 無更細節的免責聲明規定。創用 CC 授權條款中則特別言明,授權人是以現狀之基礎(AS-IS)提供本著作,且未提供關於本著作之任何保證,也不對使用授權條款或本著作產生之損害負責。

五、FDL 要求被授權人不得以科技措施妨礙或控制本文件複本被閱讀或再重製。創用 CC 授權條款對被授權人使用科技措施規定則更嚴格,禁止被授權人使用任何科技措施於本著作/改用作品,而限制從其取得本著作/改用作品的接受者,行使創用 CC 授權條款所賦與他的一切權利。

六、FDL 對本文件印刷版超過 100 份的大量重製,有別於少量重製,另外要求當本文件授權聲明中要求封皮文字時,則本文件複本亦必須附上封面及封底,且清楚標示這些複本的發行散佈者 (publisher)(註七)。此外,當大量發行或散佈本文件複本超過 100 份時,FDL 允許不透明的重製格式 (0paque),但必須同時附上機器可辨讀的透明格式 (Transparent) 複本,或提供電腦網址讓公眾可下載透明格式的本文件;當選擇提供網址時,須確保此網址自被授權人最後一次散佈該不透明格式的本文件複本時起算一年是有效的。創用 CC 授權則未特別區別本著作少量或大量份數的重製。

七、FDL 允許被授權人重製及散佈修改作品的前提是,修改作品必須採用和原作品一模一樣的授權條款。創用 CC 「姓名標示-相同方式分享」 3.0 授權條款要求則相對較寬鬆,允許改用作品可採用與原著作相同的授權條款(或其後續版本),或與該授權條款具有相同授權要素的(3.0 或後續版本的)尚未本地化或任一司法管轄領域的授權條款。

八、不論是原作品複本或由原作品而來的修改作品的散佈, FDL 皆要求需標明誰是該特定版本的發行散佈者。相對地,創用 CC 授權條款則不著重於著作複本散佈者的區別及標示。

九、FDL 要求在修改作品中,除非獲得原作品作者的免除,否則須列出至少五位原作品的主要作者,且應列明該修改作品的作者。除此姓名標示目的外,原作品作者並未授權被授權人得使用其姓名作為對修改作品的背書。創用 CC 授權條款則要求,當散佈本著作、改用作品或彙編 (Collection),除非收到授權人的移除表彰的通知,否則必須表彰本著作創作者(即原始著作人)的姓名或筆名,且若原始著作人或本著作的授權人指定第三人(例如贊助機構、期刊)為姓名標示對象,則應提供之。創用 CC 授權並未如 FDL,對最低應標明之原作者人數有所要求。

十、FDL 要求修改作品中必須刪除原作品「背書」 (Endorsements) 標題的章節,但可增加對於修改作品的背書,例如該修改作品已經同儕審閱 (peer review) 的聲明。創用 CC 授權條款則規定,除非事先取得原始著作人、授權人或第三人之姓名標示對象的同意,否則被授權人不得暗示或主張,其本人或其對原著作的使用,與原始著作人、授權人或第三人之姓名標示對象間存在任何關連或有贊助或背書關係。

十一、FDL 規定,當被授權人非依授權條款所定方式使用本文件時,所獲授權將自動終止。 1.3 版新增授權恢復的規定,只要被授權人停止所有違反 FDL 規定的行為,則自某一特定著作權人得到的授權,可重新恢復。授權的恢復又分為暫時性恢復及永久恢復,只要停止違反 FDL 規定的行為,則授權即可暫時性恢復,除非被授權人所利用本文件的著作權人明確、且終局的終止對該被授權人的授權;若著作權人自被授權人停止違反 FDL 規定行為起的六十日內,未以合理方式通知該被授權人其違反規定的事實,則該被授權人將可永久恢復 FDL 的授權。此外,若被授權人是首次收到某一特定著作權人關於違反 FDL 規定的通知,且該被授權人在收到通知後的三十日內,即矯正其行為時,則 FDL 授權亦可永久恢復。創用 CC 授權條款規定,當被授權人違反任一款項,則授權條款所授予的權利將自動終止。創用 CC 授權未若 FDL 設有授權自動恢復的機制。

十二、當作品採用 FDL 時,可指定或不指定版本。若授權人指定適用某特定版本(如 1.3 版)或其後續版本,被授權人得遵循該特定版本授權條款的規定,或選擇適用該特定授權條款的後續版本;當作品未指定適用的版本時,被授權人可選擇適用自由軟體基金會曾發行過的任一版本的 FDL,包含先前或後續版本。此外, 1.3 版增設了代理人 (proxy) 機制,授權人可選擇一代理人為其決定,其以 FDL 授權的作品,未來以哪一版本釋出。當新版創用 CC 授權條款推出,並不會自動適用於採舊版授權條款的著作上,若要一著作同時適用不同版本的創用 CC 授權條款,則可依循多重授權模式釋出。此外,創用 CC 授權條款開放改用作品得採用與原著作相同的授權條款或其後續版本外,也可選擇適用與該特定授權條款具有相同授權要素的 3.0 或後續版本的尚未本地化或任一司法管轄領域的創用 CC 授權條款,但並不允許適用之前的版本(如 2.5 或 2.0 版)。

十三、對於一作品如何使用 FDL ,於授權條款最後設有附錄 (addendum) 說明之,且有提供著作權及授權聲明用語。創用 CC 授權條款對於標示方式則未另以附錄提供授權聲明參考用語,但在授權條款最後有「注意事項」,特別提到被授權人對於 Creative Commons 商標或任何與 Creative Commons 相關的商標或表徵的使用,只能是為了表明一著作依循創用 CC 授權之目的,且必須遵循 CC 當時的商標使用方針。

2009/10/12

Google GData API

請參考Google Data API 概觀。我另外寫了一篇在 Windows .Net 上使用 GData API

很多網頁應用程式都提供 RSS, ATOM 服務來提供方便的資料查詢與處理,最常見的是 News, Blog, Youtube, 或是網路相簿等等。想像一下,你在自己的應用程式利用 blog 來寫日記,不必用瀏覽器登入到 blog 而是用專屬的應用程式,除了登入外,張貼文章、瀏覽清單、刪除文章都是必要的動作。而這個需求可以透過 GData API 來完成,是一種建立在 HTTP 通訊協定上的資料操作,例如透過 Get, Put 等等來存取資料。

也就是說,只要網站提供 RSS, ATOM 等服務,就可以透過 GData API 來存取,這樣不止可以把網路服務嵌入到你的應用程式中,也可以整合不同的服務。

GData 通訊協定是中性的編程語言;您可以利用可發佈 HTTP 要求及解析 XML 要求的任何編程語言,來編寫用戶端。這也是在說明我上面講的應用程式不限網頁,也可以是 C, C++, C#, Python....or others..

底下是清單:








功能GDataAtomRSS 2.0
聯合發佈格式YYY
查詢YNN
更新YYN
開放式並行處理YNN
驗證YNN


也就是說,若你想透過分析 HTTP request/response 來使用 GData 的話,那大概就不受程式語言限制,若想直接使用 Google 提供的 GData 函式庫的話,底下是其支援清單:

Java, .Net, PHP, Python, Object-C, Javascript

Android 應用程式架構

請參考Android Application Framework說明。

Android 為了讓開發者可以儘量重複使用相同的元件,整個開發函式庫非常詳細,從上層來看應用程式的框架包括幾個部份,這些都與系統應用程式使用相同的元件,因此開發者可以很容易開發出具有特色的應用程式來取代之:

分析所有的應用程式都包含一系列的服務與系統,包括:

* 一個豐富而且可以擴充的 Views(視覺化),用來建立應用程式的操作介面,例如清單(lists), 格子(grids), 文字區塊(text boxes), 按鈕(buttons), 甚至嵌入一個瀏覽器
* 內容供應,用來讓應用程式存取,與其他應用程式互相溝通,或是與他人分享。
* 資源管理, 例如訊息內容,多國語言,操作介面的圖片,甚至是操作介面的定義資訊
* 提示管理,讓所有應用程式可以在共用的狀態列顯示客製化的訊息
* 活動管理,這邊的活動指的就是各個應用程式所進行的工作,例如回上一頁,或是熱鍵,或是關閉等等。

幾個重要的 Google APIs

有空的話,或許會把下列清單變成一篇篇的心得....先看著就好
========================================================
資料儲存與交換  ——Google Data APIs
使用者認證    ——Google Account Authentication API
多國語言     ——Google AJAX Language API
善用雲端運算   ——Google App Engine
圖表繪製元件   ——Google Chart API
視覺化設計    ——Google Visualization API
行事曆      ——Google Calendar API
試算表      ——Google Spreadsheets API
iGoogle主題設計  ——iGoogle Themes API
Google小工具開發 ——Google Gadgets API
桌面小工具    ——Google Desktop Gadget API
即時新聞     ——Google AJAX Feed API
社交       ——OpenSocial
社交圖譜     ——Google Social Graph API
好友清單     ——Google Contacts Data API
相簿       ——Picasa Web Albums Data API
影片       ——Youtube Data API
部落格      ——Blogger Data API
即時通訊     ——Google Talk XMPP
數據格式定義   ——Google Protocol Buffer API
為網站豐富AJAX內容——Google AJAX Libraries API
用戶廣告管理   ——Google Adwords API
廣告整合     ——Google AdSense API
線上付款     ——Google Checkout API
圖書搜尋     ——Google Book Search Book
嵌入Google搜尋  ——Google AJAX Search API
地圖服務     ——Google Maps API概述
地圖信息服務工具 ——Google Mapplets
地理標記語言   ——KML
靜態地圖服務   ——Google Static Maps API
讓應用支持桌面搜索——Google Desktop Search API
與線上文檔互動  ——Google Document List API
離線瀏覽     ——Google Gears
線上筆記     ——Google Notebook Data API

2009/08/12

Class, Abstract Class, and Interface

最近在研究用 C# 寫 Plugin, 為了 plugin 寫了二篇文章,分別是Class Interface, 及 Plugins

這邊就有個問題,一般我們在寫程式,大概都只會用到類別 "Class", 書上講的抽象類別(Abstract Class)似乎很少用到,更別提界面(interface)。不過在用 Plugin 時,一直都是用界面(Interface), 為什麼呢?若看得懂英文的,請參考Abstract Class vs Interface一文。

.抽象類別: 抽象類別其實非常像一般的類別,可以擁有 Private 的成員及方法,當然不同的地方就在於它也可以擁有 Abstract 的成員及方法。

.界面: 可以簡單說,界面是更抽象的類別,只能擁有 Public 及 Abstract 的成員及方法。要換一種說法就是,界面不必宣告,一切都當成 public && abstract,而且而且,因為是抽象的,所以都不能實作。

用下面的範例來看會比較容易明白:


//Abstarct Class
public abstract class Vehicles
{
private int noOfWheel;
private string color;
public abstract string Engine
{
get;
set;
}
public abstract void Accelerator();
}

//Interface
public interface Vehicles
{
string Engine
{
get;
set;
}
void Accelerator();
}


文中提到一種使用時機,若繼承關係中,基礎類別有可能被用來產生實例的話,當然就只能用一般類別,但是若不會發生這種可能,用抽象類別會是比較好的。至於界面,則是這個基礎類別若有「預設行為」的話只能用抽象類別,否則它就只是個界面。

寫到這兒,也大概了解為何 Plugin 只能用界面了,因為,不可能為 Plugin 給什麼預設行為不是?

讓我們從抽象類別與界面的字面意義來思考,抽象類別畢竟是類別,只是它是抽象的,所以在繼承中需要被「overlay」,就像看到「筆」這個抽象概念時,你會知道可以寫,而且不管哪種筆的寫都「差不多」一樣。可是界面之所以是界面,就是因為你可以預期它要提供的功能是什麼,可是界面只停留在界面,怎麼實作是沒個準頭的,要實際繼承的人去實作。而之所以被稱為界面,也限定了繼承的人一定要「全部」實作。

2009/08/10

主開機磁區(MBR)被 grub/lilo 蓋掉了怎麼回覆?

這問題一直都存在,早期的文獻(好像我也貼過)都說用 fdisk /mbr 來修復,不過自從檔案系統用 NTFS 之後,此一工具也不見了。我的狀況是電腦裝的是 windows 7, 後來用 Linux 要將它安裝到我的隨身碟,不知道什麼時候做了蠢事,要用原來的方式從硬碟開機時發現停在不正常的 grub 上,因為此時隨身碟不見了。

好吧,至少原來用 grub 開機的方式我辦得到,也就是說,我讓系統停在 grub shell 上,然後用傳統的方式來試著開機進 Windows,因為我是用隨身碟,此時硬碟變成 (hd1,0):

root (hd1,0)
rootnoverify (hd1,0)
chainloader +1
makeactive
boot

注意哦,就算進 windows 7(我相信 vista 也一樣)也找不到 fdisk, 所以就先停在 Windows 開機選單畫面,注意看的話可以看到 "F8" 修復的字樣,就給它用力按 F8 吧。

上面的方式也許有人不知道怎樣進去那個 F8 畫面,也可以拿原版光碟來,裡面會有相同的畫面。

好了,假設你在系統的 F8 畫面,請選擇 Command Window 吧,然後用下面的命令:

bootsect /nt60 c: /mbr /force

上面的 C: 是因為我用 F8 以硬碟開機的方式進去系統,相信若是用安裝光碟的話不是 c:,請自行修改。

最後,要理解二件事:
一、前面的 grub 設定方式可以讓你從硬碟開機進之前安裝的 Windows 7/Vista, 但是卻尚未修改開機設定,因此下次若用純硬碟開機還是會停在不完全的 Grub 選單中。
二、為何要按 F8? 因為 bootsect 不在正常的 Windows 7 中,只存在 Windows 7 的修復控制台中,上面說的就是透過按 F8 或是用安裝光碟來進到修復控制台。

2009/08/04

Data Binding
本文主要來自Piping Value Converters一文,有興趣的人也可以直接看MSDN Data Binding Overview

先來看看該文範例執行時的畫面如下:


而用來 Data Binding 的資料如下:

<?xml version="1.0" encoding="utf-8" ?>
<Tasks>
  <Task Name="Paint the living room" Status="0" />
  <Task Name="Wash the floor" Status="-1" />
  <Task Name="Study WPF" Status="1" />
  <Task Name="Rebuild kernel" Status="-1" />
  <Task Name="Kernel Install" Status="0" />
  <Task Name="Rebuild Driver" Status="1" />
</Tasks>

問題:

根據所提供的資料,如何把它依某一個屬性(範例中是用 Status)轉換成不同的 UI 元素?以此例除了 Pending, Complete, Active 外,還有顏色。

說明:

資料在繫結時(Data Binding),若有設定 Converter 屬性的話會先經過 IValueConverter型別的 Converter 方法轉換,對單一的轉換就是這麼簡單,可是若要多重轉換時怎麼處理才好呢?該文撰寫了一個繼承自 IValueConverter 的 ValueConverterGroup 來達成此目標。在實作上, ValueConverterGroup 可以擁有多個 Converters, 在呼叫 Converter 時,會依序呼叫。比較特別需要注意的是,前一個 converter 的輸出會當成下一個 converter 的輸入,直到最後一個 converter 的輸出被當成 target 為止。

由 ValueConverterGroup 實例來看問題:

範例中定義下面三個 ValueConverterGroup 實例(Instance), 關於 ValueConverterGroup 的定義則見後面的說明。重溫前面的問題,我們只有一個 Status 屬性,可是要做三件事,一是將數值型態的 Status 轉換成易讀的 Pending, Complete, Active,一是不同的 Status 以不同的顏色來顯示,三是對不同的 Status 顯示不同的 Tooltip.

    <!-- 第一部份: 將 Status 屬性值轉換成像 Pending, Complete, Active 這樣的字串以便顯示在 GUI 上 -->
    <local:ValueConverterGroup x:Key="statusDisplayNameGroup">
      <local:IntegerStringToProcessingStateConverter  />
      <local:EnumToDisplayNameConverter />
    </local:ValueConverterGroup>

    <!-- 第二部份: 根據 Status 屬性值轉換成不同的顏色,以便反應不同的狀態 -->
    <local:ValueConverterGroup x:Key="statusForegroundGroup">
      <local:IntegerStringToProcessingStateConverter  />
      <local:ProcessingStateToColorConverter />
      <local:ColorToSolidColorBrushConverter />
    </local:ValueConverterGroup>

    <!-- 第三部份: 根據 Status 屬性值轉換成不同的 Tooltip -->
    <local:ValueConverterGroup x:Key="statusDescriptionGroup">
      <local:XmlAttributeToStringStateConverter />
      <local:IntegerStringToProcessingStateConverter  />
      <local:EnumToDescriptionConverter />
    </local:ValueConverterGroup>   

從上面的實例可以看到三個 Key 值分別是 statusDisplayNameGroup, statusForegroundGroup, statusDescriptionGroup,使用上可以由 <DataTemplate> 來引用,範例如下,剛好可以看到三個 Converter 分別引用了這三個 Key 值:

    <DataTemplate x:Key="taskItemTemplate">
      <StackPanel
        Margin="2"
        Orientation="Horizontal"
        ToolTip="{Binding XPath=@Status, Converter={StaticResource statusDescriptionGroup}}"
        >
        <TextBlock Text="{Binding XPath=@Name}" />
        <TextBlock Text="   (" xml:space="preserve" />
        <TextBlock
          Text="{Binding XPath=@Status, Converter={StaticResource statusDisplayNameGroup}}"
          Foreground="{Binding XPath=@Status, Converter={StaticResource statusForegroundGroup}}" />
        <TextBlock Text=")" />
      </StackPanel>
    </DataTemplate>


有興趣的人也可以分析上面的 來看最後 GUI 所呈現的每一筆資訊都由 @Name, (, @Status, ) 四個部份組成,運用上將 Status 用三個 Converter 來轉換成需要的元素即達成目的。

ValueConverterGroup 的定義:

這邊我只列出 Convert 的定義:

object IValueConverter.Convert( object value, Type targetType, object parameter, CultureInfo culture )
{
object output = value;

for( int i = 0; i < this.Converters.Count; ++i )
{
IValueConverter converter = this.Converters[i];
Type currentTargetType = this.GetTargetType( i, targetType, true );
output = converter.Convert( output, currentTargetType, parameter, culture );

// If the converter returns 'DoNothing' then the binding operation should terminate.
if( output == Binding.DoNothing )
break;
}

return output;
}

上面定義被標示成紅色斜線的部份,也就是上面在說明一節提到的「前一個 converter 的輸出會當成下一個 converter 的輸入」的實作方式。順帶一提的是,在 Data Binding 時對錯誤資料的處理可以透過 Binding.DoNothing 來終止繫結。

2009/08/03

Picasaweb Viewer

請參考Picasaweb Viewer

這個範例讓視窗的寬、高隨著內容調整大小,其作法是在 xaml 的<window> 裡面設定 SizeToContent="WidthAndHeight"
整個視窗分成左右兩部份,左邊是取自 http://picasaweb.google.com/data/feed/api/user/USER_NAME?kind=album 的RSS feed 列表,右邊則是照片列表。因為都是清單,因此需要將新專案的 <Grid> 拿掉,放兩個 <ListBox> 上去。

Resource
在繼續修改之前,可以先將 Resource 設定好,其內容如下:

    <DockPanel.Resources >
     
      <XmlNamespaceMappingCollection x:Key="mapping">
        <XmlNamespaceMapping Uri="http://www.w3.org/2005/Atom" Prefix="default"/>
        <XmlNamespaceMapping Uri="http://schemas.google.com/photos/2007" Prefix="gphoto"/>
      </XmlNamespaceMappingCollection>
     
      <XmlDataProvider x:Key="Picasa" XmlNamespaceManager="{StaticResource mapping}" Source="http://picasaweb.google.com/data/feed/api/user/USER_NAME?kind=album">
      </XmlDataProvider>
    </DockPanel.Resources>

左半部「相簿清單」

可以注意到這邊會採用 XmlDataProvider 來做 Data Binding, 而這正是左半部的 ListBox 的資料來源,因此我們來看看左半部怎麼寫的:

      <ListBox DockPanel.Dock="Left" SelectionChanged="OnSelctionChanged" DataContext="{StaticResource Picasa}"  ItemsSource="{Binding XPath=default:feed/default:entry/default:title}">
      </ListBox>

在 DataContext 設定其值為 {StaticResource Picasa},這樣就可以把資料 Binding 好。同時請注意到 SelectionChanged 被設定成 OnSelctionChanged,如此一來就會在左邊的「項目」被點選而改變時,會呼叫 OnSelctionChanged() 來改變右邊的圖片清單。

右半部「照片清單」

至於右邊的清單寫法清微複雜,可以分成三部份來讀:

DataContext

      <ListBox.DataContext>
        <XmlDataProvider XmlNamespaceManager="{StaticResource mapping}">
        </XmlDataProvider>
      </ListBox.DataContext>

可以注意到右半部的 DataContext 與左半部有相同的 XmlNamespaceManager, 也許你一下子沒看出來,不過可以從左半部的 DataContext 使用 Picasa 這個資源就可以追出來。而最重要的 ItemSource 屬性則必須靠使用者點選左半部來改變,因此在 OnSelectionChanged() 中我們可以看到其定義,先讓我們瞧瞧整個事件的定義:

        public void OnSelctionChanged(Object source, RoutedEventArgs args)
        {
            ListBox lb = args.Source as ListBox;
            string simplestr;
            XmlDataProvider provider = MyListBox.DataContext as XmlDataProvider;
            if (provider != null)
            {
                simplestr = lb.SelectedValue.ToString().Substring(0,lb.SelectedValue.ToString().IndexOf('-'));
                simplestr = simplestr.Replace(" ", "");
                simplestr = simplestr.Replace(",", "");
                provider.Source = new Uri(@"http://picasaweb.google.com/data/feed/api/user/wade.fs/album/" + simplestr  + "?kind=photo");
            }
        }

  透過 provider.Source 的設值來動態改變 ListBox 的 ItemSource 屬性。

ItemTemplate

那麼我們如何設定每個清單是什麼樣的元素?可以透過 ListBox 的 ItemTemplate 屬性來設定,範例如下:

      <ListBox.ItemTemplate>
        <DataTemplate>
          <Image Source="{Binding XPath=@src}" Width="300"></Image>
        </DataTemplate>
      </ListBox.ItemTemplate>

而照片的網址則來自 RSS <content> 項目裡面的 "@src" 來指定,可以從 XPath 知道此項關聯。這邊又可以見到一項 Data Binding 的用法。

ItemsPanel

最後,照片清單的顯示若太多,常常會發生把視窗擠的變形到無法接受,若我們要採用比較像瀏覽器的方式的話,可以透過 ItemsPanel 來設定其 Layout, 範例如下:

      <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
          <WrapPanel/>
        </ItemsPanelTemplate>
      </ListBox.ItemsPanel>

Proxy Server

若您的環境是透過 Proxy Server 的話,又該如何在 WPF 中使用呢?可以在執行檔所在地產生一個 EXECUTE_FILE.exe.config,其內容很簡單,我們讓它使用與 IE 相同的 Proxy Server 設定值,範例如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.net>
    <defaultProxy useDefaultCredentials="true" enabled="true"></defaultProxy>
  </system.net>
</configuration>

2009/07/31

P2P by using WCF

P2P by using WCF
這是一個用C# 寫的應用,主要是練習 P2P,使用的是 .NET 3.0 推出的 WCF,可以參考 A simple peer to peer chat application using WCF netPeerTcpBinding。若對開啟 C# 應用有興趣的人,可以參考 Button Controls。P2P 可以想成一個應用程式本身具有 Client 及 Server。

Server

在 Server 端需要額外引入三個 namespace:

* System.ServiceModel;
* System.ServiceModel.Channels;
* System.ServiceModel.PeerResolvers;

完整程式碼如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.PeerResolvers;

namespace ChatServer
{
public partial class ChatServer : Form
{
private CustomPeerResolverService cprs;
private ServiceHost host;

public ChatServer()
{
InitializeComponent();
btnStop.Enabled = false;
}

private void btnStart_Click(object sender, EventArgs e)
{
try
{
cprs = new CustomPeerResolverService();
cprs.RefreshInterval = TimeSpan.FromSeconds(5);
host = new ServiceHost(cprs);
cprs.ControlShape = true;
cprs.Open();
host.Open(TimeSpan.FromDays(1000000));
lblMessage.Text = "Server started successfully.";
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
btnStart.Enabled = false;
btnStop.Enabled = true;
}
}

private void btnStop_Click(object sender, EventArgs e)
{
try
{
cprs.Close();
host.Close();
lblMessage.Text = "Server stopped successfully.";
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
btnStart.Enabled = true;
btnStop.Enabled = false;
}
}
}
}

很簡單,若真的要說程式片斷就在前面的六行:

cprs = new CustomPeerResolverService();
cprs.RefreshInterval = TimeSpan.FromSeconds(5);
host = new ServiceHost(cprs);
cprs.ControlShape = true;
cprs.Open();
host.Open(TimeSpan.FromDays(1000000));

cprs 是 CustomPeerResolverService 物件,用來當 ServiceHost 物件的輸入參數,主要會讀取一個設定檔(App.config), 並且設定連線資訊更新時間是 5ms。
host 是 ServiceHost 物件,並設定 timeout 時間為永不停止(1000000 天實在是非常久的時間)。然後....就這樣.....

CONFIG

至於設定檔,內容如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="System.ServiceModel.PeerResolvers.CustomPeerResolverService">
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost/ChatServer"/>
          </baseAddresses>
        </host>
        <endpoint address="net.tcp://localhost/ChatServer" binding="netTcpBinding"
                  bindingConfiguration="TcpConfig"
                  contract="System.ServiceModel.PeerResolvers.IPeerResolverContract">         
        </endpoint>         
      </service>
    </services>

    <bindings>
      <netTcpBinding>
        <binding name="TcpConfig">
          <security mode="None"></security>
        </binding>
      </netTcpBinding>
    </bindings>
  </system.serviceModel>
</configuration>


Client

Client 是稍微複雜了點,先貼一下原始程式碼如下,只需要用到兩個 namespace(System.ServiceModel, 及System.ServiceModel.Channels):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace ChatClient
{
[ServiceContract(CallbackContract = typeof(IChatService))]
public interface IChatService
{
[OperationContract(IsOneWay = true)]
void Join(string memberName);
[OperationContract(IsOneWay = true)]
void Leave(string memberName);
[OperationContract(IsOneWay = true)]
void SendMessage(string memberName, string message);
}

public interface IChatChannel : IChatService, IClientChannel
{
}

public partial class ChatClient : Form, IChatService
{
private delegate void UserJoined(string name);
private delegate void UserSendMessage(string name, string message);
private delegate void UserLeft(string name);

private static event UserJoined NewJoin;
private static event UserSendMessage MessageSent;
private static event UserLeft RemoveUser;

private string userName;
private IChatChannel channel;
private DuplexChannelFactory factory;

public ChatClient()
{
InitializeComponent();
this.AcceptButton = btnLogin;
}

public ChatClient(string userName)
{
this.userName = userName;
}

private void btnLogin_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txtUserName.Text.Trim()))
{
try
{
NewJoin += new UserJoined(ChatClient_NewJoin);
MessageSent += new UserSendMessage(ChatClient_MessageSent);
RemoveUser += new UserLeft(ChatClient_RemoveUser);

channel = null;
this.userName = txtUserName.Text.Trim();
InstanceContext context = new InstanceContext(
new ChatClient(txtUserName.Text.Trim()));
factory =
new DuplexChannelFactory(context, "ChatEndPoint");
channel = factory.CreateChannel();
IOnlineStatus status = channel.GetProperty();
status.Offline += new EventHandler(Offline);
status.Online += new EventHandler(Online);
channel.Open();
channel.Join(this.userName);
grpMessageWindow.Enabled = true;
grpUserList.Enabled = true;
grpUserCredentials.Enabled = false;
this.AcceptButton = btnSend;
rtbMessages.AppendText("*****************************WEL-COME to Chat Application*****************************\r\n");
txtSendMessage.Select();
txtSendMessage.Focus();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}

void ChatClient_RemoveUser(string name)
{
try
{
rtbMessages.AppendText("\r\n");
rtbMessages.AppendText(name + " left at " + DateTime.Now.ToString());
lstUsers.Items.Remove(name);
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.ToString());
}
}

void ChatClient_MessageSent(string name, string message)
{
if (!lstUsers.Items.Contains(name))
{
lstUsers.Items.Add(name);
}
rtbMessages.AppendText("\r\n");
rtbMessages.AppendText(name + " says: " + message);
}

void ChatClient_NewJoin(string name)
{
rtbMessages.AppendText("\r\n");
rtbMessages.AppendText(name + " joined at: [" + DateTime.Now.ToString() + "]");
lstUsers.Items.Add(name);
}

void Online(object sender, EventArgs e)
{
rtbMessages.AppendText("\r\nOnline: " + this.userName);
}

void Offline(object sender, EventArgs e)
{
rtbMessages.AppendText("\r\nOffline: " + this.userName);
}

#region IChatService Members

public void Join(string memberName)
{
if (NewJoin != null)
{
NewJoin(memberName);
}
}

public new void Leave(string memberName)
{
if (RemoveUser != null)
{
RemoveUser(memberName);
}
}

public void SendMessage(string memberName, string message)
{
if (MessageSent != null)
{
MessageSent(memberName, message);
}
}

#endregion

private void btnSend_Click(object sender, EventArgs e)
{
channel.SendMessage(this.userName, txtSendMessage.Text.Trim());
txtSendMessage.Clear();
txtSendMessage.Select();
txtSendMessage.Focus();
}

private void ChatClient_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
if (channel != null)
{
channel.Leave(this.userName);
channel.Close();
}
if (factory != null)
{
factory.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}

雖然小小長了點,可以看到 interface 中只有定義了三個動作:

Join : 用來登入用
Leave: 用來登出用
SendMessage: 用來傳送訊息

在繼續看這份 souce code 之前,先來讀一下設定檔:

Config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint name="ChatEndPoint" address="net.p2p://chatMesh/ChatServer"
                binding="netPeerTcpBinding" bindingConfiguration="PeerTcpConfig"
                contract="ChatClient.IChatService"></endpoint>
   </client>

    <bindings>
      <netPeerTcpBinding>
        <binding name="PeerTcpConfig" port="0">
          <security mode="None"></security>
          <resolver mode="Custom">
            <custom address="net.tcp://localhost/ChatServer" binding="netTcpBinding"
                    bindingConfiguration="TcpConfig"></custom>
          </resolver>
        </binding>
      </netPeerTcpBinding>
      <netTcpBinding>
        <binding name="TcpConfig">
          <security mode="None"></security>
        </binding>
      </netTcpBinding>
    </bindings>
  </system.serviceModel>
</configuration>


對應到前面講的 Join, Leave, SendMessage 三個介面,需要三個事件來配合:

private static event UserJoined NewJoin;
private static event UserSendMessage MessageSent;
private static event UserLeft RemoveUser;

Event 的使用在程式中如下:

NewJoin += new UserJoined(ChatClient_NewJoin);
MessageSent += new UserSendMessage(ChatClient_MessageSent);
RemoveUser += new UserLeft(ChatClient_RemoveUser);

聊天室功能裡面,最重要的就是聊天,對,有點廢話,不過難就難在網路連線的維護,幸好都被 WCF 做掉了,在程式裡面是透過 DuplexChannelFactory() 物件來達成:

factory = new DuplexChannelFactory(context, "ChatEndPoint");
channel = factory.CreateChannel();

若我們看看幾個動作即可明白中間的關聯:

channel.Join(this.userName);
channel.SendMessage(this.userName, txtSendMessage.Text.Trim());
channel.Leave(this.userName);
channel.Close();

好了,就這樣。什麼?沒講完?對,聰明的你一定有發現,好像沒指出收訊息的機制?呵,其實是沒特別講清楚而已。

訊息收送

收: MessageSent += new UserSendMessage(ChatClient_MessageSent);
送: channel.SendMessage(this.userName, txtSendMessage.Text.Trim());

2009/07/24

在 blog 中優化顯示程式碼片段

底下的內容是 CSS, 放在 blog 設定畫面裡版面配置==>修改 HTML==>找到類似 body{ 附近(意指在它的前面或是那一段的後面, 不要插到裡面去了)插入下面兩種可以選擇之一的 CSS 碼, 一個是用 <Code> 括住,使用時的範例如下:

<Code>
code {
display: block;
font-family: Courier New;
font-size: 9pt;
overflow:auto;
background: #fff5ee url(http://sites.google.com/a/hc888.com.tw/file/img/Code_BG0.gif) left top repeat-y;
border: 1px solid #ccc;
padding: 5px 5px 5px 20px;
max-height:200px;
line-height: 1.2em;
margin: 5px 0 0 15px;
}
</CODE>


效果如下:

code {
display: block;
font-family: Courier New;
font-size: 9pt;
overflow:auto;
background: #fff5ee url(http://sites.google.com/a/hc888.com.tw/file/img/Code_BG0.gif) left top repeat-y;
border: 1px solid #ccc;
padding: 5px 5px 5px 20px;
max-height:200px;
line-height: 1.2em;
margin: 5px 0 0 15px;
}


或者用有縮編的 PRE tag, 在寫 blog 時的範例如下:

<PRE>
pre {
display: block;
font-family: Courier New;
font-size: 9pt;
overflow:auto;
background: #fff5ee;
border: 1px solid #ccc;
padding: 5px 5px 5px 20px;
max-height:200px;
line-height: 1.2em;
margin: 5px 0 0 15px;
}
</PRE>

效果如下:

pre {
display: block;
font-family: Courier New;
font-size: 9pt;
overflow:auto;
background: #fff5ee;
border: 1px solid #ccc;
padding: 5px 5px 5px 20px;
max-height:200px;
line-height: 1.2em;
margin: 5px 0 0 15px;
}

2009/07/18

The value of Multi touch 的價值

要說 multi touch 的價值實在是愧不敢當,但是最近的工作剛好就是在開發多點觸控的應用程式,跟著一群年輕小夥子工作,感覺非常溫馨之餘,也讓我有機會在跟他們探討中去深思多點觸控到底價值何處?

一開始我對多點觸控的期待,就是改變對電腦的操作,當然我更想要像駭客任務那樣,不止可以觸控,最希望的是立體感那種操作,最好要更先進的思想操作。但是在接觸多點觸控一年來,發現裡面的問題不少,但是這篇不是要講問題點,而是要講價值。

大概最快想到的就是「手勢操作」。可是問題是誰來定義手勢?M$ 確實定義了些手勢操作,可是若實際去開發軟體的話就會發現其中存在不少問題,這邊指的是我們開發軟體的過程,而不是「應用」。問題在我們的功力還不夠,幸好也是因為大家都聚精會神的研究並解決問題,因而讓我更有機會去探索多點觸控的價值,而這樣的思考至少目前必須先面對 M$ 所建立起來的環境是那麼的複雜與充滿矛盾上。

第一個價值,當然希望能有更直覺式的操作,剛剛提到手勢就是這樣的產物。目前開發出來的就是 Zoom In/ Zoom Out, Scroll, PAN(Move) 這三個。事實上滑鼠也可以做到。我一直在思考,click, double click, move, drag....與 what is gesture! 困惑著我。答案或許是,請拋棄滑鼠吧。(註: 鍵盤留著)

第二個價值,是希望能讓整個螢幕上出現的框框有立體操作感。立體感早就有了,我說的是立體的操作感,否則只是多了另一隻滑鼠而已。要有立體操作感很難,要在平面表達立體已經發展多年,早期都是用滑鼠,當然相安無事,現在要在投射在平面所產生的立體物件上操作,難度非常大。幸好,我也定義了三種操作,有機會再來分享。我們定義了一些立體操作與手勢,希望能改變人類操作平面電腦的習慣,這邊講平面的意思當然是希望將來的顯示裝置操作起來能隨想隨動。

第三個價值,是......趁著這波可攜熱與觸控熱,讓觸控拉近你我彼此間的距離變得更加容易。我個人一直是在玩 Linux, 嵌入式是我的擅項,突然來搞 M$ 真是有夠突兀,不過這不妨礙,問題是我最想要的是建立一個龐大而自然的虛擬世界,能因此而實現嗎?

且拭目以待吧。

2009/06/28

win7 比 vista 便宜 ... 20% off!

微軟在其網站上,正式公告售價:

昇級版售價:
* Windows 7 Home Premium (Upgrade): $119.99
* Windows 7 Professional (Upgrade): $199.99
* Windows 7 Ultimate (Upgrade): $219.99

完整版售價:

* Windows 7 Home Premium (Full): $199.99
* Windows 7 Professional (Full): $299.99
* Windows 7 Ultimate (Full): $319.99

這意味著,因應經濟不景氣,微軟大發慈悲心,大降價,以 Win7 Home Premium 為例大約降價 20%!

2009/06/23

xp, vista, win7 共舞 multi-boot -2

先前寫過一篇xp, vista, win7 共舞,後來又因為不知名的原因把某一個開機選項弄不見了。真的,不是故意為之。那問題來了,怎樣把之前的開機選項搞出來?

其實這問題或許最好的答案是養成備份習慣。不過因為是實驗機,所以我也就懶得備份,再說,工作機也不需要搞這東東。

BCDE FAQ....這文章還真怪,BCDEF...Ok Ok, 不離題,在這篇文章中提到要怎樣自己弄一個新的開機選項,請見 How to create a new Windows Vista operating system entry 這一條的說明。步驟大約如下:

1. bcdedit /copy {GuidToCopy} /d 「NewEntryDescription」
==> 我是這麼下命令的:
bcdedit /copy {current} /d "win7 enterprise"
==> 這樣一來,會把目前的開機選項複製並附在選單的最後。若是注意的話,會發現 Identifier 是新的,其餘的都是與 {current} 相同。

2. 用下列兩個命令來設定到你要的磁區,也就是「磁碟機」:
bcdedit /set {NewGuid} device partition=x:
bcdedit /set {NewGuid} osdevice partition=x:
==> 這邊的 {NewGuid} 就是上一條產生的 Identifier, 而 x: 就是你要的磁碟機

3. 用下列命令調整開機順序,不執行此命令也行
bcdedit /displayorder {NewGuid} /addlast

2009/06/12

screen capture

我們有一個應用程式,需要抓取全螢幕的畫面,有人會截取 PrtScn Keyboard 事件來達到目的,我當然認定這個方法非常不好,就像前面講的 mouse hook 一樣,別人一樣也可以做 keyboard hook。

後來用了某種 screen capture 的方法,結果把螢幕上所有東西都抓下來,或許這結果是某些人想要的,但是我們卻不要像滑鼠或是一些 Gesture 提示的畫面。目前找到一篇Screen Captures, Window Captures and Window Icon Captures with Spy++ style Window Finder!有不錯的範例,請自行前往觀看。

Touch 與 mouse 共舞

最近在搞 Windows 7 的 Multi Touch 應用程式,其中有幾項議題困擾很久,其中一項是 sleep(1) 已於前面說明。另一項是 Touch 發生時我們不想要有 Mouse Event, 我說的是不想要,不是不處理即可,這問題讓我煩到快抓狂。

不抱怨了,直接說答案,就是用 Global Mouse Hook, 然後把 Mouse Message 濾掉。是有不少例子在說明 mouse hook, 例如我看的最懂的是Processing Global Mouse and Keyboard Hooks in C#,卻沒有人講明白怎樣濾掉 mouse message.

事實上在該文中有答案,只是它沒明說而已。我直接寫一個範例片段來說明,當然說明直接放程式片段中:

// 註冊 global mouse hook
void TFormPaint::RegMouseHook()
{
MouseHookDelegate = gcnew HookProcDelegate(this, &TFormPaint::MouseHookProc);
MouseHookHandle = ::SetWindowsHookEx(WH_MOUSE_LL, MouseHookDelegate,
Marshal::GetHINSTANCE(System::Reflection::Assembly::GetExecutingAssembly()->GetModules()[0]),0);
}

// 我們處理的 mouse hook 的函式
int TFormPaint::MouseHookProc(int nCode, int wParam, IntPtr lParam)
{
WCHAR Buffer[30];

// 把 Mouse Hook 的訊息從 lParam 指標中取出來
MOUSEHOOKSTRUCT* mouseHookStruct=(MOUSEHOOKSTRUCT*)lParam.ToPointer();

// 只濾掉發生在本視窗的滑鼠事件,
// 所以要比對滑鼠所發生時的視窗
HWND CurHwnd = WindowFromPoint(mouseHookStruct->pt);
GetWindowText(CurHwnd, Buffer, 30);
String^ WindowTitle = gcnew String(Buffer);

// ☆重點來了,
// 當發現滑鼠事件是作用在我們的視窗上,就以
// return -1 來濾掉
if (WindowTitle->IndexOf(this->Text) != -1)
{
return -1;
}

// 下面這行非常重要,否則整個系統的滑鼠會因此壞掉
return CallNextHookEx(MouseHookHandle, nCode, wParam, lParam);
}

sleep 1 ms ?

還記得四月初時我寫的這一篇timer 與 while(1)嗎?最近在用 visual studio 開發應用程式時有用到 sleep() 函式來暫時停止程式運行,用我們的話說,就是我們要讓程式的執行頻率是 125 次/秒,也就是我們想要用 sleep(8) 來達到目的。sleep(8) 應該要能暫停 8ms, 結果實驗數據是 16ms, 甚至當我們調整成 sleep(1), 答案也一樣。

慘了,效率只有一半!這問題困擾很久,試著用 timer,答案一樣的令人沮喪,也試過透過 Windows Message 的方式,沒用。

好了,最後結果是參考timeBeginPeriod搭配 timeEndPeriod。因為這會改到系統的時間設定,因此記得要成對。

簡單寫個範例如下:
timeBeginPeriod(8);
sleep(8);
timeEndPeriod(8);


想對 Timer 有更進一步了解的人,可以自行參考Timer 介紹一文。

2009/06/08

xp, vista, win7 共舞 multi-boot

最近真的是離不開 M$ OS, 甚至一台電腦要裝九個作業系統,當然啦,是資源不足才需要這樣。問題來了,開機選單在 winxp 還可以透過界面修改,可是 vista, win7 全都不開放!現在研究後的心得如下,請在 vista or win7 下執行:

一、首先在 Command Prompt, 也就是 DOS command, 上用右鍵選「Run as Administrator」,這樣才有足夠的權限,若找不到的話請參考:
Start Menu->All Programs->Accessories->Command prompt(在上面點右鍵選擇"Run as administrator")

二、可以用 bcdedit /enum 列出所有開機選單,例如下面的是我的電腦的範例, # 號後面的是我加的註解:


Windows Boot Manager
--------------------
identifier {bootmgr}
device partition=D:
description Windows Boot Manager
locale en-US
inherit {globalsettings}
default {current}
resumeobject {42231781-52f5-11de-92a1-f650bd7a3f2b}
displayorder {ntldr}
{current}
{42231782-52f5-11de-92a1-f650bd7a3f2b}
{4223177e-52f5-11de-92a1-f650bd7a3f2b}
{b1252275-52ef-11de-ac3a-e7ceed221dbd}
toolsdisplayorder {memdiag}
timeout 30

Windows Legacy OS Loader
------------------------
identifier {ntldr}
device partition=D:
path \ntldr
description 舊版 Windows

# 可以用下列命令改掉
# bcdedit /set {ntldr} Description "XP 32/64"

Windows Boot Loader
-------------------
identifier {current}
device partition=C:
path \Windows\system32\winload.exe
description Microsoft Windows Vista
locale en-US
inherit {bootloadersettings}
osdevice partition=C:
systemroot \Windows
resumeobject {adc6e5dc-5450-11de-b61c-8253c0de8538}
nx OptIn
# 可以用下列命令將原來的"Microsoft Windows Vista" 改掉
# bcdedit /set {current} Description "Vista 32 en Enterprise"

Windows Boot Loader
-------------------
identifier {42231782-52f5-11de-92a1-f650bd7a3f2b}
device partition=I:
path \Windows\system32\winload.exe
description Windows 7
locale zh-TW
inherit {bootloadersettings}
recoverysequence {42231783-52f5-11de-92a1-f650bd7a3f2b}
recoveryenabled Yes
osdevice partition=I:
systemroot \Windows
resumeobject {42231781-52f5-11de-92a1-f650bd7a3f2b}
nx OptIn
# 可以用下列命令將原來的 "Windows 7" 改掉
# bcdedit /set {42231782-52f5-11de-92a1-f650bd7a3f2b} Description "Win7 64 Ultimate"

Windows Boot Loader
-------------------
identifier {4223177e-52f5-11de-92a1-f650bd7a3f2b}
device partition=H:
path \Windows\system32\winload.exe
description Windows 7
locale en-US
inherit {bootloadersettings}
recoverysequence {4223177f-52f5-11de-92a1-f650bd7a3f2b}
recoveryenabled Yes
osdevice partition=H:
systemroot \Windows
resumeobject {4223177d-52f5-11de-92a1-f650bd7a3f2b}
nx OptIn
# 可以用下列命令將原來的 "Windows 7" 改掉
# bcdedit /set {4223177e-52f5-11de-92a1-f650bd7a3f2b} Description "Win7 32 Ultimate"

Windows Boot Loader
-------------------
identifier {b1252275-52ef-11de-ac3a-e7ceed221dbd}
device partition=E:
path \Windows\system32\winload.exe
description Microsoft Windows Vista
locale en-US
inherit {bootloadersettings}
osdevice partition=E:
systemroot \Windows
resumeobject {b1252276-52ef-11de-ac3a-e7ceed221dbd}
nx OptIn
# 可以用下列命令將原來的 "Microsoft Windows Vista" 改掉
# bcdedit /set {b1252275-52ef-11de-ac3a-e7ceed221dbd} Description "Vista 64 Enterprise"


三、在上文提到的 {current} 還有 {default} 等選擇文字,其實就在 /enum 列出的 "identifier" 欄位裡面

四、 用 bcdedit /? 取得進一步資訊

2009/05/20

Programming with Windows 7 Multitouch & Gesture 續

軟體與硬體需求

當然要有硬體與作業系統及 SDK:
A multi-touch monitor
A PC or NB installed Windows 7
Installed Windows 7 SDK
Visual Studio(我用的是 Visual Studio 2008)

環境設定

設定Win7 SDK的路徑, 包含include與library都要設定:
Header :Declared in Winuser.h; include Windows.h.
Library:Include User32.lib

接下來請參考前一篇的資料結構,因為微軟的開發模式都差不多,在寫 Multitouch 與寫 Mouse 的方式很像,就是收 Message, 定義自己得 event handler, 底下就列出相關的 Message:


WM_GESTURE Message

Passes information about a gesture.

Parameters

wParam


Provides information identifying the gesture command and gesture-specific argument values. This information is retrieved by calling GetGestureInfo.

lParam

Provides information identifying the gesture command and gesture-specific argument values. This information is retrieved by calling GetGestureInfo.

Return Value

If an application processes this message, it should return 0.

If the application does not process the message, it must call DefWindowProc. Not doing so will cause the application to leak memory because the touch input handle will not be closed and associated process memory will not be freed.

WM_GESTURENOTIFY Message

Indicates that a gesture message is about to be received.

Parameters

wParam


Unused.

lParam

A pointer to a GESTURENOTIFYSTRUCT.

Return Value

If an application processes this message, it should return 0.

Remarks

When the WM_GESTURENOTIFY message is received, the application can use SetGestureConfig to specify the gestures to receive.

Examples

switch (message)
{
case WM_GESTURENOTIFY:
{
GESTURECONFIG gc = {0,GC_ALLGESTURES,0};
BOOL bResult = SetGestureConfig(hWnd,0,1,&gc,sizeof(GESTURECONFIG));

if(!bResult)
{
// an error
}
}

break

GESTUREINFO Structure

Stores information about a gesture.
Syntax

typedef struct _GESTUREINFO {
UINT cbSize;
DWORD dwFlags;
DWORD dwID;
HWND hwndTarget;
POINTS ptsLocation;
DWORD dwInstanceID;
DWORD dwSequenceID;
ULONGLONG ullArguments;
UINT cbExtraArgs;

} GESTUREINFO, *PGESTUREINFO;

Members

cbSize

The size of the structure, in bytes. The caller must set this to sizeof(GESTUREINFO).

dwFlags

The state of the gesture. For additional information, see Remarks.

dwID

The identifier of the gesture command.

hwndTarget

A handle to the window that is targeted by this gesture.

ptsLocation

A POINTS structure containing the coordinates associated with the gesture. These coordinates are always relative to the origin of the screen.

dwInstanceID

An internally used identifier for the structure.

dwSequenceID

An internally used identifier for the sequence.

ullArguments

An unsigned long long that contains the arguments for gestures that fit into 8 bytes.

cbExtraArgs

The size, in bytes, of extra arguments that accompany this gesture.

Remarks

The GESTUREINFO structure is retrieved by passing the handle to the gesture information structure to the GetGestureInfo function.

The following flags indicate the various states of the gestures and are stored in dwFlags.
Name Value Description
GF_BEGIN 0x00000001 Indicates a gesture is starting
GF_INERTIA 0x00000002 Indicates a gesture has triggered inertia
GF_END 0x00000004 Indicates a gesture has finished

Note Most applications should ignore the GID_BEGIN and GID_END messages and pass them to DefWindowProc. These messages are used by the default gesture handler and application behaviour is undefined when the GID_BEGIN and GID_END messages are consumed by a third party application.

The following table indicates the various identifiers for gestures.


Name Value Description
GID_BEGIN 1 Indicates a gesture is starting.
GID_END 2 Indicates a gesture is ending.
GID_ZOOM 3 Indicates the zoom gesture.
GID_PAN 4 Indicates the pan gesture.
GID_ROTATE 5 Indicates the rotation gesture.
GID_TWOFINGERTAP 6 Indicates the two-finger tap gesture.
GID_ROLLOVER 7 Indicates the rollover gesture.
Examples

GESTUREINFO gestureInfo = {0};

gestureInfo.cbSize = sizeof(gestureInfo);

BOOL bResult = GetGestureInfo((HGESTUREINFO)lParam, &gestureInfo);


dwCommand dwArguments ptsLocation
Pan Distance between contacts Current center of gesture
Zoom Distance between contacts Current center of gesture
Rotate Absolute angle on rotate start, delta on updates Current center of gesture
Two-finger tap NA Current center of gesture

GESTURENOTIFYSTRUCT Structure

When transmitted with WM_GESTURENOTIFY messages, passes information about a gesture.

Syntax

typedef struct tagGESTURENOTIFYSTRUCT {
UINT cbSize;
DWORD dwFlags;
HWND hwndTarget;
POINTS ptsLocation;
DWORD dwInstanceID;

} GESTURENOTIFYSTRUCT, *PGESTURENOTIFYSTRUCT;

Members

cbSize

The size of the structure.

dwFlags

Reserved for future use.

hwndTarget

The target window for the gesture notification.

ptsLocation

The location of the gesture.

dwInstanceID

A specific gesture instance with gesture messages starting with GID_START and ending with GID_END.

GESTURECONFIG Structure

Gets and sets the configuration for enabling gesture messages and the type of this configuration.

Syntax

typedef struct _GESTURECONFIG {
DWORD dwID;
DWORD dwWant;
DWORD dwBlock;

} GESTURECONFIG, *PGESTURECONFIG;

Members

dwID

The identifier for the type of configuration that will have messages enabled or disabled. For more information, see Remarks.

dwWant

The messages to enable.

dwBlock

The messages to disable.

Remarks

When you pass this structure, the dwID member contains information for a set of gestures. This determines what the other flags will mean. If you set flags for pan messages, they will be different from those flags that are set for rotation messages.

The following table indicates the various identifiers for gestures that are supported by the dwID member of the GESTURECONFIG structure. Note that setting dwID to 0 indicates that global gesture configuration flags are set.

GetGestureInfo Function

Retrieves a gesture information structure given a handle to the gesture information.

Syntax

BOOL WINAPI GetGestureInfo(

__in HGESTUREINFO hGestureInfo,

__out PGESTUREINFO pGestureInfo

);

Parameters

hGestureInfo [in]

The gesture information handle.

pGestureInfo [out]

A pointer to the gesture information structure.

Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, use the GetLastError function.

Examples

GESTUREINFO gestureInfo = {0};

gestureInfo.cbSize = sizeof(gestureInfo);

BOOL bResult = GetGestureInfo((HGESTUREINFO)lParam, &gestureInfo);

SetGestureConfig Function

Configures the messages that are sent from a window for multitouch gestures.

Syntax

BOOL WINAPI SetGestureConfig(
__in HWND hwnd,
__in DWORD dwReserved,
__in UINT cIDs,
__in PGESTURECONFIG pGestureConfig,
__in UINT cbSize
);

Parameters

hwnd [in]

A handle to the window to set the gesture configuration on.

dwReserved [in]

This value is reserved and must be set to 0.

cIDs [in]

A count of the gesture configuration structures that are being passed.

pGestureConfig [in]

An array of gesture configuration structures that specify the gesture configuration.

cbSize [in]

The size of the array of gesture configuration structures.

Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, use the GetLastError function.

Programming with Windows 7 Multitouch & Gesture

請參考Microsoft MSDN Windows Touch for Developer一文,以及微軟「阿倫」的部落格的說明。

我這邊先直接貼一些資料結構的定義:


#if(WINVER >= 0x0601)

/*
* Gesture defines and functions
*/

/*
* Gesture information handle
*/
DECLARE_HANDLE(HGESTUREINFO);


/*
* Gesture flags - GESTUREINFO.dwFlags
*/
#define GF_BEGIN 0x00000001
#define GF_INERTIA 0x00000002
#define GF_END 0x00000004

/*
* Gesture IDs
*/
#define GID_BEGIN 1
#define GID_END 2
#define GID_ZOOM 3
#define GID_PAN 4
#define GID_ROTATE 5
#define GID_TWOFINGERTAP 6
#define GID_PRESSANDTAP 7
#define GID_ROLLOVER GID_PRESSANDTAP

/*
* Gesture information structure
* - Pass the HGESTUREINFO received in the WM_GESTURE message lParam into the
* GetGestureInfo function to retrieve this information.
* - If cbExtraArgs is non-zero, pass the HGESTUREINFO received in the WM_GESTURE
* message lParam into the GetGestureExtraArgs function to retrieve extended
* argument information.
*/
typedef struct tagGESTUREINFO {
UINT cbSize; // size, in bytes, of this structure (including variable length Args field)
DWORD dwFlags; // see GF_* flags
DWORD dwID; // gesture ID, see GID_* defines
HWND hwndTarget; // handle to window targeted by this gesture
POINTS ptsLocation; // current location of this gesture
DWORD dwInstanceID; // internally used
DWORD dwSequenceID; // internally used
ULONGLONG ullArguments; // arguments for gestures whose arguments fit in 8 BYTES
UINT cbExtraArgs; // size, in bytes, of extra arguments, if any, that accompany this gesture
} GESTUREINFO, *PGESTUREINFO;
typedef GESTUREINFO const * PCGESTUREINFO;


/*
* Gesture notification structure
* - The WM_GESTURENOTIFY message lParam contains a pointer to this structure.
* - The WM_GESTURENOTIFY message notifies a window that gesture recognition is
* in progress and a gesture will be generated if one is recognized under the
* current gesture settings.
*/
typedef struct tagGESTURENOTIFYSTRUCT {
UINT cbSize; // size, in bytes, of this structure
DWORD dwFlags; // unused
HWND hwndTarget; // handle to window targeted by the gesture
POINTS ptsLocation; // starting location
DWORD dwInstanceID; // internally used
} GESTURENOTIFYSTRUCT, *PGESTURENOTIFYSTRUCT;

/*
* Gesture argument helpers
* - Angle should be a double in the range of -2pi to +2pi
* - Argument should be an unsigned 16-bit value
*/
#define GID_ROTATE_ANGLE_TO_ARGUMENT(_arg_) ((USHORT)((((_arg_) + 2.0 * 3.14159265) / (4.0 * 3.14159265)) * 65535.0))
#define GID_ROTATE_ANGLE_FROM_ARGUMENT(_arg_) ((((double)(_arg_) / 65535.0) * 4.0 * 3.14159265) - 2.0 * 3.14159265)

/*
* Gesture information retrieval
* - HGESTUREINFO is received by a window in the lParam of a WM_GESTURE message.
*/
WINUSERAPI
BOOL
WINAPI
GetGestureInfo(
__in HGESTUREINFO hGestureInfo,
__out PGESTUREINFO pGestureInfo);

/*
* Gesture extra arguments retrieval
* - HGESTUREINFO is received by a window in the lParam of a WM_GESTURE message.
* - Size, in bytes, of the extra argument data is available in the cbExtraArgs
* field of the GESTUREINFO structure retrieved using the GetGestureInfo function.
*/
WINUSERAPI
BOOL
WINAPI
GetGestureExtraArgs(
__in HGESTUREINFO hGestureInfo,
__in UINT cbExtraArgs,
__out_bcount(cbExtraArgs) PBYTE pExtraArgs);

/*
* Gesture information handle management
* - If an application processes the WM_GESTURE message, then once it is done
* with the associated HGESTUREINFO, the application is responsible for
* closing the handle using this function. Failure to do so may result in
* process memory leaks.
* - If the message is instead passed to DefWindowProc, or is forwarded using
* one of the PostMessage or SendMessage class of API functions, the handle
* is transfered with the message and need not be closed by the application.
*/
WINUSERAPI
BOOL
WINAPI
CloseGestureInfoHandle(
__in HGESTUREINFO hGestureInfo);


/*
* Gesture configuration structure
* - Used in SetGestureConfig and GetGestureConfig
* - Note that any setting not included in either GESTURECONFIG.dwWant or
* GESTURECONFIG.dwBlock will use the parent window's preferences or
* system defaults.
*/
typedef struct tagGESTURECONFIG {
DWORD dwID; // gesture ID
DWORD dwWant; // settings related to gesture ID that are to be turned on
DWORD dwBlock; // settings related to gesture ID that are to be turned off
} GESTURECONFIG, *PGESTURECONFIG;

/*
* Gesture configuration flags - GESTURECONFIG.dwWant or GESTURECONFIG.dwBlock
*/

/*
* Common gesture configuration flags - set GESTURECONFIG.dwID to zero
*/
#define GC_ALLGESTURES 0x00000001

/*
* Zoom gesture configuration flags - set GESTURECONFIG.dwID to GID_ZOOM
*/
#define GC_ZOOM 0x00000001

/*
* Pan gesture configuration flags - set GESTURECONFIG.dwID to GID_PAN
*/
#define GC_PAN 0x00000001
#define GC_PAN_WITH_SINGLE_FINGER_VERTICALLY 0x00000002
#define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 0x00000004
#define GC_PAN_WITH_GUTTER 0x00000008
#define GC_PAN_WITH_INERTIA 0x00000010

/*
* Rotate gesture configuration flags - set GESTURECONFIG.dwID to GID_ROTATE
*/
#define GC_ROTATE 0x00000001

/*
* Two finger tap gesture configuration flags - set GESTURECONFIG.dwID to GID_TWOFINGERTAP
*/
#define GC_TWOFINGERTAP 0x00000001

/*
* PressAndTap gesture configuration flags - set GESTURECONFIG.dwID to GID_PRESSANDTAP
*/
#define GC_PRESSANDTAP 0x00000001
#define GC_ROLLOVER GC_PRESSANDTAP

#define GESTURECONFIGMAXCOUNT 256 // Maximum number of gestures that can be included
// in a single call to SetGestureConfig / GetGestureConfig

WINUSERAPI
BOOL
WINAPI
SetGestureConfig(
__in HWND hwnd, // window for which configuration is specified
__in DWORD dwReserved, // reserved, must be 0
__in UINT cIDs, // count of GESTURECONFIG structures
__in_ecount(cIDs) PGESTURECONFIG pGestureConfig, // array of GESTURECONFIG structures, dwIDs will be processed in the
// order specified and repeated occurances will overwrite previous ones
__in UINT cbSize); // sizeof(GESTURECONFIG)


#define GCF_INCLUDE_ANCESTORS 0x00000001 // If specified, GetGestureConfig returns consolidated configuration
// for the specified window and it's parent window chain

WINUSERAPI
BOOL
WINAPI
GetGestureConfig(
__in HWND hwnd, // window for which configuration is required
__in DWORD dwReserved, // reserved, must be 0
__in DWORD dwFlags, // see GCF_* flags
__in PUINT pcIDs, // *pcIDs contains the size, in number of GESTURECONFIG structures,
// of the buffer pointed to by pGestureConfig
__inout_ecount(*pcIDs) PGESTURECONFIG pGestureConfig,
// pointer to buffer to receive the returned array of GESTURECONFIG structures
__in UINT cbSize); // sizeof(GESTURECONFIG)

2009/04/27

關於視窗的一點心得


/// how to capture window @ mouse?
// capture the window under the cursor's position
IntPtr hWnd = Win32.WindowFromPoint(Cursor.Position);
// handle
_textBoxHandle.Text = string.Format("{0}", hWnd.ToInt32().ToString());

// class
_textBoxClass.Text = this.GetClassName(hWnd);

// caption
_textBoxText.Text = this.GetWindowText(hWnd);

Win32.Rect rc = new Win32.Rect();
Win32.GetWindowRect(hWnd, ref rc);

// rect
_textBoxRect.Text = string.Format("[{0} x {1}], ({2},{3})-({4},{5})", rc.right - rc.left, rc.bottom - rc.top, rc.left, rc.top, rc.right, rc.bottom);

/// 自己的 Root Form Handler
if (hWnd == IntPtr.Zero)
{
}

/// 如何抓 window image?

// capture that window
Image image = ScreenCapturing.GetWindowCaptureAsBitmap(handle);

// fire our image read event, which the main window will display for us
this.OnImageReadyForDisplay(image);

/// 如何等候 Image 已經畫好再做事?

public event DisplayImageEventHandler ImageReadyForDisplay;
ImageReadyForDisplay += new DisplayImageEventHandler(this.DisplayImage);
if (ImageReadyForDisplay != null)
ImageReadyForDisplay(image, false, PictureBoxSizeMode.CenterImage);

/// 如何抓例外
try
{
if (this.ImageReadyForDisplay != null)
this.ImageReadyForDisplay(image, false, PictureBoxSizeMode.CenterImage);
}
catch(Exception ex)
{
Debug.WriteLine(ex);
}

public class WindowHighlighter
{
public static void Highlight(IntPtr hWnd)
{
const float penWidth = 3;
Win32.Rect rc = new Win32.Rect();
Win32.GetWindowRect(hWnd, ref rc);

IntPtr hDC = Win32.GetWindowDC(hWnd);
if (hDC != IntPtr.Zero)
{
using (Pen pen = new Pen(Color.Black, penWidth))
{
using (Graphics g = Graphics.FromHdc(hDC))
{
g.DrawRectangle(pen, 0, 0, rc.right - rc.left - (int)penWidth, rc.bottom - rc.top - (int)penWidth);
}
}
}
Win32.ReleaseDC(hWnd, hDC);
}

public static void Refresh(IntPtr hWnd)
{
Win32.InvalidateRect(hWnd, IntPtr.Zero, 1);
Win32.UpdateWindow(hWnd);
Win32.RedrawWindow(hWnd, IntPtr.Zero, IntPtr.Zero, Win32.RDW_FRAME | Win32.RDW_INVALIDATE | Win32.RDW_UPDATENOW | Win32.RDW_ALLCHILDREN);
}
}

2009/04/23

timer 與 while(1)

連續貼三篇文章,有的寫的很簡單卻搞到很頭痛,還有一個最頭痛的沒貼上來,等整理心得出來後再來與大家分享。這邊講一個被 M$ 氣的半死的一項。

想當然爾,timer() 的單位的 ms, 所以若設定 1ms 與 10ms, 被呼叫的頻率差應該是 10 倍吧?答案是....No!!! 究竟是多少?網路上有人在問要怎樣設定 timer 到微秒的等級,嗚呼哀哉。目前我們測試的 timer 最快也就 60HZ 而已。

因為 timer() 無法達到預期目標,那麼就用 while(1), 又怕吃掉系統資源,以前知道要用 usleep(), 不要說這會讓系統負擔變重,事實上是我們找不到!,後來大膽測試 while(1), 結果卻發現頻率夠高,而且而且,系統負擔竟然出奇的輕!偉哉,M$!

這邊要提醒的是,我說 while(1) 不會造成系統負擔過重的原因不是 OS 排程做的好,而是 while() 裡面做的是 device IO。至於如何調整 sleep() 的時間單位?答案有機會再揭曉

Visual Studio 中的記憶體管理

這篇也是同事的心得,因為程式一開始沒有作記憶體釋放動作,因而造成整個系統資源被吃光,希望不要再有人犯同樣錯誤。畢竟保持環境清潔人人有責。

C++中有new 和 gcnew(garbage collection new)(C#裡面的new 其實就是gcnew)

原則上managed的物件都只能用gcnew去創造

而unmanaged則是用new

這兩個東西的差別是需不需要主動去做garbage collection(delete的動作)

在managed的程式中

隔一段時間,GC會去判斷目前的記憶體空間是否沒有reference

沒有的話就會釋放出來

也可以採用GC::Collect()去做這件事(不需要特別再對每個ref做delete,delete沒有實際效果)

new的話就需要自己在確定沒有使用的時候去把他delete掉

另外還有一類,使用global的函式所給出的handle(比如canvas裡用的CreatePen)

不知道為什麼,他不會計算到程式的記憶體使用量裡面(一直create不會發現程式記憶體用輛增加)

但是因為沒有清掉,所以還是會在使用過多的時候發生問題(程式crash)

所以得要去做DeleteObject的動作

怎樣讓程式不會重複被執行

最近我只在 M$ 平台上混,真的被氣死了。話不多說,來說一個怎樣讓程式不會重複被叫起來的方法,這是同仁的心得,我代貼而已。

主要使用到CreateMutex()函數和GetLastError()以及一個常量
ERROR_ALREADY_EXISTS.

下面為sample code:

HANDLE hMutex = CreateMutex(NULL, false, "Process");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(hMutex);
MessageBox(Application->Handle, "程序已經執行中,不能重覆啟動!", "提示",
MB_OK);

return 0;
}

參考網頁 : http://hi.baidu.com/machh03/blog/item/52c0cc3864fd5b2697ddd815.html

2009/03/30

resource:///

繼上次談Fennec之後, 發現 Firefox 竟然支援 resource:/// 這種 url. 當時在玩 Fennec 的那十分鐘裡,找不到設定畫面,我就是透過 about:config 來做設定 proxy 的,而 resource:/// 可以快速開啟 Local File,尤其是安裝 Firefox 的目錄下。

不過....據說目前還有漏洞....

2009/03/27

嵌入式瀏覽器又多一椿 Fennec/Firefox

可以說,Fennec 是 Firefox 的兒子!
懶得貼太多東西,請見下列網址,感覺非常棒,雖然要稱之為嵌入式恐怕還太早,但是非常棒!有機會可以跟 Ubuntu 的 Netbook(Remix)比比看。

先讀讀 http://shiuan-pc.blogspot.com/2008/10/fennecmozilla.html
裡頭會講到 windows 上也可以跑,網址: http://ftp.mozilla.org/pub/mozilla.org/mobile/fennec-1.0a1.en-US.win32.zip
https://wiki.mozilla.org/Mobile/FennecVision
http://www.mozilla.org/projects/fennec/1.0a1/releasenotes/

2009/02/22

把二進位內容放進 shell script

貼過一篇 把文字檔放進 C 執行檔中。記得曾貼過類似下面的文章將二進位內容放進 shell 中,有興趣的人請看舊作建立自解壓檔一文,現在再來貼一次作法類似的文章。

分兩個檔,一個叫 addpayload.sh, 一個叫 install.sh.in, 前者如下:


#!/bin/bash

# Check for payload format option (default is uuencode).
uuencode=1
if [[ "$1" == '--binary' ]]; then
binary=1
uuencode=0
shift
fi
if [[ "$1" == '--uuencode' ]]; then
binary=0
uuencode=1
shift
fi

if [[ ! "$1" ]]; then
echo "Usage: $0 [--binary | --uuencode] PAYLOAD_FILE"
exit 1
fi


if [[ $binary -ne 0 ]]; then
# Append binary data.
sed \
-e 's/uuencode=./uuencode=0/' \
-e 's/binary=./binary=1/' \
install.sh.in >install.sh
echo "PAYLOAD:" >> install.sh

cat $1 >>install.sh
fi
if [[ $uuencode -ne 0 ]]; then
# Append uuencoded data.
sed \
-e 's/uuencode=./uuencode=1/' \
-e 's/binary=./binary=0/' \
install.sh.in >install.sh
echo "PAYLOAD:" >> install.sh

cat $1 | uuencode - >> install.sh
fi


install.sh.in 是個樣本檔,template file, 最後會產生 install.sh 才是加了二進位內容的 shell script....原文有執行例,請自行前往觀看怎麼執行。


#!/bin/bash

uuencode=1
binary=0

function untar_payload()
{
match=$(grep --text --line-number '^PAYLOAD:$' $0 | cut -d ':' -f 1)
payload_start=$((match + 1))
if [[ $binary -ne 0 ]]; then
tail -n +$payload_start $0 | tar -tzvf -
fi
if [[ $uuencode -ne 0 ]]; then
tail -n +$payload_start $0 | uudecode | tar -tzvf -
fi
}

read -p "Install files? " ans
if [[ "${ans:0:1}" || "${ans:0:1}" ]]; then
untar_payload
# Do remainder of install steps.
fi

exit 0

2009/02/09

QEMU 與 VirtualBox 的影像檔互換

QEMU img to VirtualBox vdi
代碼:
VBoxManage convertdd qemu.img qemu.vdi

或是
代碼:
./vditool DD qemu.vdi qemu.img


VirtualBox vdi to QEMU img
代碼:
./vditool COPYDD virtualbox.vdi virtualbox.img

initrd 機制

這篇文章是因為他寫的好,有在看我的文章的會比較容易找到。

cpio-initrd 的處理流程

1. boot loader 把內核以及 initrd 文件加載到內存的特定位置。

2. 內核判斷initrd的文件格式,如果是cpio格式。

3. 將initrd的內容釋放到rootfs中。

4. 執行initrd中的/init文件,執行到這一點,內核的工作全部結束,完全交給/init文件處理。

image-initrd的處理流程

1. boot loader把內核以及initrd文件加載到內存的特定位置。

2. 內核判斷initrd的文件格式,如果不是cpio格式,將其作為image-initrd處理。

3. 內核將initrd的內容保存在rootfs下的/initrd.image文件中。

4. 內核將/initrd.image的內容讀入/dev/ram0設備中,也就是讀入了一個內存盤中。

5. 接著內核以可讀寫的方式把/dev/ram0設備掛載為原始的根文件系統。

6. .如果/dev/ram0被指定為真正的根文件系統,那麼內核跳至最後一步正常啟動。

7. 執行initrd上的/linuxrc文件,linuxrc通常是一個腳本文件,負責加載內核訪問根文件系統必須的驅動, 以及加載根文件系統。

8. /linuxrc執行完畢,常規根文件系統被掛載

9. 如果常規根文件系統存在/initrd目錄,那麼/dev/ram0將從/移動到/initrd。否則如果/initrd目錄不存在, /dev/ram0將被卸載。

10. 在常規根文件系統上進行正常啟動過程 ,執行/sbin/init。

cpio-initrd的製作方法更加簡單

cpio-initrd的製作非常簡單,通過兩個命令就可以完成整個製作過程

#假設當前目錄位於準備好的initrd文件系統的根目錄下
bash# find . | cpio -c -o > ../initrd.img
bash# gzip ../initrd.img


傳統initrd的製作過程比較繁瑣,需要如下六個步驟

#假設當前目錄位於準備好的initrd文件系統的根目錄下
bash# dd if=/dev/zero of=../initrd.img bs=512k count=5
bash# mkfs.ext2 -F -m0 ../initrd.img
bash# mount -t ext2 -o loop ../initrd.img /mnt
bash# cp -r * /mnt
bash# umount /mnt
bash# gzip -9 ../initrd.img

2009/01/14

Multi-Touch & Gesture support on 最新的 VS 2008/.NET framework 3.5

==== Gesture ====

InkEdit.Gesture Event (Microsoft.Ink)
Basic C# Visual C++ J# JScript .NET Framework Class Library InkEdit..::.Gesture Event InkEdit Class Example See Also Send Feedback Updated: November 2007 Occurs when an application gesture is recognized. Namespace: Microsoft.Ink Assembly: Microsoft.Ink (in Microsoft.Ink.dll ...
Source: microsoft.ink

InkOverlay.Gesture Event (Microsoft.Ink)
Basic C# Visual C++ J# JScript .NET Framework Class Library InkOverlay..::.Gesture Event InkOverlay Class Example See Also Send Feedback Updated: November 2007 Occurs when an application gesture is recognized. Namespace: Microsoft.Ink Assembly: Microsoft.Ink (in Microsoft.Ink.dll ...
Source: microsoft.ink

InkCollector.Gesture Event (Microsoft.Ink)
Basic C# Visual C++ J# JScript .NET Framework Class Library InkCollector..::.Gesture Event InkCollector Class Example See Also Send Feedback Updated: November 2007 Occurs when an application gesture is recognized. Namespace: Microsoft.Ink Assembly: Microsoft.Ink (in Microsoft.Ink.dll ...
Source: microsoft.ink

InkPicture.Gesture Event (Microsoft.Ink)
Basic C# Visual C++ J# JScript .NET Framework Class Library InkPicture..::.Gesture Event InkPicture Class Example See Also Send Feedback Updated: November 2007 Occurs when an application gesture is recognized. Namespace: Microsoft.Ink Assembly: Microsoft.Ink (in Microsoft.Ink.dll ...
Source: microsoft.ink

Gesture Event Event (Windows)
InkEdit.Gesture Event Occurs when an application gesture is recognized. Syntax HRESULT Gesture( [in] IInkCursor *Cursor, [in] IInkStrokes *Strokes, [in] VARIANT Gestures, [in, out] VARIANT ...
Source: TabletandTouch

InputBinding.Gesture Property (System.Windows.Input)
Visual C++ J# JScript .NET Framework Class Library InputBinding..::.Gesture Property InputBinding Class Example See Also Send Feedback Updated: November ... com/winfx/xaml/presentationSyntaxVisual Basic (Declaration) Public Overridable Property Gesture As InputGestureVisual Basic (Usage) Dim instance As InputBinding Dim value ...
Source: System.Windows.Input

Gesture Class (Microsoft.Ink)
Basic C# Visual C++ J# JScript .NET Framework Class Library Gesture Class Members See Also Send Feedback Updated: November 2007 Represents the ability to query particular properties of a gesture returned from a gesture recognition. Namespace: Microsoft.Ink Assembly: Microsoft ...
Source: microsoft.ink

MouseBinding.Gesture Property (System.Windows.Input)
Basic C# Visual C++ J# JScript .NET Framework Class Library MouseBinding..::.Gesture Property MouseBinding Class Example See Also Send Feedback Updated: November 2007 Gets or sets the gesture associated with this MouseBinding. Namespace: System.Windows.Input Assembly: PresentationCore (in PresentationCore ...
Source: System.Windows.Input

Gesture Event Event (Windows)
InkCollector.Gesture Event Occurs when an application-specific gesture is recognized. Syntax void Gesture( [in] IInkCursor *Cursor, [in] IInkStrokes *Strokes, [in] VARIANT Gestures, [in, out ...
Source: TabletandTouch

Gesture Event Event (Windows)
InkOverlay.Gesture Event Occurs when an application-specific gesture is recognized. Syntax void Gesture( [in] IInkCursor *Cursor, [in] IInkStrokes *Strokes, [in] VARIANT Gestures, [in, out ...
Source: TabletandTouch

Gesture Event Event (Windows)
InkPicture.Gesture Event Occurs when an application-specific gesture is recognized. Syntax void Gesture( [in] IInkCursor *Cursor, [in] IInkStrokes *Strokes, [in] VARIANT Gestures, [in, out ...
Source: TabletandTouch

KeyBinding.Gesture Property (System.Windows.Input)
Basic C# Visual C++ J# JScript .NET Framework Class Library KeyBinding..::.Gesture Property KeyBinding Class Example See Also Send Feedback Updated: November 2007 Gets or sets the gesture associated with this KeyBinding. Namespace: System.Windows.Input Assembly: PresentationCore (in PresentationCore ...
Source: System.Windows.Input

InkCanvas.Gesture Event (System.Windows.Controls)
C# Visual C++ J# JScript .NET Framework Class Library InkCanvas..::.Gesture Event InkCanvas Class Example See Also Send Feedback Updated: November 2007 Occurs when the InkCanvas detects a gesture. Namespace: System.Windows.Controls Assembly: PresentationFramework (in PresentationFramework.dll) XMLNS for ...
Source: System.Windows.Controls

Gesture Members (Microsoft.Ink)
Members Include .NET Framework Members Include .NET Compact Framework Members Include XNA Framework Members .NET Framework Class Library Gesture Members Gesture Class Methods Properties See Also Send Feedback Updated: November 2007 Represents the ability to query particular properties of a ...
Source: microsoft.ink

Using the Microsoft Gesture Recognizer Only (Windows)
Using the Microsoft Gesture Recognizer Only You can use an ink collector (InkCollector, InkOverlay, or InkPicture) to access the default Microsoft gesture recognizer directly. To use an ink collector to access the gesture ...
Source: TabletandTouch

Gesture Properties (Microsoft.Ink)
Members Include .NET Framework Members Include .NET Compact Framework Members Include XNA Framework Members .NET Framework Class Library Gesture Properties Gesture Class See Also Send Feedback Updated: November 2007 The Gesture type exposes the following members.Properties NameDescriptionConfidenceGets the level ...
Source: microsoft.ink

Using a Custom Gesture Recognizer (Windows)
Using a Custom Gesture Recognizer You can use a custom gesture recognizer independently, or in addition to the GestureRecognizer. Create your custom gesture recognizer as an IStylusSyncPlugin ...
Source: TabletandTouch

Gesture Methods (Microsoft.Ink)
Members Include .NET Framework Members Include .NET Compact Framework Members Include XNA Framework Members .NET Framework Class Library Gesture Methods Gesture Class See Also Send Feedback Updated: November 2007 The Gesture type exposes the following members.Methods NameDescriptionEquals Determines whether ...
Source: microsoft.ink

Application Gestures and Semantic Behavior (Windows)
Windows Vista SDK. The Microsoft gesture recognizer is built to recognize these gestures. By default, no gestures are enabled. Applications must choose the gestures to enable. In addition to recognizing gestures, the Microsoft gesture recognizer also provides alternates along with ...
Source: TabletandTouch

InkApplicationGesture Enumeration (Windows)
set the interest in a set of application-specific gesture. Application gestures are gestures that you can choose to have ... enumeration type). This means you can incorporate an application gesture that has a component that may be construed as a ...
Source: TabletandTouch


=========================================================================
Multi Touch
=========================================================================

Intuitive User Experience (Windows)
time, Windows 7 allows developers and their end-users to control their computers by touching the screen. Touch and multi-touch features provide a natural, intuitive way for users to interact with PCs. The developer platform includes high-level gesture ...
Source: Windows7DeveloperGuide

Supporting Pen and Touch Input (Windows)
Supporting Pen and Touch Input Tablet PC users rely on pen and touch input as primary methods of controlling applications and entering information. This section discusses the use ...
Source: MobilPC

Pen and Touch Input in Windows Vista (Windows)
Pen and Touch Input in Windows Vista Windows Vista introduces touch input capability for Tablet PCs that support it, a new cursor scheme to use with the ...
Source: MobilPC

Designing for Touch Input (Windows)
Designing for Touch Input If your users will use touch as a primary way of interacting with your application, consider implementing a user interface that's ...
Source: MobilPC

Touch Input Support in Windows Vista (Windows)
Touch Input Support in Windows Vista Starting with Windows Vista, Tablet and Touch Technology has support for touch input on Tablet PC's with touch capable digitizers ...
Source: TabletandTouch

Touch Members (Microsoft.Build.Tasks)
Members Include .NET Framework Members Include .NET Compact Framework Members Include XNA Framework Members .NET Framework Class Library Touch Members Touch Class Constructors Methods Properties See Also Send Feedback Updated: November 2007 This API supports the .NET Framework infrastructure and ...
Source: microsoft.build.tasks

Touch Class (Microsoft.Build.Tasks)
NET Framework Class Library Touch Class Members See Also Send Feedback Updated: November 2007 This API supports the .NET Framework infrastructure and is not intended to be used directly from your code. Implements the Touch task. Use the Touch element ...
Source: microsoft.build.tasks

Touch Constructor (Microsoft.Build.Tasks)
Code: Visual C++ Code: J# Code: JScript Visual Basic C# Visual C++ J# JScript .NET Framework Class Library Touch Constructor Touch Class See Also Send Feedback Updated: November 2007 This API supports the .NET Framework infrastructure and is not intended ...
Source: microsoft.build.tasks

No Touch Deployment (Windows)
No Touch Deployment Implementation of no-touch deployment of ink-enabled applications from a Web or file server. The Microsoft?.NET Framework gives you ...
Source: TabletandTouch

Optimizing Touch Command and Control (Windows)
Optimizing Touch Command and Control A well-designed Ultra-Mobile PC user interface provides users simple, direct and reliable touch interaction. Design and organize touch targets, such as buttons and links ...
Source: MobilPC

No-Touch Deployment Web Sample (Windows)
No-Touch Deployment Web Sample Description of the No-Touch Deployment sample for the Tablet PC. This sample shows how to deploy a managed Tablet PC ...
Source: TabletandTouch

Touch Task
J# JScript .NET Framework General Reference Touch Task Example See Also Send Feedback Updated: November 2007 Sets the access and modification times of files. Parameters The following table describes the parameters of the Touch task. Parameter Description AlwaysCreate Optional Boolean ...
Source: .NET Framework: General Reference

Touch Properties (Microsoft.Build.Tasks)
Members Include .NET Framework Members Include .NET Compact Framework Members Include XNA Framework Members .NET Framework Class Library Touch Properties Touch Class See Also Send Feedback Updated: November 2007 This API supports the .NET Framework infrastructure and is not intended ...
Source: microsoft.build.tasks

Touch Methods (Microsoft.Build.Tasks)
Members Include .NET Framework Members Include .NET Compact Framework Members Include XNA Framework Members .NET Framework Class Library Touch Methods Touch Class See Also Send Feedback Updated: November 2007 This API supports the .NET Framework infrastructure and is not intended ...
Source: microsoft.build.tasks