LCOV - code coverage report
Current view: top level - compositor - mpeg4_inputsensor.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 319 504 63.3 %
Date: 2021-04-29 23:48:07 Functions: 18 19 94.7 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2017
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Compositor sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #include <gpac/internal/compositor_dev.h>
      27             : #include <gpac/modules/codec.h>
      28             : #include <gpac/utf.h>
      29             : #include <gpac/nodes_x3d.h>
      30             : #include <gpac/constants.h>
      31             : 
      32             : #ifndef GPAC_DISABLE_VRML
      33             : 
      34             : enum
      35             : {
      36             :         IS_KeySensor = 1,
      37             :         IS_StringSensor,
      38             :         IS_Mouse,
      39             :         IS_HTKSensor,
      40             : };
      41             : 
      42             : typedef struct
      43             : {
      44             :         /*object for this input stream*/
      45             :         GF_ObjectManager *odm;
      46             : 
      47             :         /*list of attached nodes*/
      48             :         GF_List *is_nodes;
      49             :         /*stream ID*/
      50             :         u16 ES_ID;
      51             :         /*uncompressed data frame*/
      52             :         GF_List *ddf;
      53             : 
      54             :         GF_InputSensorDevice *io_dev;
      55             : 
      56             :         u32 type;
      57             : 
      58             :         /*string sensor sep char */
      59             :         s16 termChar, delChar;
      60             :         /*current typed text in UTF-8*/
      61             :         unsigned short enteredText[5000];
      62             :         u32 text_len;
      63             : } GF_InputSensorCtx;
      64             : 
      65             : 
      66             : void gf_isdec_del(GF_BaseDecoder *plug);
      67             : 
      68             : static GF_Err IS_ProcessData(GF_InputSensorCtx *is_ctx, const char *inBuffer, u32 inBufferLength);
      69             : 
      70             : typedef struct
      71             : {
      72             :         /*stream context*/
      73             :         u16 ES_ID;
      74             :         Bool registered;
      75             :         GF_MediaObject *mo;
      76             :         M_InputSensor *is;
      77             : } ISStack;
      78             : 
      79             : 
      80             : 
      81             : typedef struct
      82             : {
      83             :         u16 enteredText[5000];
      84             :         u32 text_len;
      85             :         GF_Compositor *compositor;
      86             : } StringSensorStack;
      87             : 
      88             : 
      89             : 
      90             : /*
      91             :                                 input sensor decoder(s) handling
      92             : */
      93             : 
      94             : 
      95          90 : static void add_field(GF_InputSensorCtx *priv, u32 fieldType, const char *fieldName)
      96             : {
      97          90 :         GF_FieldInfo *field = (GF_FieldInfo *) gf_malloc(sizeof(GF_FieldInfo));
      98             :         memset(field, 0, sizeof(GF_FieldInfo));
      99          90 :         field->fieldType = fieldType;
     100          90 :         field->far_ptr = gf_sg_vrml_field_pointer_new(fieldType);
     101          90 :         field->name = (const char *) fieldName;
     102          90 :         field->fieldIndex = gf_list_count(priv->ddf);
     103          90 :         gf_list_add(priv->ddf, field);
     104          90 : }
     105             : 
     106           0 : static void isdev_add_field(GF_InputSensorDevice *dev, u32 fieldType, const char *fieldName)
     107             : {
     108           0 :         if (dev) {
     109           0 :                 GF_InputSensorCtx *is = (GF_InputSensorCtx *)dev->input_stream_context;
     110           0 :                 add_field(is, fieldType, fieldName);
     111             :         }
     112           0 : }
     113             : 
     114          15 : static void isdev_dispatch_frame(struct __input_device *dev, const u8 *data, u32 data_len)
     115             : {
     116             :         u32 i;
     117             :         GF_InputSensorCtx *is_ctx;
     118             :         GF_InputSensorCtx *priv;
     119          30 :         if (!dev || !data) return;
     120             : 
     121           0 :         priv = (GF_InputSensorCtx *)dev->input_stream_context;
     122             : 
     123             :         /*get all decoders and send frame*/
     124           0 :         i=0;
     125           0 :         while ((is_ctx = gf_list_enum(priv->odm->parentscene->compositor->input_streams, &i))) {
     126           0 :                 if (is_ctx->type==priv->type) {
     127           0 :                         IS_ProcessData(is_ctx, data, data_len);
     128             :                 }
     129             :         }
     130             : }
     131             : 
     132          61 : static GF_InputSensorCtx *locate_is_ctx_for_odm(GF_Scene *scene, GF_ObjectManager *for_odm)
     133             : {
     134             :         u32 i, count;
     135          61 :         count = gf_list_count(scene->compositor->input_streams);
     136          18 :         for (i=0; i<count; i++) {
     137          63 :                 GF_InputSensorCtx *is_ctx = gf_list_get(scene->compositor->input_streams, i);
     138          63 :                 if (is_ctx->odm == for_odm) return is_ctx;
     139             :         }
     140             :         return NULL;
     141             : }
     142             : 
     143          15 : GF_Err gf_input_sensor_setup_object(GF_ObjectManager *odm, GF_ESD *esd)
     144             : {
     145             :         u32 i;
     146             :         GF_InputSensorCtx *is_ctx;
     147             :         GF_BitStream *bs;
     148             :         u32 len, size;
     149             :         char devName[255];
     150             :         u16 termSeq[20];
     151          15 :         GF_Scene *scene = odm->parentscene;
     152             : 
     153          15 :         if (esd->URLString) return GF_NOT_SUPPORTED;
     154             : 
     155          15 :         if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->dataLength) return GF_NON_COMPLIANT_BITSTREAM;
     156             : 
     157          15 :         if (!scene->compositor->input_streams) {
     158           9 :                 scene->compositor->input_streams = gf_list_new();
     159           9 :                 if (!scene->compositor->input_streams) return GF_OUT_OF_MEM;
     160             :         }
     161          15 :         is_ctx = locate_is_ctx_for_odm(scene, odm);
     162          15 :         if (is_ctx) return GF_OK;
     163             : 
     164          15 :         GF_SAFEALLOC(is_ctx, GF_InputSensorCtx);
     165          15 :         if (!is_ctx) return GF_OUT_OF_MEM;
     166             : 
     167          15 :         is_ctx->odm = odm;
     168          15 :         is_ctx->is_nodes = gf_list_new();
     169          15 :         is_ctx->ddf = gf_list_new();
     170             : 
     171          15 :         is_ctx->ES_ID = esd->ESID;
     172             :         /*parse config*/
     173          15 :         bs = gf_bs_new(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, GF_BITSTREAM_READ);
     174          15 :         len = gf_bs_read_int(bs, 8);
     175         133 :         for (i=0; i<len; i++) {
     176         118 :                 devName[i] = gf_bs_read_int(bs, 8);
     177             :         }
     178          15 :         gf_bs_del(bs);
     179          15 :         devName[i] = 0;
     180          15 :         is_ctx->type = gf_crc_32(devName, len);
     181          15 :         size = len + 1;
     182             : 
     183          15 :         if (!stricmp(devName, "KeySensor")) {
     184           9 :                 is_ctx->type = IS_KeySensor;
     185           9 :                 add_field(is_ctx, GF_SG_VRML_SFINT32, "keyPressed");
     186           9 :                 add_field(is_ctx, GF_SG_VRML_SFINT32, "keyReleased");
     187           9 :                 add_field(is_ctx, GF_SG_VRML_SFINT32, "actionKeyPressed");
     188           9 :                 add_field(is_ctx, GF_SG_VRML_SFINT32, "actionKeyReleased");
     189           9 :                 add_field(is_ctx, GF_SG_VRML_SFBOOL, "shiftKeyPressed");
     190           9 :                 add_field(is_ctx, GF_SG_VRML_SFBOOL, "controlKeyPressed");
     191           9 :                 add_field(is_ctx, GF_SG_VRML_SFBOOL, "altKeyPressed");
     192             : 
     193           6 :         } else if (!stricmp(devName, "StringSensor")) {
     194           1 :                 is_ctx->type = IS_StringSensor;
     195           1 :                 add_field(is_ctx, GF_SG_VRML_SFSTRING, "enteredText");
     196           1 :                 add_field(is_ctx, GF_SG_VRML_SFSTRING, "finalText");
     197             : 
     198           1 :                 is_ctx->termChar = '\r';
     199           1 :                 is_ctx->delChar = '\b';
     200             : 
     201             :                 /*get escape chars if any specified*/
     202           1 :                 if (size<esd->decoderConfig->decoderSpecificInfo->dataLength) {
     203           0 :                         const char *src = esd->decoderConfig->decoderSpecificInfo->data + size;
     204           0 :                         gf_utf8_mbstowcs(termSeq, esd->decoderConfig->decoderSpecificInfo->dataLength - size, &src);
     205           0 :                         is_ctx->termChar = termSeq[0];
     206           0 :                         is_ctx->delChar = termSeq[1];
     207             :                 }
     208           5 :         } else if (!stricmp(devName, "Mouse")) {
     209           5 :                 is_ctx->type = IS_Mouse;
     210           5 :                 add_field(is_ctx, GF_SG_VRML_SFVEC2F, "position");
     211           5 :                 add_field(is_ctx, GF_SG_VRML_SFBOOL, "leftButtonDown");
     212           5 :                 add_field(is_ctx, GF_SG_VRML_SFBOOL, "middleButtonDown");
     213           5 :                 add_field(is_ctx, GF_SG_VRML_SFBOOL, "rightButtonDown");
     214           5 :                 add_field(is_ctx, GF_SG_VRML_SFFLOAT, "wheel");
     215             :         }
     216             :         else {
     217             :                 GF_InputSensorDevice *ifce;
     218             :                 /*not found, check all modules*/
     219           0 :                 u32 plugCount = gf_modules_count();
     220           0 :                 for (i = 0; i < plugCount ; i++) {
     221           0 :                         ifce = (GF_InputSensorDevice *) gf_modules_load(i, GF_INPUT_DEVICE_INTERFACE);
     222           0 :                         if (!ifce) continue;
     223           0 :                         ifce->input_stream_context = is_ctx;
     224           0 :                         if (ifce->RegisterDevice && ifce->RegisterDevice(ifce, devName, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, isdev_add_field) ) {
     225           0 :                                 is_ctx->io_dev = ifce;
     226           0 :                                 break;
     227             :                         }
     228           0 :                         gf_modules_close_interface((GF_BaseInterface *) ifce);
     229             :                 }
     230           0 :                 if (!is_ctx->io_dev) {
     231           0 :                         gf_free(is_ctx);
     232           0 :                         return GF_NOT_SUPPORTED;
     233             :                 }
     234           0 :                 is_ctx->io_dev->DispatchFrame = isdev_dispatch_frame;
     235             :         }
     236             : 
     237             : #ifdef GPAC_ENABLE_COVERAGE
     238          15 :         if (gf_sys_is_cov_mode()) {
     239             :                 isdev_add_field(NULL, 0, NULL);
     240          15 :                 isdev_dispatch_frame(NULL, NULL, 0);
     241             :         }
     242             : #endif
     243             : 
     244          15 :         gf_list_add(is_ctx->odm->parentscene->compositor->input_streams, is_ctx);
     245          15 :         return GF_OK;
     246             : }
     247             : 
     248          16 : void gf_input_sensor_delete(GF_ObjectManager *odm)
     249             : {
     250             :         /*get IS dec*/
     251          16 :         GF_InputSensorCtx *is_ctx = locate_is_ctx_for_odm(odm->parentscene, odm);
     252          16 :         if (!is_ctx) return;
     253             : 
     254          15 :         gf_list_del(is_ctx->is_nodes);
     255             : 
     256         120 :         while (gf_list_count(is_ctx->ddf)) {
     257          90 :                 GF_FieldInfo *fi = (GF_FieldInfo *)gf_list_get(is_ctx->ddf, 0);
     258          90 :                 gf_list_rem(is_ctx->ddf, 0);
     259          90 :                 gf_sg_vrml_field_pointer_del(fi->far_ptr, fi->fieldType);
     260          90 :                 gf_free(fi);
     261             :         }
     262          15 :         gf_list_del(is_ctx->ddf);
     263          15 :         gf_list_del_item(odm->parentscene->compositor->input_streams, is_ctx);
     264          15 :         gf_free(is_ctx);
     265             : }
     266             : 
     267             : 
     268             : 
     269          59 : static GF_Err IS_ProcessData(GF_InputSensorCtx *is_ctx, const char *inBuffer, u32 inBufferLength)
     270             : {
     271             :         u32 i, j, count;
     272             :         Double scene_time;
     273             :         GF_BitStream *bs;
     274             :         GF_FieldInfo *field;
     275             :         ISStack *st;
     276             :         GF_Err e = GF_OK;
     277             : 
     278             :         /*decode data frame except if local stringSensor*/
     279          59 :         bs = gf_bs_new((u8 *)inBuffer, inBufferLength, GF_BITSTREAM_READ);
     280          59 :         i=0;
     281         389 :         while ((field = (GF_FieldInfo *)gf_list_enum(is_ctx->ddf, &i))) {
     282             :                 /*store present flag in eventIn for command skip - this is an ugly hack but it works since DDF don't have event types*/
     283         271 :                 field->eventType = gf_bs_read_int(bs, 1);
     284             :                 /*parse val ourselves (we don't want to depend on bifs codec)*/
     285         271 :                 if (field->eventType) {
     286          49 :                         switch (field->fieldType) {
     287           7 :                         case GF_SG_VRML_SFBOOL:
     288           7 :                                 * ((SFBool *) field->far_ptr) = (SFBool) gf_bs_read_int(bs, 1);
     289           7 :                                 break;
     290           0 :                         case GF_SG_VRML_SFFLOAT:
     291           0 :                                 *((SFFloat *)field->far_ptr) = FLT2FIX( gf_bs_read_float(bs) );
     292           0 :                                 break;
     293           6 :                         case GF_SG_VRML_SFINT32:
     294           6 :                                 *((SFInt32 *)field->far_ptr) = (s32) gf_bs_read_int(bs, 32);
     295           6 :                                 break;
     296           0 :                         case GF_SG_VRML_SFTIME:
     297           0 :                                 *((SFTime *)field->far_ptr) = gf_bs_read_double(bs);
     298           0 :                                 break;
     299          36 :                         case GF_SG_VRML_SFVEC2F:
     300          36 :                                 ((SFVec2f *)field->far_ptr)->x = FLT2FIX( gf_bs_read_float(bs) );
     301          36 :                                 ((SFVec2f *)field->far_ptr)->y = FLT2FIX( gf_bs_read_float(bs) );
     302          36 :                                 break;
     303           0 :                         case GF_SG_VRML_SFVEC3F:
     304           0 :                                 ((SFVec3f *)field->far_ptr)->x = FLT2FIX( gf_bs_read_float(bs) );
     305           0 :                                 ((SFVec3f *)field->far_ptr)->y = FLT2FIX( gf_bs_read_float(bs) );
     306           0 :                                 ((SFVec3f *)field->far_ptr)->z = FLT2FIX( gf_bs_read_float(bs) );
     307           0 :                                 break;
     308           0 :                         case GF_SG_VRML_SFCOLOR:
     309           0 :                                 ((SFColor *)field->far_ptr)->red = FLT2FIX( gf_bs_read_float(bs) );
     310           0 :                                 ((SFColor *)field->far_ptr)->green = FLT2FIX( gf_bs_read_float(bs) );
     311           0 :                                 ((SFColor *)field->far_ptr)->blue = FLT2FIX( gf_bs_read_float(bs) );
     312           0 :                                 break;
     313           0 :                         case GF_SG_VRML_SFVEC4F:
     314             :                         case GF_SG_VRML_SFROTATION:
     315           0 :                                 ((SFRotation *)field->far_ptr)->x = FLT2FIX( gf_bs_read_float(bs) );
     316           0 :                                 ((SFRotation *)field->far_ptr)->y = FLT2FIX( gf_bs_read_float(bs) );
     317           0 :                                 ((SFRotation *)field->far_ptr)->z = FLT2FIX( gf_bs_read_float(bs) );
     318           0 :                                 ((SFRotation *)field->far_ptr)->q = FLT2FIX( gf_bs_read_float(bs) );
     319           0 :                                 break;
     320             : 
     321           0 :                         case GF_SG_VRML_SFSTRING:
     322             :                         {
     323             :                                 u32 size, length;
     324           0 :                                 size = gf_bs_read_int(bs, 5);
     325           0 :                                 length = gf_bs_read_int(bs, size);
     326           0 :                                 if (gf_bs_available(bs) < length) return GF_NON_COMPLIANT_BITSTREAM;
     327             : 
     328           0 :                                 if ( ((SFString *)field->far_ptr)->buffer ) gf_free( ((SFString *)field->far_ptr)->buffer);
     329           0 :                                 ((SFString *)field->far_ptr)->buffer = (char*)gf_malloc(sizeof(char)*(length+1));
     330           0 :                                 if ( ((SFString *)field->far_ptr)->buffer) {
     331           0 :                                         for (j=0; j<length; j++) {
     332           0 :                                                 ((SFString *)field->far_ptr)->buffer[j] = gf_bs_read_int(bs, 8);
     333             :                                         }
     334           0 :                                         ((SFString *)field->far_ptr)->buffer[length] = 0;
     335             :                                 } else {
     336           0 :                                         gf_bs_del(bs);
     337           0 :                                         return GF_OUT_OF_MEM;
     338             :                                 }
     339             :                         }
     340           0 :                         break;
     341             :                         }
     342             :                 }
     343             :         }
     344          59 :         gf_bs_del(bs);
     345             : 
     346             :         /*special case for StringSensor in local mode: lookup for special chars*/
     347          59 :         if (is_ctx->type == IS_StringSensor) {
     348             :                 char tmp_utf8[5000];
     349             :                 const unsigned short *ptr;
     350             :                 u32 len;
     351          14 :                 GF_FieldInfo *field1 = (GF_FieldInfo *)gf_list_get(is_ctx->ddf, 0);
     352          14 :                 GF_FieldInfo *field2 = (GF_FieldInfo *)gf_list_get(is_ctx->ddf, 1);
     353          14 :                 SFString *inText = (SFString *) field1->far_ptr;
     354          14 :                 SFString *outText = (SFString *) field2->far_ptr;
     355             : 
     356          14 :                 field1->eventType = field2->eventType = 0;
     357          14 :                 is_ctx->enteredText[is_ctx->text_len] = (short) '\0';
     358             : 
     359          14 :                 len = (u32) gf_utf8_wcslen(is_ctx->enteredText);
     360          14 :                 if (len && (is_ctx->enteredText[len-1] == is_ctx->termChar)) {
     361           1 :                         ptr = is_ctx->enteredText;
     362           1 :                         len = (u32) gf_utf8_wcstombs(tmp_utf8, 5000, &ptr);
     363           1 :                         if (outText->buffer) gf_free(outText->buffer);
     364           1 :                         outText->buffer = (char*)gf_malloc(sizeof(char) * (len));
     365           1 :                         memcpy(outText->buffer, tmp_utf8, sizeof(char) * len-1);
     366           1 :                         outText->buffer[len-1] = 0;
     367           1 :                         if (inText->buffer) gf_free(inText->buffer);
     368           1 :                         inText->buffer = NULL;
     369           1 :                         is_ctx->text_len = 0;
     370             : 
     371           1 :                         field1->eventType = field2->eventType = 1;
     372             :                 } else {
     373          13 :                         if (is_ctx->delChar) {
     374             :                                 /*remove chars*/
     375          13 :                                 if ((len>1) && (is_ctx->enteredText[len-1] == is_ctx->delChar)) {
     376           4 :                                         is_ctx->enteredText[len-1] = (short) '\0';
     377             :                                         len--;
     378           4 :                                         is_ctx->enteredText[len-1] = (short) '\0';
     379             :                                         len--;
     380             :                                 }
     381             :                         }
     382          13 :                         is_ctx->text_len = len;
     383          13 :                         ptr = is_ctx->enteredText;
     384          13 :                         len = (u32) gf_utf8_wcstombs(tmp_utf8, 5000, &ptr);
     385          13 :                         if (inText->buffer) gf_free(inText->buffer);
     386          13 :                         inText->buffer = (char*)gf_malloc(sizeof(char) * (len+1));
     387             :                         memcpy(inText->buffer, tmp_utf8, sizeof(char) * len);
     388          13 :                         inText->buffer[len] = 0;
     389          13 :                         field1->eventType = 1;
     390             :                 }
     391             :         }
     392             : 
     393             :         //we still need this since we have no clue when the device sensor is calling us
     394             :         //TO CLEANUP (define PIDs and filters for input sensors and put them in the main thread ?)
     395          59 :         gf_sc_lock(is_ctx->odm->parentscene->compositor, GF_TRUE);
     396             : 
     397             :         /*apply it*/
     398          59 :         i=0;
     399         177 :         while ((st = (ISStack*)gf_list_enum(is_ctx->is_nodes, &i))) {
     400             :                 assert(st->is);
     401             :                 assert(st->mo);
     402          59 :                 if (!st->is->enabled) continue;
     403             : 
     404          59 :                 count = gf_list_count(st->is->buffer.commandList);
     405          59 :                 scene_time = gf_scene_get_time(is_ctx->odm->parentscene);
     406         330 :                 for (j=0; j<count; j++) {
     407         271 :                         GF_Command *com = (GF_Command *)gf_list_get(st->is->buffer.commandList, j);
     408         271 :                         GF_CommandField *info = (GF_CommandField *)gf_list_get(com->command_fields, 0);
     409         271 :                         field = (GF_FieldInfo *)gf_list_get(is_ctx->ddf, j);
     410         271 :                         if (info && field && field->eventType) {
     411          64 :                                 gf_sg_vrml_field_copy(info->field_ptr, field->far_ptr, field->fieldType);
     412          64 :                                 gf_sg_command_apply(is_ctx->odm->parentscene->graph, com, scene_time);
     413             :                         }
     414             :                 }
     415             :         }
     416          59 :         gf_sc_lock(is_ctx->odm->parentscene->compositor, GF_FALSE);
     417          59 :         return e;
     418             : }
     419             : 
     420             : 
     421             : /*
     422             :                                 input sensor node handling
     423             : */
     424          15 : static void InputSensorUnregister(GF_Node *node, ISStack *st)
     425             : {
     426             :         GF_ObjectManager *odm;
     427             :         GF_InputSensorCtx *is_ctx;
     428             : 
     429          15 :         gf_mo_unregister(node, st->mo);
     430             : 
     431          15 :         odm = st->mo->odm;
     432          15 :         if (!odm) return;
     433             : 
     434             :         assert(odm->type == GF_STREAM_INTERACT);
     435             : 
     436             :         /*get IS dec*/
     437          15 :         is_ctx = locate_is_ctx_for_odm(odm->parentscene, odm);
     438          15 :         if (!is_ctx) return;
     439             : 
     440          15 :         gf_list_del_item(is_ctx->is_nodes, st);
     441             : 
     442             : 
     443             :         /*stop stream*/
     444          15 :         if (st->mo->num_open) gf_mo_stop(&st->mo);
     445          15 :         st->mo = NULL;
     446          15 :         if (st->registered) {
     447          15 :                 st->registered = 0;
     448          15 :                 if (is_ctx->io_dev && is_ctx->io_dev->Stop) is_ctx->io_dev->Stop(is_ctx->io_dev);
     449             :         }
     450             : }
     451             : 
     452          25 : static void InputSensorRegister(GF_Node *n)
     453             : {
     454             :         GF_ObjectManager *odm;
     455             :         GF_InputSensorCtx *is_ctx;
     456             :         u32 i;
     457          25 :         ISStack *st = (ISStack *)gf_node_get_private(n);
     458          25 :         odm = st->mo->odm;
     459          35 :         if (!odm || (odm->type != GF_STREAM_INTERACT)) return;
     460             : 
     461             :         assert(odm->type == GF_STREAM_INTERACT);
     462             : 
     463             :         /*get IS dec*/
     464          15 :         is_ctx = locate_is_ctx_for_odm(odm->parentscene, odm);
     465          15 :         if (!is_ctx) return;
     466             : 
     467          15 :         if ( gf_list_find(is_ctx->is_nodes, st) == -1 )
     468          15 :                 gf_list_add(is_ctx->is_nodes, st);
     469             : 
     470             :         /*start stream*/
     471          15 :         gf_mo_play(st->mo, 0, -1, 0);
     472             : 
     473          15 :         gf_sc_unqueue_node_traverse(is_ctx->odm->parentscene->compositor, n);
     474             : 
     475             :         /*we want at least one sensor enabled*/
     476          15 :         i=0;
     477          30 :         while ((st = gf_list_enum(is_ctx->is_nodes, &i))) {
     478          15 :                 if (st->is->enabled) {
     479          15 :                         st->registered = 1;
     480          15 :                         if (is_ctx->io_dev && is_ctx->io_dev->Start) is_ctx->io_dev->Start(is_ctx->io_dev);
     481             :                         break;
     482             :                 }
     483             :         }
     484             : }
     485             : 
     486         447 : static void TraverseInputSensor(GF_Node *node, void *rs, Bool is_destroy)
     487             : {
     488         447 :         ISStack *st = (ISStack*)gf_node_get_private(node);
     489             :         M_InputSensor *is = (M_InputSensor *)node;
     490             : 
     491         447 :         if (is_destroy) {
     492             :                 GF_Scene *scene;
     493          15 :                 if (st->registered) InputSensorUnregister(node, st);
     494          15 :                 scene = (GF_Scene*)gf_sg_get_private(gf_node_get_graph(node));
     495          15 :                 gf_sc_unqueue_node_traverse(scene->compositor, node);
     496          15 :                 gf_free(st);
     497         432 :         } else if (!st->registered) {
     498             :                 /*get decoder object */
     499          25 :                 if (!st->mo) st->mo = gf_mo_register(node, &is->url, 0, 0);
     500             :                 /*register with decoder*/
     501          25 :                 if (st->mo) InputSensorRegister(node);
     502             :         }
     503         447 : }
     504             : 
     505             : 
     506          15 : void InitInputSensor(GF_Scene *scene, GF_Node *node)
     507             : {
     508             :         ISStack *stack;
     509          15 :         GF_SAFEALLOC(stack, ISStack);
     510          15 :         if (!stack) {
     511           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Terminal] Failed to allocate input sensor stack\n"));
     512             :                 return;
     513             :         }
     514          15 :         stack->is = (M_InputSensor *) node;
     515          15 :         gf_node_set_private(node, stack);
     516          15 :         gf_node_set_callback_function(node, TraverseInputSensor);
     517             : 
     518          15 :         gf_sc_queue_node_traverse(scene->compositor, node);
     519             : }
     520             : 
     521             : /*check only URL changes*/
     522           3 : void InputSensorModified(GF_Node *node)
     523             : {
     524             :         GF_MediaObject *mo;
     525           3 :         ISStack *st = (ISStack *)gf_node_get_private(node);
     526             : 
     527           3 :         mo = gf_mo_register(node, &st->is->url, 0, 0);
     528           3 :         if ((mo!=st->mo) || !st->registered) {
     529           0 :                 if (mo!=st->mo) {
     530           0 :                         if (st->mo) InputSensorUnregister(node, st);
     531           0 :                         st->mo = mo;
     532             :                 }
     533           0 :                 if (st->is->enabled)
     534           0 :                         InputSensorRegister(node);
     535             :                 else
     536             :                         return;
     537           3 :         } else if (!st->is->enabled) {
     538           3 :                 InputSensorUnregister(node, st);
     539           3 :                 return;
     540             :         }
     541             : }
     542             : 
     543             : 
     544             : 
     545             : /*
     546             :                                 input sensor DDF generations (user interface)
     547             : */
     548             : GF_EXPORT
     549        3889 : void gf_sc_input_sensor_mouse_input(GF_Compositor *compositor, GF_EventMouse *event)
     550             : {
     551             :         s32 X, Y;
     552             :         u32 left_but_down, middle_but_down, right_but_down;
     553             :         SFFloat wheel_pos;
     554             :         u32 i;
     555             :         GF_BitStream *bs;
     556             :         u8 *buf;
     557             :         u32 buf_size;
     558             :         Fixed bX, bY;
     559             :         GF_InputSensorCtx *is_ctx;
     560             : 
     561        7716 :         if ( !gf_list_count(compositor->input_streams)) return;
     562             : 
     563          62 :         X = event->x;
     564          62 :         Y = event->y;
     565             :         left_but_down = middle_but_down = right_but_down = 0;
     566             :         wheel_pos = 0;
     567          62 :         switch (event->type) {
     568           2 :         case GF_EVENT_MOUSEDOWN:
     569           2 :                 if (event->button==GF_MOUSE_RIGHT) right_but_down = 2;
     570           1 :                 else if (event->button==GF_MOUSE_MIDDLE) middle_but_down = 2;
     571           1 :                 else if (event->button==GF_MOUSE_LEFT) left_but_down = 2;
     572             :                 break;
     573           2 :         case GF_EVENT_MOUSEUP:
     574           2 :                 if (event->button==GF_MOUSE_RIGHT) right_but_down = 1;
     575           1 :                 else if (event->button==GF_MOUSE_MIDDLE) middle_but_down = 1;
     576           1 :                 else if (event->button==GF_MOUSE_LEFT) left_but_down = 1;
     577             :                 break;
     578           0 :         case GF_EVENT_MOUSEWHEEL:
     579           0 :                 wheel_pos = event->wheel_pos;
     580           0 :                 break;
     581             :         case GF_EVENT_MOUSEMOVE:
     582             :                 break;
     583             :         default:
     584             :                 return;
     585             :         }
     586             : 
     587             :         /*get BIFS coordinates*/
     588          62 :         gf_sc_map_point(compositor, X, Y, &bX, &bY);
     589          62 :         bX = gf_divfix(bX, compositor->scale_x);
     590          62 :         bY = gf_divfix(bY, compositor->scale_y);
     591             : 
     592          62 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     593             : 
     594             :         /*If wheel is specified disable X and Y (bug from MS wheel handling)*/
     595          62 :         if (wheel_pos) {
     596           0 :                 gf_bs_write_int(bs, 0, 1);
     597             :         } else {
     598          62 :                 gf_bs_write_int(bs, 1, 1);
     599          62 :                 gf_bs_write_float(bs, FIX2FLT(bX));
     600          62 :                 gf_bs_write_float(bs, FIX2FLT(bY));
     601             :         }
     602          62 :         gf_bs_write_int(bs, left_but_down ? 1 : 0, 1);
     603          62 :         if (left_but_down) gf_bs_write_int(bs, left_but_down-1, 1);
     604          62 :         gf_bs_write_int(bs, middle_but_down ? 1 : 0, 1);
     605          62 :         if (middle_but_down) gf_bs_write_int(bs, middle_but_down-1, 1);
     606          62 :         gf_bs_write_int(bs, right_but_down ? 1 : 0, 1);
     607          62 :         if (right_but_down) gf_bs_write_int(bs, right_but_down-1, 1);
     608          62 :         if (wheel_pos==0) {
     609          62 :                 gf_bs_write_int(bs, 0, 1);
     610             :         } else {
     611           0 :                 gf_bs_write_int(bs, 1, 1);
     612           0 :                 gf_bs_write_float(bs, FIX2FLT(wheel_pos) );
     613             :         }
     614             : 
     615          62 :         gf_bs_align(bs);
     616          62 :         gf_bs_get_content(bs, &buf, &buf_size);
     617          62 :         gf_bs_del(bs);
     618             : 
     619             :         /*get all IS Mouse decoders and send frame*/
     620          62 :         i=0;
     621         186 :         while ((is_ctx = gf_list_enum(compositor->input_streams, &i))) {
     622          62 :                 if (is_ctx->type==IS_Mouse) {
     623          36 :                         IS_ProcessData(is_ctx, buf, buf_size);
     624             :                 }
     625             :         }
     626          62 :         gf_free(buf);
     627             : }
     628             : 
     629             : GF_EXPORT
     630         146 : Bool gf_sc_input_sensor_keyboard_input(GF_Compositor *compositor, u32 key_code, u32 hw_code, Bool isKeyUp)
     631             : {
     632             :         u32 i;
     633             :         GF_BitStream *bs;
     634             :         GF_SLHeader slh;
     635             :         u8 *buf;
     636             : #ifndef GPAC_DISABLE_X3D
     637             :         X_KeySensor *n;
     638             : #endif
     639             :         GF_InputSensorCtx *is_ctx;
     640             :         u32 buf_size;
     641             :         u32 actionKey = 0;
     642             :         u32 shiftKeyDown, controlKeyDown, altKeyDown;
     643             :         s32 keyPressed, keyReleased, actionKeyPressed, actionKeyReleased;
     644             : 
     645         146 :         if (!gf_list_count(compositor->input_streams) && !gf_list_count(compositor->x3d_sensors)) return 0;
     646             : 
     647             :         memset(&slh, 0, sizeof(GF_SLHeader));
     648          37 :         slh.accessUnitStartFlag = slh.accessUnitEndFlag = 1;
     649          37 :         slh.compositionTimeStampFlag = 1;
     650             :         /*cf above*/
     651             :         slh.compositionTimeStamp = 0;
     652             : 
     653          37 :         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     654             : 
     655             :         shiftKeyDown = controlKeyDown = altKeyDown = 0;
     656             :         keyPressed = keyReleased = actionKeyPressed = actionKeyReleased = 0;
     657             :         /*key-sensor codes*/
     658          37 :         switch (key_code) {
     659             :         case GF_KEY_F1:
     660             :                 actionKey = 1;
     661             :                 break;
     662           2 :         case GF_KEY_F2:
     663             :                 actionKey = 2;
     664           2 :                 break;
     665           2 :         case GF_KEY_F3:
     666             :                 actionKey = 3;
     667           2 :                 break;
     668           0 :         case GF_KEY_F4:
     669             :                 actionKey = 4;
     670           0 :                 break;
     671           0 :         case GF_KEY_F5:
     672             :                 actionKey = 5;
     673           0 :                 break;
     674           0 :         case GF_KEY_F6:
     675             :                 actionKey = 6;
     676           0 :                 break;
     677           0 :         case GF_KEY_F7:
     678             :                 actionKey = 7;
     679           0 :                 break;
     680           0 :         case GF_KEY_F8:
     681             :                 actionKey = 8;
     682           0 :                 break;
     683           0 :         case GF_KEY_F9:
     684             :                 actionKey = 9;
     685           0 :                 break;
     686           0 :         case GF_KEY_F10:
     687             :                 actionKey = 10;
     688           0 :                 break;
     689           0 :         case GF_KEY_F11:
     690             :                 actionKey = 11;
     691           0 :                 break;
     692           0 :         case GF_KEY_F12:
     693             :                 actionKey = 12;
     694           0 :                 break;
     695           0 :         case GF_KEY_HOME:
     696             :                 actionKey = 13;
     697           0 :                 break;
     698           0 :         case GF_KEY_END:
     699             :                 actionKey = 14;
     700           0 :                 break;
     701           0 :         case GF_KEY_PAGEUP:
     702             :                 actionKey = 15;
     703           0 :                 break;
     704           0 :         case GF_KEY_PAGEDOWN:
     705             :                 actionKey = 16;
     706           0 :                 break;
     707           0 :         case GF_KEY_UP:
     708             :                 actionKey = 17;
     709           0 :                 break;
     710           0 :         case GF_KEY_DOWN:
     711             :                 actionKey = 18;
     712           0 :                 break;
     713           0 :         case GF_KEY_LEFT:
     714             :                 actionKey = 19;
     715           0 :                 break;
     716           0 :         case GF_KEY_RIGHT:
     717             :                 actionKey = 20;
     718           0 :                 break;
     719           3 :         case GF_KEY_SHIFT:
     720             :                 actionKey = 0;
     721           3 :                 shiftKeyDown = isKeyUp ? 1 : 2;
     722             :                 break;
     723           0 :         case GF_KEY_CONTROL:
     724             :                 actionKey = 0;
     725           0 :                 controlKeyDown = isKeyUp ? 1 : 2;
     726             :                 break;
     727           0 :         case GF_KEY_ALT:
     728             :                 actionKey = 0;
     729           0 :                 altKeyDown = isKeyUp ? 1 : 2;
     730             :                 break;
     731             : 
     732          28 :         default:
     733             :                 actionKey = 0;
     734          28 :                 break;
     735             :         }
     736          37 :         if (actionKey) {
     737           6 :                 if (isKeyUp)
     738           3 :                         actionKeyReleased = actionKey;
     739             :                 else
     740           3 :                         actionKeyPressed = actionKey;
     741             :         } else {
     742             :                 /*handle numeric pad*/
     743          31 :                 if ((key_code>=GF_KEY_0) && (key_code<=GF_KEY_9) ) {
     744           0 :                         key_code = key_code + 0x30 - GF_KEY_0;
     745             :                 }
     746             :                 else
     747             :                         key_code = hw_code;
     748             : 
     749          31 :                 if (isKeyUp) keyReleased = key_code;
     750          16 :                 else keyPressed = key_code;
     751             :         }
     752             : 
     753          37 :         gf_bs_write_int(bs, keyPressed ? 1 : 0, 1);
     754          37 :         if (keyPressed) gf_bs_write_int(bs, keyPressed, 32);
     755          37 :         gf_bs_write_int(bs, keyReleased ? 1 : 0, 1);
     756          37 :         if (keyReleased) gf_bs_write_int(bs, keyReleased, 32);
     757          37 :         gf_bs_write_int(bs, actionKeyPressed ? 1 : 0, 1);
     758          37 :         if (actionKeyPressed) gf_bs_write_int(bs, actionKeyPressed, 32);
     759          37 :         gf_bs_write_int(bs, actionKeyReleased ? 1 : 0, 1);
     760          37 :         if (actionKeyReleased) gf_bs_write_int(bs, actionKeyReleased, 32);
     761          37 :         gf_bs_write_int(bs, shiftKeyDown ? 1 : 0 , 1);
     762          37 :         if (shiftKeyDown) gf_bs_write_int(bs, shiftKeyDown-1, 1);
     763          37 :         gf_bs_write_int(bs, controlKeyDown ? 1 : 0 , 1);
     764          37 :         if (controlKeyDown) gf_bs_write_int(bs, controlKeyDown-1, 1);
     765          37 :         gf_bs_write_int(bs, altKeyDown ? 1 : 0 , 1);
     766          37 :         if (altKeyDown) gf_bs_write_int(bs, altKeyDown, 1);
     767             : 
     768          37 :         gf_bs_align(bs);
     769          37 :         gf_bs_get_content(bs, &buf, &buf_size);
     770          37 :         gf_bs_del(bs);
     771             : 
     772             :         /*get all IS keySensor decoders and send frame*/
     773          37 :         i=0;
     774         111 :         while ((is_ctx = gf_list_enum(compositor->input_streams, &i))) {
     775          37 :                 if (is_ctx->type==IS_KeySensor) {
     776           9 :                         IS_ProcessData(is_ctx, buf, buf_size);
     777             :                 }
     778             :         }
     779          37 :         gf_free(buf);
     780             : 
     781             : #ifndef GPAC_DISABLE_X3D
     782          37 :         i=0;
     783          74 :         while ((n = (X_KeySensor*)gf_list_enum(compositor->x3d_sensors, &i))) {
     784             :                 u16 tc[2];
     785             :                 u32 len;
     786             :                 char szStr[10];
     787             :                 const unsigned short *ptr;
     788           0 :                 if (gf_node_get_tag((GF_Node*)n) != TAG_X3D_KeySensor) continue;
     789           0 :                 if (!n->enabled) return 0;
     790             : 
     791           0 :                 if (keyPressed) {
     792           0 :                         if (n->keyPress.buffer) gf_free(n->keyPress.buffer);
     793           0 :                         tc[0] = keyPressed;
     794           0 :                         tc[1] = 0;
     795           0 :                         ptr = tc;
     796           0 :                         len = (u32) gf_utf8_wcstombs(szStr, 10, &ptr);
     797           0 :                         n->keyPress.buffer = (char*)gf_malloc(sizeof(char) * (len+1));
     798             :                         memcpy(n->keyPress.buffer, szStr, sizeof(char) * len);
     799           0 :                         n->keyPress.buffer[len] = 0;
     800           0 :                         gf_node_event_out_str((GF_Node *)n, "keyPress");
     801             :                 }
     802           0 :                 if (keyReleased) {
     803           0 :                         if (n->keyRelease.buffer) gf_free(n->keyRelease.buffer);
     804           0 :                         tc[0] = keyReleased;
     805           0 :                         tc[1] = 0;
     806           0 :                         ptr = tc;
     807           0 :                         len = (u32) gf_utf8_wcstombs(szStr, 10, &ptr);
     808           0 :                         n->keyRelease.buffer = (char*)gf_malloc(sizeof(char) * (len+1));
     809             :                         memcpy(n->keyRelease.buffer, szStr, sizeof(char) * len);
     810           0 :                         n->keyRelease.buffer[len] = 0;
     811           0 :                         gf_node_event_out_str((GF_Node *)n, "keyRelease");
     812             :                 }
     813           0 :                 if (actionKeyPressed) {
     814           0 :                         n->actionKeyPress = actionKeyPressed;
     815           0 :                         gf_node_event_out_str((GF_Node *)n, "actionKeyPress");
     816             :                 }
     817           0 :                 if (actionKeyReleased) {
     818           0 :                         n->actionKeyRelease = actionKeyReleased;
     819           0 :                         gf_node_event_out_str((GF_Node *)n, "actionKeyRelease");
     820             :                 }
     821           0 :                 if (shiftKeyDown) {
     822           0 :                         n->shiftKey = (shiftKeyDown-1) ? 1 : 0;
     823           0 :                         gf_node_event_out_str((GF_Node *)n, "shiftKey");
     824             :                 }
     825           0 :                 if (controlKeyDown) {
     826           0 :                         n->controlKey = (controlKeyDown-1) ? 1 : 0;
     827           0 :                         gf_node_event_out_str((GF_Node *)n, "controlKey");
     828             :                 }
     829           0 :                 if (altKeyDown) {
     830           0 :                         n->altKey= (altKeyDown-1) ? 1 : 0;
     831           0 :                         gf_node_event_out_str((GF_Node *)n, "altKey");
     832             :                 }
     833           0 :                 if (keyPressed || actionKeyPressed || (shiftKeyDown-1) || (controlKeyDown-1) || (altKeyDown-1)) {
     834           0 :                         if (!n->isActive) {
     835           0 :                                 n->isActive = 1;
     836           0 :                                 gf_node_event_out_str((GF_Node *)n, "isActive");
     837             :                         }
     838           0 :                 } else if (n->isActive) {
     839           0 :                         n->isActive = 0;
     840           0 :                         gf_node_event_out_str((GF_Node *)n, "isActive");
     841             :                 }
     842             :         }
     843             : #endif
     844             :         /*with KeySensor, we don't know if the key will be consumed or not, assume it is*/
     845             :         return 1;
     846             : }
     847             : 
     848             : GF_EXPORT
     849          14 : void gf_sc_input_sensor_string_input(GF_Compositor *compositor, u32 character)
     850             : {
     851             :         u32 i;
     852             :         GF_BitStream *bs;
     853             : #ifndef GPAC_DISABLE_X3D
     854             :         X_StringSensor *n;
     855             : #endif
     856             :         GF_InputSensorCtx *is_ctx;
     857             :         u8 *buf;
     858             :         u32 buf_size;
     859             : 
     860          14 :         if (!character) return;
     861          14 :         if (!gf_list_count(compositor->input_streams) && !gf_list_count(compositor->x3d_sensors)) return;
     862             : 
     863             :         /*get all IS StringSensor decoders and send frame*/
     864          14 :         i=0;
     865          42 :         while ((is_ctx = gf_list_enum(compositor->input_streams, &i))) {
     866          14 :                 if (is_ctx->type==IS_StringSensor) {
     867          14 :                         is_ctx->enteredText[is_ctx->text_len] = character;
     868          14 :                         is_ctx->text_len += 1;
     869             : 
     870             :                         /*write empty DDF*/
     871          14 :                         bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     872          14 :                         gf_bs_write_int(bs, 0, 1);
     873          14 :                         gf_bs_write_int(bs, 0, 1);
     874          14 :                         gf_bs_align(bs);
     875          14 :                         gf_bs_get_content(bs, &buf, &buf_size);
     876          14 :                         gf_bs_del(bs);
     877             : 
     878          14 :                         IS_ProcessData(is_ctx, buf, buf_size);
     879             : 
     880          14 :                         gf_free(buf);
     881             :                 }
     882             :         }
     883             : 
     884             : 
     885             : #ifndef GPAC_DISABLE_X3D
     886             :         /*get all X3D StringSensors*/
     887          14 :         i=0;
     888          28 :         while ((n = (X_StringSensor*)gf_list_enum(compositor->x3d_sensors, &i))) {
     889             :                 StringSensorStack *st;
     890             :                 char szStr[5000];
     891             :                 const unsigned short *ptr;
     892             :                 u32 len;
     893           0 :                 if (gf_node_get_tag((GF_Node*)n) != TAG_X3D_StringSensor) continue;
     894           0 :                 if (!n->enabled) continue;
     895             : 
     896           0 :                 st = (StringSensorStack *) gf_node_get_private((GF_Node *)n);
     897             : 
     898           0 :                 if (character=='\b') {
     899           0 :                         if (n->deletionAllowed && st->text_len) {
     900           0 :                                 st->text_len -= 1;
     901           0 :                                 st->enteredText[st->text_len] = 0;
     902           0 :                                 ptr = st->enteredText;
     903           0 :                                 len = (u32) gf_utf8_wcstombs(szStr, 10, &ptr);
     904           0 :                                 if (n->enteredText.buffer) gf_free(n->enteredText.buffer);
     905           0 :                                 szStr[len] = 0;
     906           0 :                                 n->enteredText.buffer = gf_strdup(szStr);
     907           0 :                                 gf_node_event_out_str((GF_Node *)n, "enteredText");
     908             :                         }
     909           0 :                 } else if (character=='\r') {
     910           0 :                         if (n->finalText.buffer) gf_free(n->finalText.buffer);
     911           0 :                         n->finalText.buffer = n->enteredText.buffer;
     912           0 :                         n->enteredText.buffer = gf_strdup("");
     913           0 :                         st->text_len = 0;
     914           0 :                         gf_node_event_out_str((GF_Node *)n, "enteredText");
     915           0 :                         gf_node_event_out_str((GF_Node *)n, "finalText");
     916             :                 } else {
     917           0 :                         st->enteredText[st->text_len] = character;
     918           0 :                         st->text_len += 1;
     919           0 :                         st->enteredText[st->text_len] = 0;
     920           0 :                         ptr = st->enteredText;
     921           0 :                         len = (u32) gf_utf8_wcstombs(szStr, 10, &ptr);
     922           0 :                         if (n->enteredText.buffer) gf_free(n->enteredText.buffer);
     923           0 :                         szStr[len] = 0;
     924           0 :                         n->enteredText.buffer = gf_strdup(szStr);
     925           0 :                         gf_node_event_out_str((GF_Node *)n, "enteredText");
     926             :                 }
     927             :         }
     928             : #endif
     929             : }
     930             : 
     931             : #ifndef GPAC_DISABLE_X3D
     932             : 
     933           6 : void DestroyKeySensor(GF_Node *node, void *rs, Bool is_destroy)
     934             : {
     935           6 :         if (is_destroy) {
     936           1 :                 GF_Compositor *compositor = (GF_Compositor *) gf_node_get_private(node);
     937           1 :                 gf_list_del_item(compositor->x3d_sensors, node);
     938             :         }
     939           6 : }
     940           1 : void InitKeySensor(GF_Scene *scene, GF_Node *node)
     941             : {
     942           1 :         gf_node_set_private(node, scene->compositor);
     943           1 :         gf_node_set_callback_function(node, DestroyKeySensor);
     944           1 :         if (!scene->compositor->x3d_sensors)
     945           1 :                 scene->compositor->x3d_sensors = gf_list_new();
     946             : 
     947           1 :         gf_list_add(scene->compositor->x3d_sensors, node);
     948           1 : }
     949             : 
     950           6 : void DestroyStringSensor(GF_Node *node, void *rs, Bool is_destroy)
     951             : {
     952           6 :         if (is_destroy) {
     953           1 :                 StringSensorStack *st = (StringSensorStack *) gf_node_get_private(node);
     954           1 :                 gf_list_del_item(st->compositor->x3d_sensors, node);
     955           1 :                 gf_free(st);
     956             :         }
     957           6 : }
     958           1 : void InitStringSensor(GF_Scene *scene, GF_Node *node)
     959             : {
     960             :         StringSensorStack*st;
     961           1 :         GF_SAFEALLOC(st, StringSensorStack)
     962           1 :         if (!st) {
     963           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Terminal] Failed to allocate string sensor stack\n"));
     964             :                 return;
     965             :         }
     966           1 :         st->compositor = scene->compositor;
     967           1 :         gf_node_set_private(node, st);
     968           1 :         gf_node_set_callback_function(node, DestroyStringSensor);
     969             : 
     970           1 :         if (!scene->compositor->x3d_sensors)
     971           1 :                 scene->compositor->x3d_sensors = gf_list_new();
     972             : 
     973           1 :         gf_list_add(scene->compositor->x3d_sensors, node);
     974             : }
     975             : 
     976             : #endif /*GPAC_DISABLE_X3D*/
     977             : 
     978             : #else
     979             : GF_EXPORT
     980             : void gf_sc_input_sensor_mouse_input(GF_Compositor *compositor, GF_EventMouse *event)
     981             : {
     982             : }
     983             : GF_EXPORT
     984             : Bool gf_sc_input_sensor_keyboard_input(GF_Compositor *compositor, u32 key_code, u32 hw_code, Bool isKeyUp)
     985             : {
     986             :         return GF_TRUE;
     987             : }
     988             : GF_EXPORT
     989             : void gf_sc_input_sensor_string_input(GF_Compositor *compositor, u32 character)
     990             : {
     991             : }
     992             : 
     993             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13