MozillaZine

Raising dom event from npapi plugin

Discuss building things with or for the Mozilla Platform.
ankur_agrwl
 
Posts: 1
Joined: October 6th, 2009, 5:30 am
October 6th, 2009, 6:04 am

Post Posted October 6th, 2009, 6:04 am

Hi All,
I am looking for how to raise a dom event from npapi?
I know NPN_Invoke() but it just calls an already attached function rather than raising an event.
Will appreciate any kind of help on the issue.

Regards,
Ankur

Torisugari
 
Posts: 1426
Joined: November 4th, 2002, 8:34 pm
Location: Kyoto, Nippon (GMT +9)
October 13th, 2009, 4:28 am

Post Posted October 13th, 2009, 4:28 am

I don't know what "raising DOM evnets" means and what for, even after reading MSDN article "Raising an Event".

http://msdn.microsoft.com/en-us/library/wkzf914z.aspx

I guess it may be something like "firing fake events, to call (DOM) event listeners". Yet I'm not too sure, I even browsed wiktionary: http://en.wiktionary.org/wiki/raise . Anyway, please forgive me if I'm talking about something quite pointless. And English nataive speakers, please explain why the term "raise" can be used on handling events.

After some simple search on the web, we can find examples to dispatch DOM events, here and there, e.g. https://developer.mozilla.org/en/DOM/do ... nt#Example

So I assume you already have enough knowledge about DOM event objects. Then the bottleneck would be "How to use DOM from NPAPI plugins", isn't it? Maybe NPAPI looks confusing, but the concept is relatively simple. You should keep in mind 2 rules:
  • When you want to use DOM methods, you can use NPN_Invoke
  • When you want to use DOM properties, you can use NPN_GetProperty
    • You have to use NPN_GetValue when you get window object, as NPN_GetProperty assumes you have an existing parent object.

Then I'd like to convert JavaScript example in that link into NPRUNTIME manner.
Mozilla Developer Center wrote:
Code: Select all
function simulateClick() {
  var evt = document.createEvent("MouseEvents");
  evt.initMouseEvent("click", true, true, window,
    0, 0, 0, 0, 0, false, false, false, false, 0, null);
  var cb = document.getElementById("checkbox");
  var canceled = !cb.dispatchEvent(evt);
  if(canceled) {
    // A handler called preventDefault
    alert("canceled");
  } else {
    // None of the handlers called preventDefault
    alert("not canceled");
  }
}


->
Code: Select all
#include "npfunctions.h"
#include "npruntime.h"

/* You always need Pointer to the Plugin instance. */
void SimulateClick(NPP aInstance) {
  /* Get window object */
  NPObject* window = NULL;
  NPN_GetValue(aInstance, NPNVWindowNPObject, &window);

  /* Get document object */
  NPVariant documentVar;
  NPIdentifier id = NPN_GetStringIdentifier("document");
  NPN_GetProperty(aInstance, window, id, &documentVar);
  NPObject* document = NPVARIANT_TO_OBJECT(documentVar);
  /* Note that this |document| is |window.document|.
     Maybe |element.ownerDocument| is more useful. */

  /* Get event object. See "evt" part of the JavaScript. */
  NPVariant evtVar;
  id = NPN_GetStringIdentifier("createEvent");

  { /* Note that I just like to use the words |args| and |type| again. */
    NPVariant type;
    NPVariant args[] = {type};
    STRINGZ_TO_NPVARIANT("MouseEvents", type);
    NPN_Invoke(aInstance, document, id, args, sizeof(args)/sizeof(args[0]),
               &evtVar);
  }
  NPObject* evt = NPVARIANT_TO_OBJECT(evtVar);
  /* Now, we have done the fist line of the script:

     var evt = document.createEvent("MouseEvents");

     Then, let's try initMouseEvent.
   */

  NPVariant dummyResult; /* Probably initMouseEvent returns void.*/
  id = NPN_GetStringIdentifier("initMouseEvent");
  {
    NPVariant type, canBubble, cancelable, view,
              detail, screenX, screenY, clientX, clientY,
              ctrlKey, altKey, shiftKey, metaKey,
              button, relatedTarget;
    NPVariant args[] = {
      type, canBubble, cancelable, view,
      detail, screenX, screenY, clientX, clientY,
      ctrlKey, altKey, shiftKey, metaKey,
      button, relatedTarget
    };

    /* Initialize args: you can reuse false/true/0 though. */
    STRINGZ_TO_NPVARIANT("click", type);
    BOOLEAN_TO_NPVARIANT(true, canBubble);     
    BOOLEAN_TO_NPVARIANT(true, cancelable);
    OBJECT_TO_NPVARIANT(window, view);
    INT32_TO_NPVARIANT(0, detail);       
    INT32_TO_NPVARIANT(0, screenX);       
    INT32_TO_NPVARIANT(0, screenY);       
    INT32_TO_NPVARIANT(0, clientX);       
    INT32_TO_NPVARIANT(0, clientY);       
    BOOLEAN_TO_NPVARIANT(false, ctrlKey);
    BOOLEAN_TO_NPVARIANT(false, altKey); 
    BOOLEAN_TO_NPVARIANT(false, shiftKey);
    BOOLEAN_TO_NPVARIANT(false, metaKey);
    INT32_TO_NPVARIANT(0, button);
    NULL_TO_NPVARIANT(relatedTarget);

    NPN_Invoke(aInstance, evt, id, args, sizeof(args)/sizeof(args[0]),
               &dummyResult);
  }

  /* Get checkbox element */
  NPVariant cbVar;
  id = NPN_GetStringIdentifier("getElementById");
  {
    NPVariant elementId;
    NPVariant args[] = {elementId};
    STRINGZ_TO_NPVARIANT("checkbox", elementId);
    NPN_Invoke(aInstance, document, id, args, sizeof(args)/sizeof(args[0]),
               &cbVar);
  }
  NPObject* cb = NPVARIANT_TO_OBJECT(cbVar);

  /* Fire |evt| to |cb| */
  NPVariant notCanceled; /* We can't receive "canceled" directly! */
  id = NPN_GetStringIdentifier("dispatchEvent");
  {
    NPVariant args[] = {evtVar};
    NPN_Invoke(aInstance, cb, id, args, sizeof(args)/sizeof(args[0]),
               &notCanceled);
  }

  bool canceled = NPVARIANT_IS_BOOLEAN(notCanceled) &&
                  !(NPVARIANT_TO_BOOLEAN(notCanceled));
  if (canceled) {
    // A handler called preventDefault
    printf("canceled\n");
  }
  else {
    // None of the handlers called preventDefault
    printf("not canceled\n");
  }

  /* Release all allocated objects, otherwise, reference count/memory leaks. */
  NPN_ReleaseObject(window);
  NPN_ReleaseVariantValue(&documentVar);
  NPN_ReleaseVariantValue(&evtVar);
  NPN_ReleaseVariantValue(&dummyResult); /* fake */
  NPN_ReleaseVariantValue(&cbVar);
  NPN_ReleaseVariantValue(&notCanceled); /* fake*/
}
/* XXX I haven't tested  this code so I'm not sure if even it is compilable. */

If you've ever written a npruntime plugin, you'll see the symmetric relation between NPP_Invoke/GetProperty and NPN_Invoke/GetProperty. You can use NPN_Invoke just as you've implemented NPP_Inovke, as if NPN_Invoke had been implemented by another plugin author.

anmorf
 
Posts: 8
Joined: October 27th, 2009, 6:28 am
October 27th, 2009, 6:34 am

Post Posted October 27th, 2009, 6:34 am

Hey,

I tried your example and it really works fine ;-) (well I had to do two small modifications) ... do you have any idea how to add an event listener in an NPAPI Plugin?
I wanna do something like in javascript element.addEventListener('click', anyFunction, false), but it does not work.

Thx

Torisugari
 
Posts: 1426
Joined: November 4th, 2002, 8:34 pm
Location: Kyoto, Nippon (GMT +9)
October 27th, 2009, 6:43 pm

Post Posted October 27th, 2009, 6:43 pm

anmorf wrote: do you have any idea how to add an event listener in an NPAPI Plugin?
I wanna do something like in javascript element.addEventListener('click', anyFunction, false), but it does not work.


You mean you are going to run a specific (i.e. fixed, not dynamic) script? Then, how about NPN_Evaluate?

https://developer.mozilla.org/en/NPN_Evaluate

This is equivalent to JavaScript's eval

By the way, good old plugins used to call NPN_GetURL with "javascript" shceme. (e.g. "javascript:alert('hello');"). Actually this was a recommended way to evaluate JavaScript by Netscape.

anmorf
 
Posts: 8
Joined: October 27th, 2009, 6:28 am
November 2nd, 2009, 6:13 am

Post Posted November 2nd, 2009, 6:13 am

Yes, that indeed worked :-), thanks a lot.
What if you want to evaluate a script which is dynamic or needs some parameters? Let's say I want to evaluate one of the typical javascript functions which take an event as parameter and give some result (like e.g. in http://www.w3schools.com/js/tryit.asp?f ... srcelement). Is there a way how to attach an event object (which gets triggered by e.g. a click/mouseover event) to an element on the page with the NPAPI Plugin?

Torisugari
 
Posts: 1426
Joined: November 4th, 2002, 8:34 pm
Location: Kyoto, Nippon (GMT +9)
November 2nd, 2009, 9:49 pm

Post Posted November 2nd, 2009, 9:49 pm

Hmm, I doubt DOM events work within a plugin-window area. Isn't it more handy to catch them in a callback(WndProc or NPP_HandleElvent etc.) than DOM event listener?

Anyway, I guess you could use addEventlistener in this way:
1. create a brand new NPClass
2. implement your event listener in InvokeDefault of the NPClass.
3.create NPObject per the NPClass and pass it as second param of addEventListener.

anmorf
 
Posts: 8
Joined: October 27th, 2009, 6:28 am
November 3rd, 2009, 8:29 am

Post Posted November 3rd, 2009, 8:29 am

Thx for the answer. In the meantime I found similar code (like e.g. in http://code.google.com/p/gears/source/b ... .cc?r=2268) which has the same goal. So I try to include it in a similar way. Your idea is correct ... but it's not so easy to do that :?

anmorf
 
Posts: 8
Joined: October 27th, 2009, 6:28 am
November 7th, 2009, 2:46 am

Post Posted November 7th, 2009, 2:46 am

It finally worked. Thank you Torisugari for the hints! The addEventListener can be implemented as follows:
1. Create your own BaseClass which extends from NPObject (e.g. EventObjectBase). You should also define a brand new NPClass (that worked!)
2. Create your own Class which extends the BaseClass (e.g. EventObject). There you need at least the functions HasMethod, HasProperty, GetProperty, Invoke and InvokeDefault.
3. Implement your event listener in Invoke / GetProperty of the NPClass -> you need to add a functionId 'handleEvent'. Firefox allows the use of both method and property; Opera uses only the method; Opera and Safari only use the property.
4. Create NPObject for your NPClass together with your new EventObject class and pass it as the second parameter of addEventListener -> you need to create the object with NPN_CreateObject(...) which returns an NPObject *eventObject.
After all this steps, an actual click on your element in the browser should now invoke either the method or the property (depending where you use it). You also have access to all the associated properties of the event object (target, pageX, pageY, and so on ...).

Torisugari
 
Posts: 1426
Joined: November 4th, 2002, 8:34 pm
Location: Kyoto, Nippon (GMT +9)
November 7th, 2009, 8:31 pm

Post Posted November 7th, 2009, 8:31 pm

anmorf wrote:you need to add a functionId 'handleEvent'.

Oh, I didn't know that. It seems corresponding to DOM-L2's "EventListener" Interface.
http://www.w3.org/TR/DOM-Level-2-Events ... tions.html
w3c wrote:
Code: Select all
  // Introduced in DOM Level 2:
  interface EventListener {
    void handleEvent(in Event evt);
  };


So, in DOM Level 2's sense, it's more proper to use
Code: Select all
var eventListener = {
  handleEvent: function _he_(aEvent) {
    alert(aEvent.type);   
  }
};
myTarget.addEventListener("click", eventListener, false);
than
Code: Select all
function eventListener2(aEvent) {
  alert(aEvent.type);   
}
myTarget.addEventListener("click", eventListener2, false);


https://developer.mozilla.org/en/DOM/el ... ner#Syntax
Mozilla Developer Center wrote:listener
The object that receives a notification when an event of the specified type occurs. This must be an object implementing the EventListener interface, or simply a JavaScript function.


I always used the latter and never imagined the former, but it's very reasonable especially when I'm doing something complicated, such as programming with npruntime. Anyway, thanks for the info.

anmorf
 
Posts: 8
Joined: October 27th, 2009, 6:28 am
November 9th, 2009, 11:05 am

Post Posted November 9th, 2009, 11:05 am

Hey,

I still have a problem in my implementation.
Firefox supports Invoke and GetProperty, Opera only supports Invoke, Safari supports GetProperty and InvokeDefault, and Chrome only supports GetProperty. When the function is invoked with Invoke or InvokeDefault I have easy access to the actual event object which the browser returns (it's the argument[0]) and I can get all the properties of an event. But in GetProperty I don't know how I can get hold of the event object from the browser. Is there a way to access this event object? I tried with window.event but it does not work.

anmorf
 
Posts: 8
Joined: October 27th, 2009, 6:28 am
November 9th, 2009, 12:00 pm

Post Posted November 9th, 2009, 12:00 pm

I found the solution:
In Firefox (I use Invoke and args[0]), Opera (I use Invoke and args[0]) and Safari (I use InvokeDefault and args[0]) the problem is already solved. In Chrome I always have the problem that I am not able to debug with Visual Studio and hence I first had the impression that window.event doesn't work, but it does! So in Chrome you can invoke in GetProperty() the function NPN_Invoke(...) on the window object and get the event. It seems to work and I even have access on e.g. pageX.
and by the way: my classes should actually have the name EventListenerObject since it is not the actual event object but the listener (but that's just a detail since it works :-)).

anmorf
 
Posts: 8
Joined: October 27th, 2009, 6:28 am
November 13th, 2009, 4:38 am

Post Posted November 13th, 2009, 4:38 am

Hi all, I have a new challenge: creating XMLHTTPRequest with NPAPI.
I would like to get the XMLHttpRequest object in an NPObject.
Is there a way to execute the script

var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
xhr = new ActiveXObject("Msxml2.XMLHTTP");
}

and then get the xhr object inside an NPVariant / NPObject ?
I already know that one can evaluate a script inside NPN_Evaluate, but it doesn't seem to return the object in the variant. I looked at NPN_Construct but I don't know how to use it (but maybe its anyway not the right way to get the correct object).

anmorf
 
Posts: 8
Joined: October 27th, 2009, 6:28 am
November 13th, 2009, 4:51 am

Post Posted November 13th, 2009, 4:51 am

Interesting result:

you can use it directly inside of NPN_Invoke to create an object. And indeed it worked! So use the following:
bool g = NPN_GetProperty(m_pluginInstance, m_windowObj, npId_XMLHttpRequest, &v);
if (g) {
NPVariant nullv;
NPN_Invoke(m_pluginInstance, m_windowObj, npId_XMLHttpRequest, &nullv, 0, &v);
} else {
// do alternative
}

and then you should have the XMLHttpRequest inside the NPVariant v. On this object you can add an event listener and then you get the callback.

Torisugari
 
Posts: 1426
Joined: November 4th, 2002, 8:34 pm
Location: Kyoto, Nippon (GMT +9)
November 13th, 2009, 5:36 am

Post Posted November 13th, 2009, 5:36 am

Umm, at this point, I'd rather like to know why you don't like to use NPAPI, such as NPN_GetURL and NPP_NewStream/NPP_Write etc...

krecik
 
Posts: 1
Joined: November 17th, 2009, 7:17 am
November 17th, 2009, 7:29 am

Post Posted November 17th, 2009, 7:29 am

Hello,

I'd like to ask about something similar to issues discussed in this topic, namely about firing/raising custom events from npapi plugin.
I have read all replies however I still does not know how to implement it.

I need to handle a case below:
Code: Select all
var pluginObject = document.getElementById('plugin');
pluginObject.myCustomEventHandler = function( message ) { alert(message); };

pluginObject.DoSomething();

// Then somewhere in NPAPI plugin I want to fire myCustomEventHandler event which invokes my attached function.
// myCustomEventHandler("Hello world");


Is it possible with NPAPI or should I implement this behavior in different way (How?)?
Thanks in advance for Your help :)

Return to Mozilla Development


Who is online

Users browsing this forum: No registered users and 2 guests