• 手机探索者开发实录—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上的效果图:



  • 相关阅读:
    bcdedit /copy {current} /d "xxx" 报错,提示找不到系统文件
    Moving docker images location to different partition
    docker 使用save和load命令来转移image
    docker image rm ubuntu 失败
    yum国内镜像配置
    VMware下安装CentOS7 无法通过桥接模式进行联网
    docker大概理解
    windows cmd 切换磁盘
    使用Git向GitHub上上传代码
    抛砖引玉——进程和线程的理解方式
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167612.html
Copyright © 2020-2023  润新知