출처: http://www.mozilla.org/projects/plugins/bi-directional-plugin-scripting.html

Bi-directional Plugin Scripting

Patrick C. Beard <beard@netscape.com>


July 26, 2002

Introduction
Background
Sample Code

Introduction

Mozilla has supported plugin scripting since the 0.9.4 milestone, and has been documented by a previous article. However, that article only discusses how to make a plugin callable from JavaScript. This article will show how to call JavaScript from a plugin.

Background

The traditional plugin API already provides a mechanism by which a plugin instance can call into JavaScript and access information from the embedding web page. A plugin instance can simply call NPN_GetURL() passing in a "javascript:" URL. Here's a simple example:

	NPN_GetURL(instance, "javascript:alert('hello world.')", NULL);

This simply tells JavaScript to display an alert window with the message "hello world." However, this happens asynchronously, i.e. the alert doesn't come up until some time after the call has been issued. This makes showing alert rather inconvenient to use as a debugging tool. In addition, what if what we really want to do is read some value, rather than display a message?

If we are willing to wait for the result to come at some later time, then we have a couple of options. One is to use NPN_GetURLNotify() instead, which will call the plugin back with the result of evaluating the JavaScript URL. Alternatively, since you are presumably writing a scriptable plugin, we can deliver the results to the scriptable plugin through one of its methods. For the sake of exposition, let's define a hypothetical scriptable plugin interface:

	interface acmeScriptablePlugin : nsISupports {
		attribute string location;
	}

This interface defines an attribute, location, which can be both read and written from script. If the plugin is instantiated on a web page, all by itself, then a simple script that reads and writes this attribute would look like this:

	<SCRIPT>
	var plugin = document.embeds[0];
	plugin.location = document.location;     // tell the plugin the URL of this document.
	alert('location  = ' + plugin.location); // read back the document's location
	</SCRIPT>

This is an example of a script calling into a plugin's scriptable interface. Things get more interesting if we define an attribute with a more complex value. Let's define an interface that represents a simple JavaScript object. It has properties which can be read and written:

	interface acmeJSObject : nsISupports {
		string getProperty(in string name);
		void setProperty(in string name, in string value);
	}

If we modify our plugin's scriptable interface to use this interface, we can provide a way for the plugin itself to read properties of the web page's document object:

	interface acmeScriptablePlugin : nsISupports {
		attribute acmeJSObject document;
	}

Here's JavaScript code that would write to the document attribute:

	<SCRIPT>
	var plugin = document.embeds[0];
	var docWrapper = {
		doc : document,
		getProperty : function(name) { return this.doc[name]; }
		setPropety : function(name, value) { this.doc[name] = value; }
	};
	plugin.document = docWrapper; // give plugin wrapper to this document.
	</SCRIPT>

Finally, here's some C++ code reads document.location:

	nsIMemory* allocator = GetMemoryAllocator();
	acmeJSObject* document = GetJSDocument();
	char* location;
	if (NS_SUCCEEDED(document->GetProperty("location", &location))) {
		printf("location = %s\n", location);
		allocator->Free(location);
	}

How does all of this work? The Mozilla browser contains a bridging layer which wraps JavaScript objects in C++ objects that implement XPCOM interfaces. All that a script object has to do to implement an XPCOM interface is to define function properties that correspond to the IDL declaration of that interface.

Sample Code

Here's a more fully fleshed out example. Here's an interface that will be implemented by JavaScript code that the plugin injects into a web page:

/*
  acmeIScriptObject.idl
 */

#include "nsISupports.idl"

[scriptable, uuid(f78d64e0-1dd1-11b2-a9b4-ae998c529d3e)]
interface acmeIScriptObject : nsISupports {
	acmeIScriptObject getProperty(in string name);
	void setProperty(in string name, in acmeIScriptObject value);

	/**
	 * Conversions.
	 */
	string toString();
	double toNumber();

	/**
	 * Constructors.
	 */
	acmeIScriptObject fromString(in string value);
	acmeIScriptObject fromNumber(in double value);

	acmeIScriptObject call(in string name, in PRUint32 count,
				[array, size_is(count)] in acmeIScriptObject argArray);
};

Here's a JavaScript implementation of acmeIScriptObject:

	function jsScriptObject(obj)
	{
		// implementation detail, to allow unwrapping.
		this.wrappedJSObject = obj;
	}

	jsScriptObject.prototype = {
		QueryInterface : function(iid)
		{
			try {
				if (iid.equals(Components.interfaces.acmeIScriptObject) ||
				iid.equals(Components.interfaces.nsIClassInfo) ||
				iid.equals(Components.interfaces.nsISecurityCheckedComponent) ||
				iid.equals(Components.interfaces.nsISupports)) {
					alert("QI good.");
					return this;
				}
				throw Components.results.NS_ERROR_NO_INTERFACE;
			} catch (se) {
				// older browsers don't let us use iid.equals, wah.
				return this;
			}
		}

		// acmeIScriptObject implementation.
		getProperty : function(name)
		{
			return new jsScriptObject(this.wrappedJSObject[name]);
		}

		setProperty : function(name, value)
		{
			alert('setProperty:  name = ' + name + ', value = ' + value.toString() + '\n');
			this.wrappedJSObject[name] = value.toString();
		}

		toString : function()
		{
			return this.wrappedJSObject.toString();
		}

		toNumber : function()
		{
			return this.wrappedJSObject.valueOf();
		}

		fromString : function(value)
		{
			return new jsScriptObject(value);
		}

		fromNumber : function(value)
		{
			return new jsScriptObject(value);
		}

		call : function(name, argArray)
		{
			// TBD
		}
	};

Finally, here's some C++ code that uses the acmeIScriptObject interface:

NS_IMETHODIMP nsScriptablePeer::SetWindow(acmeIScriptObject *window)
{
  NS_IF_ADDREF(window);
  NS_IF_RELEASE(mWindow);
  mWindow = window;

  acmeIScriptObject* location = nsnull;
  nsresult rv = window->GetProperty("location", &location);
  if (NS_SUCCEEDED(rv) && location) {
    char* locationStr = NULL;
    rv = location->ToString(&locationStr);
    if (NS_SUCCEEDED(rv) && locationStr) {
      NPN_MemFree(locationStr);
    }
    NS_RELEASE(location);
  }
  
  acmeIScriptObject* newLocation = nsnull;
  rv = window->FromString("http://www.mozilla.org", &newLocation);
  if (NS_SUCCEEDED(rv) && newLocation) {
    window->SetProperty("location", newLocation);
    NS_RELEASE(newLocation);
  }
   
  return NS_OK;
}

AND

출처: http://xulfr.org/forums/read.php?5,9541

[résolu]plantage notification

Ecrit par : xulien

Date : le 22/08/2007 à 15h01

Salut, je développe un client riche en Xul. Celui-ci est notifié par un serveur distant du changement de certaines valeurs. Pour cela j'ai un mini serveur soap (XPCOM) dans mon client riche qui écoute les notifications de mon serveur distant. Depuis le code javascript je fournis une fonction à l'XPCOM pour être notifié mais lors de l'appel à cette fonction ca plante je ne comprends pas ! Pourriez vous y jeter un oeil ou si vous avez une autre solution...

code javascript

var listener = 
{
 onNotify: function()
 {
   alert("notify");
 }
};

myXPCOM = Components.classes[[CID].createInstance(Components.interfaces.IClient);
voibResult = myXPCOM.init(listener);
 

idl

[[scriptable, uuid(...)]
interface JSCallback : nsISupports 
{
 void onNotify();
};

[[scriptable, uuid(...)]
interface IServerXpcom : nsISupports
{
 boolean init(in JSCallback aCallback)
}
 

code C++ - .h

class ServerXpcom : public IServerXpcom
{
public:
 NS_DECL_ISUPPORTS
 NS_DECL_ISIMSCLIENT

 ServerXpcom();
 // Méthode appelée lorsque le serveur distant notifie
 void vCallNotify();

private:
 ~ServerXpcom();

protected:
 // fonction de callback des notifications 
 nsCOMPtr<JSCallback> js_callback;
}
 

.cpp

NS_IMETHODIMP ServerXpcom::Init(JSCallback *aCallback, PRBool *_retval)
{
 js_callback = aCallback;

 // par exemple si j'appels notify ici ca fonctionne
 js_callback->onNotify();
  
 return NS_OK;
 

}

void ServerXpcom::vCallNotify()
{
 // Si en revanche je l'appels ici ca plante
 js_callback->onNotify();
};
 

Seuls les utilisateurs enregistrés peuvent écrire dans ce forum.

AND

출처: http://blog.xiaoduo.info/?p=38

Sometimes we need to call javascript function form a c++ xpcom. The following is a method for this.

1. Define your javascript callback interface in a IDL file.

  1. interface JSCallback : nsISupports {
  2.     boolean call(in PRUint32 aData);
  3. }

And another interface looks like:

  1. interface TestJSCallback : nsISupports {
  2.     void sum(in PRUint32 first, in PRUint32 second, in JSCallBack aCallback);
  3. }

2. Complete the sum function’s cpp code.

  1. NS_IMETHODIMP TestJSCallback::Sum(PRUint32 first, PRUint32 second, JSCallback *aCallback) {
  2.     PRBool ret = TRUE;
  3.     nsCOMPtr<JSCallback> js_callback = aCallback;
  4.     js_callback->Call(first+second, &ret);
  5. }

3. Interface call.

  1. var test = function(sum) {
  2.     alert(sum);
  3. };
  4. var com = Components.classes["XXXXXX"].getService(Components.interfaces.TestJSCallback);
  5. com.sum(1, 2, test);

It will pop up a dialog shows “3″ … Cheers…

9 Responses to “XPCOM: Javascript function call”

  1. John SWITZERLAND Linux Mozilla Firefox 2.0.0.4 Says:

    thanks for the tip, that’s really smart. I’m now able to trig a js function from my c++ xpcom component. The only bug is that the parameter given to the callback are not correctly handled, ie they appears as ‘undefined’ in the js function. Any idea?

  2. Santa UNITED STATES Windows XP Internet Explorer 7.0 Says:

    Do you have all the code?

  3. kid.duo CHINA Mac OS X Mozilla Firefox 2.0.0.12 Says:

    You can check out the Firetray’s source code from google code.
    Or browse it online via http://code.google.com/p/firetray/source/browse

  4. Santa UNITED STATES Windows XP Internet Explorer 7.0 Says:

    The information all works upto the point of calling JS with parameters.
    The parameter is coming out “undefined”.

    The info in this thread is great with that caveat. How to make it work?

  5. Santa UNITED STATES Windows XP Internet Explorer 7.0 Says:

    I got the solution to my own post. I’ll post it asap.

  6. Santa UNITED STATES Windows XP Internet Explorer 7.0 Says:

    You have to call from javascript to XPCOM once the callback is called. That is the only way I can think so far.

  7. Tur SPAIN Windows XP Mozilla Firefox 2.0.0.12 Says:

    Hi, nice article, but I am not able to pass the argument to the JavaScript callback.
    I just get an alert window saying “undefined”. Does anybody knows how to solve this issue?
    Santa, can you explain further your workaround? Do you mean store the data in a variable in XPCom component and then in the call back recover that info from JavaScript?

  8. Tur SPAIN Windows XP Mozilla Firefox 2.0.0.12 Says:

    Hey I ‘ve discovered something!!
    I was wondering why JSCallback interface should define a method named “call” and not any other name.
    I found that in JavaScript, if you define a function you create an object with a call() method!, so i decided to test this. In the JavaScript example above i called “test.call()”. After some more test I’ve discovered that test.call(0,3) makes an alert(3)!!.
    The last step was to do the same in the XPCom, so modify the idl for the callback:
    boolean call(in PRUint32 bogus, in PRUint32 aData);
    And the C++ code
    aCallback->Call(0, first+second, &ret);
    And I got it.
    Hope this helps any one.

    One final request. I don’t know how to use nsCOMPtr. Help linking (aditional libs) would be very appreciated.

  9. Santa UNITED STATES Windows XP Internet Explorer 7.0 Says:

    Do this:
    http://www.mail-archive.com/dev-tech-xpcom@lists.mozilla.org/msg00531.html
    if you want parameters.

AND

출처: http://groups.google.com/group/netscape.public.mozilla.xpcom/browse_thread/thread/e2ff8c3ffb6323b8/3d2b1991758d6c44

플래그
  2개의 메시지 - 모두 축소

메시지를 게시하실 그룹은 유즈넷 그룹입니다. 이 그룹에 메시지를 게시하시면 인터넷의 모든 사용자가 귀하의 이메일을 볼 수도 있습니다.
답장이 전송되지 않았습니다.
성공적으로 게시되었습니다.
mcbraz...@gmail.com  
프로필 보기
 추가 옵션 2007년9월1일, 오전6시12분
Hello,

I've written a scriptable firefox plugin that is able to receive
messages from JavaScript.  I now need to send messages from the plugin
to JS.  The only way I've found to do this is through the use of the
nsIObserverService using the following code:

    nsCOMPtr<nsIServiceManager> servMan;
    nsresult rv = NS_GetServiceManager(getter_AddRefs(servMan));
    nsCOMPtr<nsIObserverService> observerService;
    rv = servMan->GetServiceByContractID("@mozilla.org/observer-
service;1",

NS_GET_IID(nsIObserverService),

getter_AddRefs(observerService));

    observerService->NotifyObservers(NULL, "Topic", 0);

On the JS side, I will declare an observer that listens for "Topic".

First of all, is this the recommended way to communicate from the
plugin to JS?

Second, when I linked my plugin with xpcom.lib, it no longer gets
instantiated by firefox (I just get a blank window).  I checked the
dependencies on my plugin dll and they are all satisfied.

Any suggestions would be greatly appreciated.

Thanks!


메시지를 게시하려면 그룹에 가입해야 합니다.
메시지를 게시하려면 먼저 해당 그룹에 가입하셔야 합니다.
게시하기 전에 가입 설정 페이지에서 닉네임을 업데이트하십시오.
메시지를 게시할 수 있는 권한이 없습니다.
jenslsoren...@gmail.com  
프로필 보기
 추가 옵션 2007년9월30일, 오후1시37분
On Aug 31, 2:12 pm, mcbraz...@gmail.com wrote:

- 따온 텍스트 보기 -
You can use methods such as JS_CallFunctionName to call java script
from C/C++ if this is what you are looking for. You basically get a
hold of the JS Context and JS Object and then pass in the name of the
function you want to call + the arguments that you want to pass into
this function.
Here are some examples..

http://developer.mozilla.org/en/docs/JS_CallFunctionName

http://www.mozilla.org/js/spidermonkey/tutorial.html

-Jens

AND

출처: http://kr.blog.yahoo.com/certkr/6.html

모질라/파이어폭스 XPI 코드사이닝
2006/11/14 오 전 9:55 | ActiveX 코드사인 인증서

#####
 모질라/파이어폭스 XPI signing
#####


((( 준비작업 )))


A. 인증서 신청은
  Netscape Object Signing 인증서를 신청
 또는
  Microsoft Authenticode로 받은 인증서를 Netscape로 변환하여 사용

(일반적으로 사용가능한 Microsoft Authenticode 를 받는 편이 유리)


B. pvkimprt 를 통해 받은 spc , pvk 파일을 레지스트리로 import 시킨다.
pvkimprt 다운로드 : http://www.certkorea.co.kr/pds/pvkimprt.exe


   > pvkimprt -import nine4u.spc nine4u.pvk
   a. 비밀번호를 물어보는 창에서 개인키 비밀번호를 입력한다.
   b. 다음
   c. 인증서 종류 기준으로 인증서 저장소를 자동으로 선택 (default) 에 체크 -> 다음
   d. 마침.
   e. 이상으로 레지스트리에 인증서가 import 된다.
   확인: IE(브라우저) 에서 도구>인터넷옵션>내용>인증서 에서 개인탭을 보시면 발급대상에 추가된 인증서 확인가능


C. 인증서에 이름 부여
  a. IE 의 도구 > 인터넷 옵션 > 내용 > 인증서
  b. 인증서 선택
  c. 보기 > 자세히 > 속성편집
  d. 이름입력 후 확인 (예) nine4uCodeSign


D. pvkimprt 를 통해 pfx 파일로 export 시킨다.
   > pvkimprt -pfx nine4u.spc nine4u.pvk
   a. 비밀번호를 물어보는 창에서 개인키 비밀번호를 입력한다.
   b. 다음
   c. 예, 개인키를 내보냅니다. (default) 에 체크 -> 다음
   d. 가능하면 인증 경로에 있는 인증서 모두 포함 (체크)
      그외 체크 모두 없애고 다음
   e. 암호 , 암호확인 입력 후 다음
   f. 파일이름은 저장할 pfx 파일 이름을 입력합니다. (예: nine4u.pfx) 다음.
   g. 마침.


(참고) http://www.certkorea.co.kr/doc.asp?g_dev_conv




((( 코드사인 시작~~ )))

-------

다음은 윈도우 플랫폼에서 Firefox 플러그인 코드사인 방법입니다.

1. Mozilla FTP 사이트에서 최신의 Network Security Services (NSS) 패키지를 다운 받습니다. :
ftp://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/
윈도우 사용자는 NSS_3_9_RTM/WINNT5.0_OPT.OBJ/ 에서 nss-3.9.zip 을 받습니다.


2. 원하시는 곳에 압축을 풉니다. 예)  C:\Apps\nss-3.9\


3. Mozilla FTP 사이트에서 최신의 Netscape Portable Runtime 을 다운 받습니다. 
http://ftp.mozilla.org/pub/mozilla.org/nspr/releases/
윈도우 사용자는 v4.6/WINNT5.0_OPT.OBJ/ 에서 nspr-4.6.zip 을 받습니다.


4. 압축을 풉니다.  예) C:\Apps\nspr-4.6\


5.  NSS 의 bin , lib, nspr 의 lib 를 시스템 path 에 추가합니다.
   제어판 > 시스템 속성 > 고급 > 환경변수 > 시스템변수 에 추가하거나,
   또는 실행시 마다 설정 하실 수 있습니다.

   윈도우의 경우 몇몇 파일들 (예로, certutil.exe) 은 \widnows\system32\ 에 이미 포함되어 있으니,
   새로 추가된 파일들이 실행되도록 하기 위해 추가될 경로는 기존의 path 앞에 위치 시킵니다.

  설정 예)
          C:\> set PATH=C:\Apps\nss-3.9\bin\;C:\Apps\nss-3.9\lib\;C:\Apps\nspr-4.6\lib\;%PATH%


6. NSS 툴 문서 함 읽어 보시고~ (패스 )


7. 인증서 DB 초기화
  인증서 DB 파일을 위치시킬 폴더를 결정합니다. 다음 명령으로 DB 파일을 생성합니다. ( -d 옵션뒤에 . (마침표) 있음)


  Code:
       C:\Projects\CodeSigning\> certutil -N -d .
  => 현재디렉토리에 인증서 DB 파일을 새로 생성 한다.

  다음 내용과 같이 NSS Certificate database 의 password 를 물어 봅니다.
  (중요) 절대 잊어 버리면 안됩니다.
  뒤에도 비번이 나오는데 NSS 인증서 DB 비번과 , 인증서의 개인키 비번은 별개 입니다. 혼동주의!

   Code:
C:\Projects\CodeSigning\> certutil -N -d .
Enter a password which will be used to encrypt your keys.
The password should be at least 8 characters long,
and should contain at least one non-alphabetic character.

Enter new password:
Re-enter password:


이후 dir 해보시면
cert8.db , key3.db , secmod.db 파일 3개가 생성되어 있음을 확인 할 수 있습니다.


8. 위에서 준비한 pfx 파일을 NSS cert DB 에 import 시킵니다.

Code:
C:\Projects\CodeSigning> pk12util -i "nine4uCodeSign" -d .
Enter Password or Pin for "NSS Certificate DB":  <- 7번 단계에서 입력한 비밀번호
Enter password for PKCS12 file:                  <- 인증서 개인키 비밀번호
pk12util: PKCS12 IMPORT SUCCESSFUL
; nine4uCodeSign 은 위의 C 단계에서 지정한 인증서 이름입니다.


; 다음 명령으로 인증서가 추가된 것을 확인 하실 수 있습니다.
C:\Projects\CodeSigning> certutil -L -d .
nine4uCodeSign                                               u,u,u
Thawte Code Signing CA - Thawte Consulting cc                c,,c



9. 싸인을 위한 XPI 파일을 준비 합니다.

 새로운 폴더를 하나 생성하고 XPI 파일을 생성된 폴더에 카피 후 경로를 포함하여 압축을 풉니다.
 XPI 파일은 삭제하고 NSS DB 폴더로 돌아갑니다.

(주의) xpi zip 파일내의 파일 순서를 지켜줘야 합니다.
       첫번째 파일은 META-INF/zigbert.rsa 파일이 되어야 합니다.
       순서정렬이 가능한 zip 유틸을 사용하셔야 합니다.

Code:
C:\Projects\CodeSigning\> md signed

C:\Projects\CodeSigning\> copy C:\Projects\fsb\fsb.xpi signed
        1 file(s) copied.

C:\Projects\CodeSigning\> cd signed

C:\Projects\CodeSigning\signed> unzip fsb.xpi
Archive:  fsb.xpi
   creating: chrome/
  inflating: chrome.manifest
  inflating: chrome/fsb.jar
  inflating: install.rdf

C:\Projects\CodeSigning\signed> del fsb.xpi

C:\Projects\CodeSigning\signed> cd ..


10. 싸인 합니다.

Code:
C:\Projects\CodeSigning\> signtool -d . -k nine4uCodeSign -p "NSS패스워드" signed/
using certificate directory: .
Generating signed//META-INF/manifest.mf file..
--> chrome/fsb.jar
--> chrome.manifest
--> install.rdf
Generating zigbert.sf file..
tree "signed/" signed successfully
 


11. XPI 로 다시 패키징 합니다.

signed 폴더로 가서 META-INF/zigbert.rsa 파일을 처음에 오도록 zip 합니다.

Code:
C:\Projects\Certs\> cd signed

C:\Projects\CodeSigning\signed\> zip fsb.xpi META-INF/zigbert.rsa
  adding: META-INF/zigbert.rsa (deflated 35%)

C:\Projects\CodeSigning\signed> zip -r -D fsb.xpi * -x META-INF/zigbert.rsa
  adding: META-INF/manifest.mf (deflated 37%)
  adding: META-INF/zigbert.sf (deflated 40%)
  adding: chrome/fsb.jar (deflated 74%)
  adding: chrome.manifest (deflated 69%)
  adding: install.rdf (deflated 62%)

12. 완료.



http://forums.tjworld.net/viewtopic.php?p=210  의 내용을 번역 수정하였습니다.


인증서 신청  :

THAWTE : www.certkorea.co.kr

VERISIGN : www.ssl.co.kr


AND

FireFox에서 Fiddler로 디버깅하는 방법

1. 먼저 Fiddler를 설치한다.
2. Fiddler를 실행하면 \Documents and Settings\deguls\My Documents\Fiddler\Scripts 폴더에
   BrowserPAC.js 가 생성된다.

3. Firefox를 설치한다.
4. Firefox 의 연결설정 - 프록시 자동 설정 주소에 BrowserPAC.js를 등록한다.
5. Firefox를 재시작한다.
AND

1. IE Tab 을 설치한다.

2. Firefox 의 메뉴에서  도구 - 설정 - 탭옵션 에서
   "창이 하나만 열려 있을 때 탭 숨기기 옵션 제거" 한다.
AND

출처: http://cafe.naver.com/hodeacademy.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=1987

Firefox의 최대 단점은 ActiveX를 사용하는 사이트가 어렵다는 것이랑

IE에 최적화된 싸이트(playforum)같은데서 테이블이 깨진다는거...

그래서 애드온/플러그인 시스템 중에 괜찮은 것이 있어서 소개 합니다.

IE Tab이라고 하는 플러그 인인데요

이걸 설치하면..firefox로 브라우징을 하다가 IE가 필요한 사이트에 오면(은행같은...)

버튼 하나 클릭하면 firefox 웹 브라우징 엔진을 IE엔진으로 바꿔줍니다.

그럼 OK죠..ㅋㅋ


그리고 fastfox란 것은 파이어폭스의 브라우징 속도를 최대한 올려주는 플러그인인데요

이 방식이 자신이 현재 보는 사이트에 걸려있는 링크 대상에 대한 파일을 미리 캐슁해두는 것 같습니다.

물론 현재 보고 있는 사이트가 느려지지 않는 수준에서만요.

그럼 링크 걸린 사이트 따라 갔을 때 이미 캐슁된 데이타에서 얻어오니깐 훨씬 빠르죠.


Fast Dic
은 ctrl+클릭 으로 영어단어를 클릭하면 미리 지정한(네이버 사전 같은..) 사전 사이트의 결과를 새 탭으로 열어서 보여 줍니다.


All in one Gesture
이던가..이것은 마우스 우클릭 한상태에서 모션을 취했을 때

해당 모션에 따른 반응을 하는 프로그램입니다.

마우스 우클릭하고 밑으로 쭉 내리면 프로그램이 내려가고

오른쯕으로 그으면 앞으로가기 왼쪽으로 그으면 뒤로가기 등이죠

AND