手机探索者开发实录—Broncho支持VNC

手机探索者开发实录—Broncho支持VNC

转载时请注明出处和作者联系方式
作者联系方式:李先静 <xianjimli at hotmail dot com>

在前段时间写的一篇BLOG中,我介绍了DirectFB同时显示到X11和VNC的方法。那是一个有趣的实验,为此我兴奋了好一会儿,不过没有什么太大的实用价值,因为broncho平台使用的GTK/DirectFB作为GUI,显示通过fbdev(framebuffer)输出到LCD。我们要做的是让DirectFB同时显示到fbdev和VNC上,这个功能作为手机探索者的一部分,现在是实现的时候了。这并不难,由于一些小问题,我还是花了一整天时间才搞定。

一、 下载libVNCServer,然后编译和安装。要确保通过环境变量PATH能找到vncserver的配置脚本。

二、 为DirectFB创建fbvnc的system模块。

1. 把fbdev拷贝为fbvnc,把所有的文件名、变量名和函数名,从fbdev改名为fbvnc。
2. 修改fbvnc.c,包含下列头文件

  1. #include <direct/thread.h>
  2. #include <core/input.h>
  3. #include <rfb/rfb.h>
  4. #include <rfb/keysym.h

3. 修改fbvnc.c,声明下列函数和变量。
  1. static rfbScreenInfoPtr rfb_screen = NULL;
  2. static CoreInputDevice *vncPointerDevice = NULL;
  3. static CoreInputDevice *vncKeyboardDevice = NULL;
  4. static int g_vnc_client_nr = 0;

  5. typedef struct _ClientData
  6. {
  7.      int oldButtonMask;
  8.      int pressed;
  9.      int oldx;
  10.      int oldy;
  11. } ClientData;

  12. static void  vnc_client_gone(rfbClientPtr cl);
  13. static enum  rfbNewClientAction vnc_client_new(rfbClientPtr cl);
  14. static bool  vnc_translate_key(rfbKeySym key, DFBInputEvent *evt);
  15. static void* vnc_server_thread( DirectThread *thread, void *data);
  16. static void* vnc_refresh_thread( DirectThread *thread, void *data);
  17. static void  vnc_process_key_event(rfbBool down, rfbKeySym key, struct _rfbClientRec* cl);
  18. static void  vnc_process_pointer_event(int buttonMask, int x, int y, struct _rfbClientRec* cl);
  19. static DFBResult vnc_update_screen(unsigned short* src, int x, int y, int w, int h );
  20. static DFBResult vnc_set_video_mode(DFBDisplayLayerConfig *config );
  21. static DFBEnumerationResult vnc_attach_keyboard_device( CoreInputDevice *device, void *ctx );
  22. static DFBEnumerationResult vnc_attach_pointer_device( CoreInputDevice *device, void *ctx );

4. 修改fbvnc.c,在primaryInitLayer中调用vnc_set_video_mode。

5. 修改fbvnc.c,实现下列函数。
  1. static DFBEnumerationResult
  2. vnc_attach_keyboard_device( CoreInputDevice *device,
  3.                       void            *ctx )
  4. {
  5.   vncKeyboardDevice = device;
  6.   return DFENUM_OK;
  7. }

  8. static DFBEnumerationResult
  9. vnc_attach_pointer_device( CoreInputDevice *device,
  10.                       void            *ctx )
  11. {
  12.   vncPointerDevice = device;

  13.   return DFENUM_OK;
  14. }
  15. static void vnc_client_gone(rfbClientPtr cl)
  16. {
  17.   g_vnc_client_nr--;
  18.   free(cl->clientData);

  19.   return;
  20. }

  21. static enum rfbNewClientAction vnc_client_new(rfbClientPtr cl)
  22. {
  23.   g_vnc_client_nr++;
  24.   cl->clientData = (void*)calloc(sizeof(ClientData),1);
  25.   cl->clientGoneHook = vnc_client_gone;
  26.   return RFB_CLIENT_ACCEPT;
  27. }


  28. static void 
  29. vnc_process_pointer_event(int buttonMask, int x, int y, rfbClientPtr cl)
  30. {

  31.     DFBInputEvent evt = {0};
  32.     int button = 0;

  33.     if( vncPointerDevice == NULL ){
  34.         /* Attach to first input device */
  35.         dfb_input_enumerate_devices( vnc_attach_pointer_device,NULL, 
  36.           DICAPS_BUTTONS|DICAPS_AXES);
  37.         D_ASSERT(vncPointerDevice); 
  38.     }

  39.     ClientData* cd=cl->clientData;
  40.     if(buttonMask != cd->oldButtonMask ) {
  41.         int mask = buttonMask^cd->oldButtonMask;
  42.         if( mask & (1 << 0)) { 
  43.             button=DIBI_LEFT;
  44.         } else if( mask & (1 << 1)) {
  45.             button=DIBI_MIDDLE;
  46.         } else if( mask & (1 << 2)) {
  47.             button=DIBI_RIGHT;
  48.         } else {
  49.             return;
  50.         }
  51.         evt.flags = DIEF_NONE;
  52.                 
  53.         if(cd->pressed) 
  54.         {
  55.             evt.type = DIET_BUTTONRELEASE;
  56.             cd->pressed=0;
  57.             cd->oldButtonMask = 0;
  58.         }else {
  59.             evt.type = DIET_BUTTONPRESS;
  60.             cd->pressed=1;
  61.             cd->oldButtonMask=buttonMask;
  62.         }
  63.         evt.button=button;
  64.         printf("%s %d %d %d %d/n", __func__, button, cd->pressed, x, y);
  65.         dfb_input_dispatch( vncPointerDevice, &evt );
  66.         cd->oldx=x; 
  67.         cd->oldy=y; 
  68.         return;
  69.     }

  70.     evt.type    = DIET_AXISMOTION;
  71.     evt.flags   = DIEF_AXISABS;

  72.     if( cd->oldx != x ) {
  73.           evt.axis    = DIAI_X;
  74.           evt.axisabs = x;
  75.           dfb_input_dispatch( vncPointerDevice, &evt );
  76.     }

  77.     if( cd->oldy != y ) {
  78.           evt.axis    = DIAI_Y;
  79.           evt.axisabs = y;
  80.           dfb_input_dispatch( vncPointerDevice, &evt );
  81.     }
  82.     cd->oldx=x; 
  83.     cd->oldy=y; 

  84.     dfb_input_dispatch( vncPointerDevice, &evt );
  85.     rfbDefaultPtrAddEvent(buttonMask,x,y,cl);

  86. }

  87. /*
  88.  * declaration of private data
  89.  */
  90. static void
  91. vnc_process_key_event(rfbBool down, rfbKeySym key, rfbClientPtr cl)
  92. {
  93.     DFBInputEvent evt;
  94.     if( vncKeyboardDevice == NULL ){
  95.         /* Attach to first input device */
  96.         dfb_input_enumerate_devices( vnc_attach_keyboard_device,NULL, DICAPS_KEYS);
  97.         D_ASSERT(vncKeyboardDevice); 
  98.     }
  99.      if (down)
  100.           evt.type = DIET_KEYPRESS;
  101.      else
  102.           evt.type = DIET_KEYRELEASE;
  103.                                                                                   
  104.      if (vnc_translate_key( key, &evt )) {
  105.           dfb_input_dispatch( vncKeyboardDevice, &evt );
  106.      }

  107. }


  108. static bool
  109. vnc_translate_key(rfbKeySym key, DFBInputEvent *evt )
  110. {
  111.      /* Unicode */
  112.      if (key <= 0xf000) {
  113.          evt->flags = DIEF_KEYSYMBOL;
  114.          evt->key_symbol = key;
  115.          return true;
  116.      }

  117.      /* Dead keys */
  118.      /* todo */     

  119.      /* Numeric keypad */
  120.      if (key >= XK_KP_0  &&  key <= XK_KP_9) {
  121.           evt->flags = DIEF_KEYID;
  122.           evt->key_id = DIKI_KP_0 + key - XK_KP_0;
  123.           return true;
  124.      }

  125.      /* Function keys */
  126.      if (key >= XK_F1  &&  key <= XK_F11) {
  127.           evt->flags = DIEF_KEYID;
  128.           evt->key_id = DIKI_F1 + key - XK_F1;
  129.           return true;
  130.      }

  131.      switch (key) {
  132.           /* Numeric keypad */
  133.           case XK_KP_Decimal:
  134.                evt->flags = DIEF_KEYID;
  135.                evt->key_id = DIKI_KP_DECIMAL;
  136.                break;

  137.           case XK_KP_Separator:
  138.                evt->flags = DIEF_KEYID;
  139.                evt->key_id = DIKI_KP_SEPARATOR;
  140.                break;

  141.           case XK_KP_Divide:
  142.                evt->flags = DIEF_KEYID;
  143.                evt->key_id = DIKI_KP_DIV;
  144.                break;

  145.           case XK_KP_Multiply:
  146.                evt->flags = DIEF_KEYID;
  147.                evt->key_id = DIKI_KP_MULT;
  148.                break;

  149.           case XK_KP_Subtract:
  150.                evt->flags = DIEF_KEYID;
  151.                evt->key_id = DIKI_KP_MINUS;
  152.                break;

  153.           case XK_KP_Add:
  154.                evt->flags = DIEF_KEYID;
  155.                evt->key_id = DIKI_KP_PLUS;
  156.                break;

  157.           case XK_KP_Enter:
  158.                evt->flags = DIEF_KEYID;
  159.                evt->key_id = DIKI_KP_ENTER;
  160.                break;

  161.           case XK_KP_Equal:
  162.                evt->flags = DIEF_KEYID;
  163.                evt->key_id = DIKI_KP_EQUAL;
  164.                break;


  165.           /* Arrows + Home/End pad */
  166.           case XK_Up:
  167.                evt->flags = DIEF_KEYID;
  168.                evt->key_id = DIKI_UP;
  169.                break;

  170.           case XK_Down:
  171.                evt->flags = DIEF_KEYID;
  172.                evt->key_id = DIKI_DOWN;
  173.                break;

  174.           case XK_Right:
  175.                evt->flags = DIEF_KEYID;
  176.                evt->key_id = DIKI_RIGHT;
  177.                break;

  178.           case XK_Left:
  179.                evt->flags = DIEF_KEYID;
  180.                evt->key_id = DIKI_LEFT;
  181.                break;

  182.           case XK_Insert:
  183.                evt->flags = DIEF_KEYID;
  184.                evt->key_id = DIKI_INSERT;
  185.                break;
  186.                                                                                 
  187.           case XK_Delete:
  188.                evt->flags = DIEF_KEYID;
  189.                evt->key_id = DIKI_DELETE;
  190.                break;

  191.           case XK_Home:
  192.                evt->flags = DIEF_KEYID;
  193.                evt->key_id = DIKI_HOME;
  194.                break;

  195.           case XK_End:
  196.                evt->flags = DIEF_KEYID;
  197.                evt->key_id = DIKI_END;
  198.                break;

  199.           case XK_Page_Up:
  200.                evt->flags = DIEF_KEYID;
  201.                evt->key_id = DIKI_PAGE_UP;
  202.                break;

  203.           case XK_Page_Down:
  204.                evt->flags = DIEF_KEYID;
  205.                evt->key_id = DIKI_PAGE_DOWN;
  206.                break;


  207.           /* Key state modifier keys */
  208.           case XK_Num_Lock:
  209.                evt->flags = DIEF_KEYID;
  210.                evt->key_id = DIKI_NUM_LOCK;
  211.                break;

  212.           case XK_Caps_Lock:
  213.                evt->flags = DIEF_KEYID;
  214.                evt->key_id = DIKI_CAPS_LOCK;
  215.                break;

  216.           case XK_Scroll_Lock:
  217.                evt->flags = DIEF_KEYID;
  218.                evt->key_id = DIKI_SCROLL_LOCK;
  219.                break;

  220.           case XK_Shift_R:
  221.                evt->flags = DIEF_KEYID;
  222.                evt->key_id = DIKI_SHIFT_R;
  223.                break;

  224.           case XK_Shift_L:
  225.                evt->flags = DIEF_KEYID;
  226.                evt->key_id = DIKI_SHIFT_L;
  227.                break;

  228.           case XK_Control_R:
  229.                evt->flags = DIEF_KEYID;
  230.                evt->key_id = DIKI_CONTROL_R;
  231.                break;

  232.           case XK_Control_L:
  233.                evt->flags = DIEF_KEYID;
  234.                evt->key_id = DIKI_CONTROL_L;
  235.                break;

  236.           case XK_Alt_R:
  237.                evt->flags = DIEF_KEYID;
  238.                evt->key_id = DIKI_ALT_R;
  239.                break;

  240.           case XK_Alt_L:
  241.                evt->flags = DIEF_KEYID;
  242.                evt->key_id = DIKI_ALT_L;
  243.                break;

  244.           case XK_Meta_R:
  245.                evt->flags = DIEF_KEYID;
  246.                evt->key_id = DIKI_META_R;
  247.                break;

  248.           case XK_Meta_L:
  249.                evt->flags = DIEF_KEYID;
  250.                evt->key_id = DIKI_META_L;
  251.                break;

  252.           case XK_Super_L:
  253.                evt->flags = DIEF_KEYID;
  254.                evt->key_id = DIKI_SUPER_L;
  255.                break;

  256.           case XK_Super_R:
  257.                evt->flags = DIEF_KEYID;
  258.                evt->key_id = DIKI_SUPER_R;
  259.                break;

  260.           case XK_Hyper_L:
  261.                evt->flags = DIEF_KEYID;
  262.                evt->key_id = DIKI_HYPER_L;
  263.                break;
  264.                                                                                 
  265.           case XK_Hyper_R:
  266.                evt->flags = DIEF_KEYID;
  267.                evt->key_id = DIKI_HYPER_R;
  268.                break;

  269.           /*case ??:
  270.                evt->flags = DIEF_KEYID;
  271.                evt->key_id = DIKI_ALTGR;
  272.                break;*/

  273.           case XK_BackSpace:
  274.                evt->flags = DIEF_KEYID;
  275.                evt->key_id = DIKI_BACKSPACE;
  276.                break;

  277.           case XK_Tab:
  278.                evt->flags = DIEF_KEYID;
  279.                evt->key_id = DIKI_HYPER_L;
  280.                break;

  281.           case XK_Return:
  282.                evt->flags = DIEF_KEYID;
  283.                evt->key_id = DIKI_ENTER;
  284.                break;

  285.           case XK_Escape:
  286.                evt->flags = DIEF_KEYID;
  287.                evt->key_id = DIKI_ESCAPE;
  288.                     break;

  289.           case XK_Pause:
  290.                evt->flags = DIEF_KEYID;
  291.                evt->key_id = DIKI_PAUSE;
  292.                break;

  293.           /* Miscellaneous function keys */
  294.           case XK_Help:
  295.                evt->flags = DIEF_KEYSYMBOL;
  296.                evt->key_symbol = DIKS_HELP;
  297.                break;

  298.           case XK_Print:
  299.                evt->flags = DIEF_KEYSYMBOL;
  300.                evt->key_symbol = DIKS_PRINT;
  301.                break;

  302.           case XK_Break:
  303.                evt->flags = DIEF_KEYSYMBOL;
  304.                evt->key_symbol = DIKS_BREAK;
  305.                break;

  306.           default:
  307.                return false;
  308.      }

  309.      return true;
  310. }

  311. #define RGB16_TO_RGB32(pixel)  ( (((pixel) & 0xF800) << 8) | /
  312.                                  (((pixel) & 0x07E0) << 5) | /
  313.                                  (((pixel) & 0x001F) << 3) )

  314. static DFBResult
  315. vnc_update_screen(unsigned short* src, int x, int y, int w, int h )
  316. {
  317.      int i = 0;
  318.      int j = 0;
  319.      D_ASSERT( rfb_screen != NULL );
  320.      D_ASSERT( rfb_screen->frameBuffer != NULL );

  321.      if(g_vnc_client_nr <= 0 
  322.        || src == NULL
  323.        || rfb_screen == NULL 
  324.        || rfb_screen->frameBuffer == NULL)
  325.      {
  326.            return DFB_FALSE;
  327.      }

  328.      int d_bpp = 4;
  329.      char* dst = rfb_screen->frameBuffer;
  330.      char* src_line = src;
  331.      char* src_row  = src;
  332.      char* dst_line = dst;
  333.      char* dst_row  = dst;
  334.      struct fb_fix_screeninfo* fix = &(dfb_fbvnc->shared->fix);
  335.      struct fb_var_screeninfo* var = &(dfb_fbvnc->shared->current_var);
  336.      int s_bpp = (var->bits_per_pixel + 7) / 8;

  337.      if(w > var->xres_virtual
  338.       || h > var->yres_virtual)
  339.      {
  340.            return DFB_FALSE;
  341.      }

  342.      for (i = y; i < h; i++)
  343.      {    
  344.           src_row = src_line;
  345.           dst_row = dst_line;
  346.           for(j = x; j < w; j++)
  347.           {
  348.                src_row += s_bpp;   
  349.                dst_row += d_bpp;
  350.                *(int*)dst_row = RGB16_TO_RGB32(*(short*)src_row);
  351.           }

  352.           src_line += fix->line_length;
  353.           dst_line = dst_row;
  354.      }
  355.      rfbMarkRectAsModified ( rfb_screen, x, y, x+w, y+h );

  356.      return DFB_OK;
  357. }

  358. DFBResult
  359. vnc_set_video_mode(DFBDisplayLayerConfig *config )
  360. {
  361.      int argc = 0;
  362.      char** argv = NULL;
  363.      struct fb_var_screeninfo* var = &(dfb_fbvnc->shared->current_var);
  364.      int height = var->yres_virtual;
  365.      int width = var->xres_virtual;

  366.      D_DEBUG( "DirectFB/VNC: layer config properties/n");

  367.      if(rfb_screen) return DFB_OK;

  368.      rfb_screen = rfbGetScreen(&argc, argv, width, height, 8, 3, 4);
  369.     
  370.      if ( rfb_screen == NULL )
  371.      {
  372.              D_ERROR( "DirectFB/VNC: Couldn't set %dx%dx%d video mode/n",
  373.                       config->width, config->height,
  374.                       config->pixelformat);

  375.              return DFB_FAILURE;
  376.      }
  377.     
  378.      rfb_screen->frameBuffer = malloc(width*height*rfb_screen->depth/8) ;
  379.      
  380.      rfb_screen->kbdAddEvent = vnc_process_key_event;
  381.      rfb_screen->ptrAddEvent = vnc_process_pointer_event;
  382.      rfb_screen->newClientHook = vnc_client_new;
  383.      
  384.      rfbInitServer(rfb_screen);
  385.      
  386.      direct_thread_create( DTT_OUTPUT, vnc_server_thread, rfb_screen, "VNC Output" ); 
  387.      direct_thread_create( DTT_OUTPUT, vnc_refresh_thread, rfb_screen, "VNC Refresh" );
  388.  
  389.      return DFB_OK;
  390. }

  391. static void*
  392. vnc_server_thread( DirectThread *thread, void *data )
  393. {
  394.    rfbRunEventLoop(rfb_screen, -1, FALSE); 

  395.    return NULL;
  396. }

  397. static void*
  398. vnc_refresh_thread( DirectThread *thread, void *data )
  399. {
  400.    while(1) 
  401.    {
  402.       if(dfb_fbvnc != NULL && dfb_fbvnc->framebuffer_base != NULL && g_vnc_client_nr > 0)
  403.       {
  404.           vnc_update_screen(dfb_fbvnc->framebuffer_base, 0, 0, 
  405.              rfb_screen->width, rfb_screen->height);
  406.       }
  407.       usleep(200000);
  408.    }

  409.    return NULL;
  410. }

三、 修改directfbrc,让system=fbvnc。

一切OK了(颜色还有点问题),在broncho上的效果图:



原文地址:https://www.cnblogs.com/zhangyunlin/p/6167612.html